summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sanitizer/common_interface_defs.h8
-rw-r--r--lib/asan/asan_poisoning.cc34
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h3
-rw-r--r--test/asan/TestCases/contiguous_container.cc12
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.