forked from OSchip/llvm-project
[asan] introduce __sanitizer_annotate_contiguous_container
llvm-svn: 195011
This commit is contained in:
parent
4d3457e628
commit
3d97c2040d
|
@ -50,6 +50,30 @@ extern "C" {
|
|||
// Record and dump coverage info.
|
||||
void __sanitizer_cov_dump();
|
||||
|
||||
// Annotate the current state of a contiguous container, such as
|
||||
// std::vector, std::string or similar.
|
||||
// A contiguous container is a container that keeps all of its elements
|
||||
// in a contiguous region of memory. The container owns the region of memory
|
||||
// [beg, end); the memory [beg, mid) is used to store the current elements
|
||||
// and the memory [mid, end) is reserved for future elements;
|
||||
// end <= mid <= end. For example, in "std::vector<> v"
|
||||
// beg = &v[0];
|
||||
// end = beg + v.capacity() * sizeof(v[0]);
|
||||
// mid = beg + v.size() * sizeof(v[0]);
|
||||
//
|
||||
// This annotation tells the Sanitizer tool about the current state of the
|
||||
// container so that the tool can report errors when memory from [mid, end)
|
||||
// is accessed. Insert this annotation into methods like push_back/pop_back.
|
||||
// Supply the old and the new values of mid (old_mid/new_mid).
|
||||
// In the initial state mid == end and so should be the final
|
||||
// state when the container is destroyed or when it reallocates the storage.
|
||||
//
|
||||
// Use with caution and don't use for anything other than vector-like classes.
|
||||
//
|
||||
// For AddressSanitizer, 'beg' should be 8-aligned.
|
||||
void __sanitizer_annotate_contiguous_container(void *beg, void *end,
|
||||
void *old_mid, void *new_mid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
@ -255,3 +255,45 @@ void __asan_unpoison_stack_memory(uptr addr, uptr size) {
|
|||
Report("unpoisoning: %p %zx\n", (void*)addr, size);
|
||||
PoisonAlignedStackMemory(addr, size, false);
|
||||
}
|
||||
|
||||
void __sanitizer_annotate_contiguous_container(void *beg_p, void *end_p,
|
||||
void *old_mid_p,
|
||||
void *new_mid_p) {
|
||||
uptr beg = reinterpret_cast<uptr>(beg_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;
|
||||
CHECK(beg <= end && beg <= old_mid && beg <= new_mid && old_mid <= end &&
|
||||
new_mid <= end && IsAligned(beg, granularity));
|
||||
CHECK_LE(end - beg,
|
||||
FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
|
||||
|
||||
uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
|
||||
uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
|
||||
uptr b = new_mid;
|
||||
uptr b1 = RoundDownTo(b, granularity);
|
||||
uptr b2 = RoundUpTo(b, granularity);
|
||||
uptr d = old_mid;
|
||||
uptr d1 = RoundDownTo(d, granularity);
|
||||
uptr d2 = RoundUpTo(d, granularity);
|
||||
// Currently we should be in this state:
|
||||
// [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
|
||||
// Make a quick sanity check that we are indeed in this state.
|
||||
if (d1 != d2)
|
||||
CHECK_EQ(*(u8*)MemToShadow(d1), d - d1);
|
||||
if (a + granularity <= d1)
|
||||
CHECK_EQ(*(u8*)MemToShadow(a), 0);
|
||||
if (d2 + granularity <= c && c <= end)
|
||||
CHECK_EQ(*(u8 *)MemToShadow(c - granularity), kAsanUserPoisonedMemoryMagic);
|
||||
|
||||
// New state:
|
||||
// [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
|
||||
// FIXME: we may want to have a separate poison magic value.
|
||||
PoisonShadow(a, b1 - a, 0);
|
||||
PoisonShadow(b2, c - b2, kAsanUserPoisonedMemoryMagic);
|
||||
if (b1 != b2) {
|
||||
CHECK_EQ(b2 - b1, granularity);
|
||||
*(u8*)MemToShadow(b1) = b - b1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// RUN: %clangxx_asan -O %s -o %t && %t
|
||||
//
|
||||
// Test __sanitizer_annotate_contiguous_container.
|
||||
|
||||
#include <stdlib.h>
|
||||
#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"
|
||||
|
||||
void TestContainer(size_t capacity) {
|
||||
char *beg = new char[capacity];
|
||||
char *end = beg + capacity;
|
||||
char *mid = beg + capacity;
|
||||
char *old_mid = 0;
|
||||
unsigned seed = 0;
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
size_t size = rand_r(&seed) % (capacity + 1);
|
||||
assert(size <= capacity);
|
||||
old_mid = mid;
|
||||
mid = beg + size;
|
||||
__sanitizer_annotate_contiguous_container(beg, end, old_mid, mid);
|
||||
|
||||
for (size_t idx = 0; idx < size; idx++)
|
||||
assert(!__asan_address_is_poisoned(beg + idx));
|
||||
for (size_t idx = size; idx < capacity; idx++)
|
||||
assert(__asan_address_is_poisoned(beg + idx));
|
||||
}
|
||||
|
||||
// Don't forget to unpoison the whole thing before destroing/reallocating.
|
||||
__sanitizer_annotate_contiguous_container(beg, end, mid, end);
|
||||
for (size_t idx = 0; idx < capacity; idx++)
|
||||
assert(!__asan_address_is_poisoned(beg + idx));
|
||||
delete[] beg;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int n = argc == 1 ? 128 : atoi(argv[1]);
|
||||
for (int i = 0; i <= n; i++)
|
||||
TestContainer(i);
|
||||
}
|
|
@ -113,6 +113,9 @@ extern "C" {
|
|||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_annotate_contiguous_container(void *beg, void *end,
|
||||
void *old_mid, void *new_mid);
|
||||
} // extern "C"
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue