diff options
-rw-r--r-- | include/sanitizer/common_interface_defs.h | 8 | ||||
-rw-r--r-- | lib/asan/asan_poisoning.cc | 34 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_internal_defs.h | 3 | ||||
-rw-r--r-- | test/asan/TestCases/contiguous_container.cc | 12 |
4 files changed, 50 insertions, 7 deletions
diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h index 798f0c52f..fa3c14d1b 100644 --- a/include/sanitizer/common_interface_defs.h +++ b/include/sanitizer/common_interface_defs.h @@ -86,6 +86,14 @@ extern "C" { const void *end, const void *old_mid, const void *new_mid); + // Returns true if the contiguous container [beg, end) ir properly poisoned + // (e.g. with __sanitizer_annotate_contiguous_container), i.e. if + // - [beg, mid) is addressable, + // - [mid, end) is unaddressable. + // Full verification requires O(end-beg) time; this function tries to avoid + // such complexity by touching only parts of the container around beg/mid/end. + int __sanitizer_verify_contiguous_container(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(); diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc index a545769bd..b356e4073 100644 --- a/lib/asan/asan_poisoning.cc +++ b/lib/asan/asan_poisoning.cc @@ -270,7 +270,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p, VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p, new_mid_p); uptr beg = reinterpret_cast<uptr>(beg_p); - uptr end= reinterpret_cast<uptr>(end_p); + uptr end = reinterpret_cast<uptr>(end_p); uptr old_mid = reinterpret_cast<uptr>(old_mid_p); uptr new_mid = reinterpret_cast<uptr>(new_mid_p); uptr granularity = SHADOW_GRANULARITY; @@ -313,6 +313,38 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p, } } +int __sanitizer_verify_contiguous_container(const void *beg_p, + const void *mid_p, + const void *end_p) { + if (!flags()->detect_container_overflow) return 1; + uptr beg = reinterpret_cast<uptr>(beg_p); + uptr end = reinterpret_cast<uptr>(end_p); + uptr mid = reinterpret_cast<uptr>(mid_p); + CHECK_LE(beg, mid); + CHECK_LE(mid, end); + // Check some bytes starting from beg, some bytes around mid, and some bytes + // ending with end. + uptr kMaxRangeToCheck = 32; + uptr r1_beg = beg; + uptr r1_end = Min(end + kMaxRangeToCheck, mid); + uptr r2_beg = Max(beg, mid - kMaxRangeToCheck); + uptr r2_end = Min(end, mid + kMaxRangeToCheck); + uptr r3_beg = Max(end - kMaxRangeToCheck, mid); + uptr r3_end = end; + for (uptr i = r1_beg; i < r1_end; i++) + if (AddressIsPoisoned(i)) + return 0; + for (uptr i = r2_beg; i < mid; i++) + if (AddressIsPoisoned(i)) + return 0; + for (uptr i = mid; i < r2_end; i++) + if (!AddressIsPoisoned(i)) + return 0; + for (uptr i = r3_beg; i < r3_end; i++) + if (!AddressIsPoisoned(i)) + return 0; + return 1; +} // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { bool WordIsPoisoned(uptr addr) { diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index 6c3cf4e03..2c64bf20c 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -111,6 +111,9 @@ extern "C" { const void *end, const void *old_mid, const void *new_mid); + SANITIZER_INTERFACE_ATTRIBUTE + int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, + const void *end); } // extern "C" diff --git a/test/asan/TestCases/contiguous_container.cc b/test/asan/TestCases/contiguous_container.cc index e02f0e5eb..8d8c8d049 100644 --- a/test/asan/TestCases/contiguous_container.cc +++ b/test/asan/TestCases/contiguous_container.cc @@ -6,12 +6,7 @@ #include <stdio.h> #include <string.h> #include <assert.h> - -extern "C" { -void __sanitizer_annotate_contiguous_container(void *beg, void *end, - void *old_mid, void *new_mid); -bool __asan_address_is_poisoned(void *addr); -} // extern "C" +#include <sanitizer/asan_interface.h> void TestContainer(size_t capacity) { char *beg = new char[capacity]; @@ -30,6 +25,11 @@ void TestContainer(size_t capacity) { assert(!__asan_address_is_poisoned(beg + idx)); 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(!__sanitizer_verify_contiguous_container(beg, mid - 1, end)); + if (mid != end) + assert(!__sanitizer_verify_contiguous_container(beg, mid + 1, end)); } // Don't forget to unpoison the whole thing before destroing/reallocating. |