aboutsummaryrefslogtreecommitdiff
path: root/lib/asan/tests/asan_noinst_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asan/tests/asan_noinst_test.cc')
-rw-r--r--lib/asan/tests/asan_noinst_test.cc233
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));