diff options
Diffstat (limited to 'lib/asan/tests/asan_noinst_test.cc')
-rw-r--r-- | lib/asan/tests/asan_noinst_test.cc | 233 |
1 files changed, 158 insertions, 75 deletions
diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc index 44d4c3c845b2..576312bf319f 100644 --- a/lib/asan/tests/asan_noinst_test.cc +++ b/lib/asan/tests/asan_noinst_test.cc @@ -1,4 +1,4 @@ -//===-- asan_noinst_test.cc ----------------------===// +//===-- asan_noinst_test.cc -----------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -11,12 +11,13 @@ // // This test file should be compiled w/o asan instrumentation. //===----------------------------------------------------------------------===// + #include "asan_allocator.h" -#include "asan_interface.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_stack.h" #include "asan_test_utils.h" +#include "sanitizer/asan_interface.h" #include <assert.h> #include <stdio.h> @@ -24,15 +25,6 @@ #include <string.h> // for memset() #include <algorithm> #include <vector> -#include "gtest/gtest.h" - -// Simple stand-alone pseudorandom number generator. -// Current algorithm is ANSI C linear congruential PRNG. -static inline u32 my_rand(u32* state) { - return (*state = *state * 1103515245 + 12345) >> 16; -} - -static u32 global_seed = 0; TEST(AddressSanitizer, InternalSimpleDeathTest) { @@ -40,18 +32,18 @@ TEST(AddressSanitizer, InternalSimpleDeathTest) { } static void MallocStress(size_t n) { - u32 seed = my_rand(&global_seed); - __asan::AsanStackTrace stack1; + u32 seed = my_rand(); + __asan::StackTrace stack1; stack1.trace[0] = 0xa123; stack1.trace[1] = 0xa456; stack1.size = 2; - __asan::AsanStackTrace stack2; + __asan::StackTrace stack2; stack2.trace[0] = 0xb123; stack2.trace[1] = 0xb456; stack2.size = 2; - __asan::AsanStackTrace stack3; + __asan::StackTrace stack3; stack3.trace[0] = 0xc123; stack3.trace[1] = 0xc456; stack3.size = 2; @@ -60,20 +52,21 @@ static void MallocStress(size_t n) { for (size_t i = 0; i < n; i++) { if ((i % 3) == 0) { if (vec.empty()) continue; - size_t idx = my_rand(&seed) % vec.size(); + size_t idx = my_rand_r(&seed) % vec.size(); void *ptr = vec[idx]; vec[idx] = vec.back(); vec.pop_back(); - __asan::asan_free(ptr, &stack1); + __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC); } else { - size_t size = my_rand(&seed) % 1000 + 1; - switch ((my_rand(&seed) % 128)) { + size_t size = my_rand_r(&seed) % 1000 + 1; + switch ((my_rand_r(&seed) % 128)) { case 0: size += 1024; break; case 1: size += 2048; break; case 2: size += 4096; break; } - size_t alignment = 1 << (my_rand(&seed) % 10 + 1); - char *ptr = (char*)__asan::asan_memalign(alignment, size, &stack2); + size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1); + char *ptr = (char*)__asan::asan_memalign(alignment, size, + &stack2, __asan::FROM_MALLOC); vec.push_back(ptr); ptr[0] = 0; ptr[size-1] = 0; @@ -81,7 +74,7 @@ static void MallocStress(size_t n) { } } for (size_t i = 0; i < vec.size(); i++) - __asan::asan_free(vec[i], &stack3); + __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC); } @@ -118,7 +111,7 @@ TEST(AddressSanitizer, DISABLED_InternalPrintShadow) { } static uptr pc_array[] = { -#if __WORDSIZE == 64 +#if SANITIZER_WORDSIZE == 64 0x7effbf756068ULL, 0x7effbf75e5abULL, 0x7effc0625b7cULL, @@ -164,7 +157,7 @@ static uptr pc_array[] = { 0x7effbcc3e726ULL, 0x7effbcc40852ULL, 0x7effb681ec4dULL, -#endif // __WORDSIZE +#endif // SANITIZER_WORDSIZE 0xB0B5E768, 0x7B682EC1, 0x367F9918, @@ -208,22 +201,22 @@ static uptr pc_array[] = { }; void CompressStackTraceTest(size_t n_iter) { - u32 seed = my_rand(&global_seed); - const size_t kNumPcs = ASAN_ARRAY_SIZE(pc_array); + u32 seed = my_rand(); + const size_t kNumPcs = ARRAY_SIZE(pc_array); u32 compressed[2 * kNumPcs]; for (size_t iter = 0; iter < n_iter; iter++) { std::random_shuffle(pc_array, pc_array + kNumPcs); - __asan::AsanStackTrace stack0, stack1; + __asan::StackTrace stack0, stack1; stack0.CopyFrom(pc_array, kNumPcs); - stack0.size = std::max((size_t)1, (size_t)(my_rand(&seed) % stack0.size)); + stack0.size = std::max((size_t)1, (size_t)(my_rand_r(&seed) % stack0.size)); size_t compress_size = - std::max((size_t)2, (size_t)my_rand(&seed) % (2 * kNumPcs)); + std::max((size_t)2, (size_t)my_rand_r(&seed) % (2 * kNumPcs)); size_t n_frames = - __asan::AsanStackTrace::CompressStack(&stack0, compressed, compress_size); + __asan::StackTrace::CompressStack(&stack0, compressed, compress_size); Ident(n_frames); assert(n_frames <= stack0.size); - __asan::AsanStackTrace::UncompressStack(&stack1, compressed, compress_size); + __asan::StackTrace::UncompressStack(&stack1, compressed, compress_size); assert(stack1.size == n_frames); for (size_t i = 0; i < stack1.size; i++) { assert(stack0.trace[i] == stack1.trace[i]); @@ -236,17 +229,17 @@ TEST(AddressSanitizer, CompressStackTraceTest) { } void CompressStackTraceBenchmark(size_t n_iter) { - const size_t kNumPcs = ASAN_ARRAY_SIZE(pc_array); + const size_t kNumPcs = ARRAY_SIZE(pc_array); u32 compressed[2 * kNumPcs]; std::random_shuffle(pc_array, pc_array + kNumPcs); - __asan::AsanStackTrace stack0; + __asan::StackTrace stack0; stack0.CopyFrom(pc_array, kNumPcs); stack0.size = kNumPcs; for (size_t iter = 0; iter < n_iter; iter++) { size_t compress_size = kNumPcs; size_t n_frames = - __asan::AsanStackTrace::CompressStack(&stack0, compressed, compress_size); + __asan::StackTrace::CompressStack(&stack0, compressed, compress_size); Ident(n_frames); } } @@ -256,18 +249,18 @@ TEST(AddressSanitizer, CompressStackTraceBenchmark) { } TEST(AddressSanitizer, QuarantineTest) { - __asan::AsanStackTrace stack; + __asan::StackTrace stack; stack.trace[0] = 0x890; stack.size = 1; const int size = 32; void *p = __asan::asan_malloc(size, &stack); - __asan::asan_free(p, &stack); + __asan::asan_free(p, &stack, __asan::FROM_MALLOC); size_t i; size_t max_i = 1 << 30; for (i = 0; i < max_i; i++) { void *p1 = __asan::asan_malloc(size, &stack); - __asan::asan_free(p1, &stack); + __asan::asan_free(p1, &stack, __asan::FROM_MALLOC); if (p1 == p) break; } // fprintf(stderr, "i=%ld\n", i); @@ -277,14 +270,14 @@ TEST(AddressSanitizer, QuarantineTest) { void *ThreadedQuarantineTestWorker(void *unused) { (void)unused; - u32 seed = my_rand(&global_seed); - __asan::AsanStackTrace stack; + u32 seed = my_rand(); + __asan::StackTrace stack; stack.trace[0] = 0x890; stack.size = 1; for (size_t i = 0; i < 1000; i++) { - void *p = __asan::asan_malloc(1 + (my_rand(&seed) % 4000), &stack); - __asan::asan_free(p, &stack); + void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack); + __asan::asan_free(p, &stack, __asan::FROM_MALLOC); } return NULL; } @@ -296,8 +289,8 @@ TEST(AddressSanitizer, ThreadedQuarantineTest) { size_t mmaped1 = __asan_get_heap_size(); for (int i = 0; i < n_threads; i++) { pthread_t t; - pthread_create(&t, NULL, ThreadedQuarantineTestWorker, 0); - pthread_join(t, 0); + PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0); + PTHREAD_JOIN(t, 0); size_t mmaped2 = __asan_get_heap_size(); EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20)); } @@ -305,7 +298,7 @@ TEST(AddressSanitizer, ThreadedQuarantineTest) { void *ThreadedOneSizeMallocStress(void *unused) { (void)unused; - __asan::AsanStackTrace stack; + __asan::StackTrace stack; stack.trace[0] = 0x890; stack.size = 1; const size_t kNumMallocs = 1000; @@ -315,7 +308,7 @@ void *ThreadedOneSizeMallocStress(void *unused) { p[i] = __asan::asan_malloc(32, &stack); } for (size_t i = 0; i < kNumMallocs; i++) { - __asan::asan_free(p[i], &stack); + __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC); } } return NULL; @@ -325,10 +318,10 @@ TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) { const int kNumThreads = 4; pthread_t t[kNumThreads]; for (int i = 0; i < kNumThreads; i++) { - pthread_create(&t[i], 0, ThreadedOneSizeMallocStress, 0); + PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0); } for (int i = 0; i < kNumThreads; i++) { - pthread_join(t[i], 0); + PTHREAD_JOIN(t[i], 0); } } @@ -336,16 +329,20 @@ TEST(AddressSanitizer, MemsetWildAddressTest) { typedef void*(*memset_p)(void*, int, size_t); // Prevent inlining of memset(). volatile memset_p libc_memset = (memset_p)memset; - EXPECT_DEATH(libc_memset((void*)(kLowShadowBeg + kPageSize), 0, 100), + EXPECT_DEATH(libc_memset((void*)(kLowShadowBeg + 200), 0, 100), "unknown-crash.*low shadow"); - EXPECT_DEATH(libc_memset((void*)(kShadowGapBeg + kPageSize), 0, 100), + EXPECT_DEATH(libc_memset((void*)(kShadowGapBeg + 200), 0, 100), "unknown-crash.*shadow gap"); - EXPECT_DEATH(libc_memset((void*)(kHighShadowBeg + kPageSize), 0, 100), + EXPECT_DEATH(libc_memset((void*)(kHighShadowBeg + 200), 0, 100), "unknown-crash.*high shadow"); } TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) { +#if ASAN_ALLOCATOR_VERSION == 1 EXPECT_EQ(1U, __asan_get_estimated_allocated_size(0)); +#elif ASAN_ALLOCATOR_VERSION == 2 + EXPECT_EQ(0U, __asan_get_estimated_allocated_size(0)); +#endif const size_t sizes[] = { 1, 30, 1<<30 }; for (size_t i = 0; i < 3; i++) { EXPECT_EQ(sizes[i], __asan_get_estimated_allocated_size(sizes[i])); @@ -370,23 +367,32 @@ TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) { // We cannot call GetAllocatedSize from the memory we didn't map, // and from the interior pointers (not returned by previous malloc). void *wild_addr = (void*)0x1; - EXPECT_EQ(false, __asan_get_ownership(wild_addr)); + EXPECT_FALSE(__asan_get_ownership(wild_addr)); EXPECT_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg); - EXPECT_EQ(false, __asan_get_ownership(array + kArraySize / 2)); + EXPECT_FALSE(__asan_get_ownership(array + kArraySize / 2)); EXPECT_DEATH(__asan_get_allocated_size(array + kArraySize / 2), kGetAllocatedSizeErrorMsg); // NULL is not owned, but is a valid argument for __asan_get_allocated_size(). - EXPECT_EQ(false, __asan_get_ownership(NULL)); + EXPECT_FALSE(__asan_get_ownership(NULL)); EXPECT_EQ(0U, __asan_get_allocated_size(NULL)); // When memory is freed, it's not owned, and call to GetAllocatedSize // is forbidden. free(array); - EXPECT_EQ(false, __asan_get_ownership(array)); + EXPECT_FALSE(__asan_get_ownership(array)); EXPECT_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg); - delete int_ptr; + + void *zero_alloc = Ident(malloc(0)); + if (zero_alloc != 0) { + // If malloc(0) is not null, this pointer is owned and should have valid + // allocated size. + EXPECT_TRUE(__asan_get_ownership(zero_alloc)); + // Allocated size is 0 or 1 depending on the allocator used. + EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U); + } + free(zero_alloc); } TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) { @@ -410,6 +416,7 @@ static void DoDoubleFree() { delete Ident(x); } +#if ASAN_ALLOCATOR_VERSION == 1 // This test is run in a separate process, so that large malloced // chunk won't remain in the free lists after the test. // Note: use ASSERT_* instead of EXPECT_* here. @@ -441,9 +448,26 @@ static void RunGetHeapSizeTestAndDie() { TEST(AddressSanitizerInterface, GetHeapSizeTest) { EXPECT_DEATH(RunGetHeapSizeTestAndDie(), "double-free"); } +#elif ASAN_ALLOCATOR_VERSION == 2 +TEST(AddressSanitizerInterface, GetHeapSizeTest) { + // asan_allocator2 does not keep huge chunks in free list, but unmaps them. + // The chunk should be greater than the quarantine size, + // otherwise it will be stuck in quarantine instead of being unmaped. + static const size_t kLargeMallocSize = 1 << 29; // 512M + uptr old_heap_size = __asan_get_heap_size(); + for (int i = 0; i < 3; i++) { + // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize); + free(Ident(malloc(kLargeMallocSize))); + EXPECT_EQ(old_heap_size, __asan_get_heap_size()); + } +} +#endif // Note: use ASSERT_* instead of EXPECT_* here. static void DoLargeMallocForGetFreeBytesTestAndDie() { +#if ASAN_ALLOCATOR_VERSION == 1 + // asan_allocator2 does not keep large chunks in free_lists, so this test + // will not work. size_t old_free_bytes, new_free_bytes; static const size_t kLargeMallocSize = 1 << 29; // 512M // If we malloc and free a large memory chunk, it will not fall @@ -455,33 +479,42 @@ static void DoLargeMallocForGetFreeBytesTestAndDie() { new_free_bytes = __asan_get_free_bytes(); fprintf(stderr, "free bytes after malloc and free: %zu\n", new_free_bytes); ASSERT_GE(new_free_bytes, old_free_bytes + kLargeMallocSize); +#endif // ASAN_ALLOCATOR_VERSION // Test passed. DoDoubleFree(); } TEST(AddressSanitizerInterface, GetFreeBytesTest) { - static const size_t kNumOfChunks = 100; - static const size_t kChunkSize = 100; - char *chunks[kNumOfChunks]; - size_t i; - size_t old_free_bytes, new_free_bytes; +#if ASAN_ALLOCATOR_VERSION == 1 // Allocate a small chunk. Now allocator probably has a lot of these // chunks to fulfill future requests. So, future requests will decrease - // the number of free bytes. - chunks[0] = Ident((char*)malloc(kChunkSize)); - old_free_bytes = __asan_get_free_bytes(); - for (i = 1; i < kNumOfChunks; i++) { - chunks[i] = Ident((char*)malloc(kChunkSize)); - new_free_bytes = __asan_get_free_bytes(); - EXPECT_LT(new_free_bytes, old_free_bytes); - old_free_bytes = new_free_bytes; + // the number of free bytes. Do this only on systems where there + // is enough memory for such assumptions. + if (SANITIZER_WORDSIZE == 64 && !ASAN_LOW_MEMORY) { + static const size_t kNumOfChunks = 100; + static const size_t kChunkSize = 100; + char *chunks[kNumOfChunks]; + size_t i; + size_t old_free_bytes, new_free_bytes; + chunks[0] = Ident((char*)malloc(kChunkSize)); + old_free_bytes = __asan_get_free_bytes(); + for (i = 1; i < kNumOfChunks; i++) { + chunks[i] = Ident((char*)malloc(kChunkSize)); + new_free_bytes = __asan_get_free_bytes(); + EXPECT_LT(new_free_bytes, old_free_bytes); + old_free_bytes = new_free_bytes; + } + for (i = 0; i < kNumOfChunks; i++) + free(chunks[i]); } +#endif EXPECT_DEATH(DoLargeMallocForGetFreeBytesTestAndDie(), "double-free"); } -static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<20, 357}; +static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357}; static const size_t kManyThreadsIterations = 250; -static const size_t kManyThreadsNumThreads = (__WORDSIZE == 32) ? 40 : 200; +static const size_t kManyThreadsNumThreads = + (SANITIZER_WORDSIZE == 32) ? 40 : 200; void *ManyThreadsWithStatsWorker(void *arg) { (void)arg; @@ -490,6 +523,8 @@ void *ManyThreadsWithStatsWorker(void *arg) { free(Ident(malloc(kManyThreadsMallocSizes[size_index]))); } } + // Just one large allocation. + free(Ident(malloc(1 << 20))); return 0; } @@ -498,11 +533,11 @@ TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) { pthread_t threads[kManyThreadsNumThreads]; before_test = __asan_get_current_allocated_bytes(); for (i = 0; i < kManyThreadsNumThreads; i++) { - pthread_create(&threads[i], 0, + PTHREAD_CREATE(&threads[i], 0, (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i); } for (i = 0; i < kManyThreadsNumThreads; i++) { - pthread_join(threads[i], 0); + PTHREAD_JOIN(threads[i], 0); } after_test = __asan_get_current_allocated_bytes(); // ASan stats also reflect memory usage of internal ASan RTL structs, @@ -649,6 +684,45 @@ TEST(AddressSanitizerInterface, PoisoningStressTest) { } } +TEST(AddressSanitizerInterface, PoisonedRegion) { + size_t rz = 16; + for (size_t size = 1; size <= 64; size++) { + char *p = new char[size]; + uptr x = reinterpret_cast<uptr>(p); + for (size_t beg = 0; beg < size + rz; beg++) { + for (size_t end = beg; end < size + rz; end++) { + uptr first_poisoned = __asan_region_is_poisoned(x + beg, end - beg); + if (beg == end) { + EXPECT_FALSE(first_poisoned); + } else if (beg < size && end <= size) { + EXPECT_FALSE(first_poisoned); + } else if (beg >= size) { + EXPECT_EQ(x + beg, first_poisoned); + } else { + EXPECT_GT(end, size); + EXPECT_EQ(x + size, first_poisoned); + } + } + } + delete [] p; + } +} + +// This is a performance benchmark for manual runs. +// asan's memset interceptor calls mem_is_zero for the entire shadow region. +// the profile should look like this: +// 89.10% [.] __memset_sse2 +// 10.50% [.] __sanitizer::mem_is_zero +// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles +// than memset itself. +TEST(AddressSanitizerInterface, DISABLED_Stress_memset) { + size_t size = 1 << 20; + char *x = new char[size]; + for (int i = 0; i < 100000; i++) + Ident(memset)(x, 0, size); + delete [] x; +} + static const char *kInvalidPoisonMessage = "invalid-poison-memory-range"; static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range"; @@ -670,20 +744,29 @@ TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) { } static void ErrorReportCallbackOneToZ(const char *report) { - write(2, "ABCDEF", 6); + int report_len = strlen(report); + ASSERT_EQ(6, write(2, "ABCDEF", 6)); + ASSERT_EQ(report_len, write(2, report, report_len)); + ASSERT_EQ(6, write(2, "ABCDEF", 6)); + _exit(1); } TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) { __asan_set_error_report_callback(ErrorReportCallbackOneToZ); - EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1), "ABCDEF"); + EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1), + ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF"); __asan_set_error_report_callback(NULL); } TEST(AddressSanitizerInterface, GetOwnershipStressTest) { std::vector<char *> pointers; std::vector<size_t> sizes; +#if ASAN_ALLOCATOR_VERSION == 1 const size_t kNumMallocs = - (__WORDSIZE <= 32 || ASAN_LOW_MEMORY) ? 1 << 10 : 1 << 14; + (SANITIZER_WORDSIZE <= 32 || ASAN_LOW_MEMORY) ? 1 << 10 : 1 << 14; +#elif ASAN_ALLOCATOR_VERSION == 2 // too slow with asan_allocator2. :( + const size_t kNumMallocs = 1 << 9; +#endif for (size_t i = 0; i < kNumMallocs; i++) { size_t size = i * 100 + 1; pointers.push_back((char*)malloc(size)); |