Index: compiler-rt/trunk/include/sanitizer/common_interface_defs.h =================================================================== --- compiler-rt/trunk/include/sanitizer/common_interface_defs.h +++ compiler-rt/trunk/include/sanitizer/common_interface_defs.h @@ -105,6 +105,12 @@ int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, const void *end); + // Similar to __sanitizer_verify_contiguous_container but returns the address + // of the first improperly poisoned byte otherwise. Returns null if the area + // is poisoned properly. + const void *__sanitizer_contiguous_container_find_bad_address( + const void *beg, const void *mid, const void *end); + // Print the stack trace leading to this call. Useful for debugging user code. void __sanitizer_print_stack_trace(); Index: compiler-rt/trunk/lib/asan/asan_poisoning.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_poisoning.cc +++ compiler-rt/trunk/lib/asan/asan_poisoning.cc @@ -375,10 +375,10 @@ } } -int __sanitizer_verify_contiguous_container(const void *beg_p, - const void *mid_p, - const void *end_p) { - if (!flags()->detect_container_overflow) return 1; +const void *__sanitizer_contiguous_container_find_bad_address( + const void *beg_p, const void *mid_p, const void *end_p) { + if (!flags()->detect_container_overflow) + return nullptr; uptr beg = reinterpret_cast(beg_p); uptr end = reinterpret_cast(end_p); uptr mid = reinterpret_cast(mid_p); @@ -395,17 +395,24 @@ uptr r3_end = end; for (uptr i = r1_beg; i < r1_end; i++) if (AddressIsPoisoned(i)) - return 0; + return reinterpret_cast(i); for (uptr i = r2_beg; i < mid; i++) if (AddressIsPoisoned(i)) - return 0; + return reinterpret_cast(i); for (uptr i = mid; i < r2_end; i++) if (!AddressIsPoisoned(i)) - return 0; + return reinterpret_cast(i); for (uptr i = r3_beg; i < r3_end; i++) if (!AddressIsPoisoned(i)) - return 0; - return 1; + return reinterpret_cast(i); + return nullptr; +} + +int __sanitizer_verify_contiguous_container(const void *beg_p, + const void *mid_p, + const void *end_p) { + return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p, + end_p) == nullptr; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_interface_internal.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_interface_internal.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_interface_internal.h @@ -53,6 +53,9 @@ SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, const void *end); -} // extern "C" + SANITIZER_INTERFACE_ATTRIBUTE + const void *__sanitizer_contiguous_container_find_bad_address( + const void *beg, const void *mid, const void *end); + } // extern "C" #endif // SANITIZER_INTERFACE_INTERNAL_H Index: compiler-rt/trunk/test/asan/TestCases/contiguous_container.cc =================================================================== --- compiler-rt/trunk/test/asan/TestCases/contiguous_container.cc +++ compiler-rt/trunk/test/asan/TestCases/contiguous_container.cc @@ -26,10 +26,18 @@ for (size_t idx = size; idx < capacity; idx++) assert(__asan_address_is_poisoned(beg + idx)); assert(__sanitizer_verify_contiguous_container(beg, mid, end)); - if (mid != beg) + assert(NULL == + __sanitizer_contiguous_container_find_bad_address(beg, mid, end)); + if (mid != beg) { assert(!__sanitizer_verify_contiguous_container(beg, mid - 1, end)); - if (mid != end) + assert(mid - 1 == __sanitizer_contiguous_container_find_bad_address( + beg, mid - 1, end)); + } + if (mid != end) { assert(!__sanitizer_verify_contiguous_container(beg, mid + 1, end)); + assert(mid == __sanitizer_contiguous_container_find_bad_address( + beg, mid + 1, end)); + } } // Don't forget to unpoison the whole thing before destroing/reallocating.