Alexey Samsonov | 7da8503 | 2012-09-28 12:24:23 +0000 | [diff] [blame] | 1 | //===-- asan_noinst_test.cc -----------------------------------------------===// |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is a part of AddressSanitizer, an address sanity checker. |
| 11 | // |
| 12 | // This test file should be compiled w/o asan instrumentation. |
| 13 | //===----------------------------------------------------------------------===// |
Chandler Carruth | d865fec | 2012-08-29 02:27:54 +0000 | [diff] [blame] | 14 | |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 15 | #include "asan_allocator.h" |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 16 | #include "asan_internal.h" |
| 17 | #include "asan_mapping.h" |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 18 | #include "asan_test_utils.h" |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 19 | #include <sanitizer/allocator_interface.h> |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 20 | |
| 21 | #include <assert.h> |
| 22 | #include <stdio.h> |
| 23 | #include <stdlib.h> |
Alexander Potapenko | 79d12e8 | 2012-07-23 08:22:27 +0000 | [diff] [blame] | 24 | #include <string.h> // for memset() |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 25 | #include <algorithm> |
Alexander Potapenko | 79d12e8 | 2012-07-23 08:22:27 +0000 | [diff] [blame] | 26 | #include <vector> |
Kostya Serebryany | 65199f1 | 2013-01-25 11:46:22 +0000 | [diff] [blame] | 27 | #include <limits> |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 28 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 29 | // ATTENTION! |
| 30 | // Please don't call intercepted functions (including malloc() and friends) |
| 31 | // in this test. The static runtime library is linked explicitly (without |
| 32 | // -fsanitize=address), thus the interceptors do not work correctly on OS X. |
Alexey Samsonov | 05fa380 | 2013-09-16 15:50:53 +0000 | [diff] [blame] | 33 | |
Alexey Samsonov | 05fa380 | 2013-09-16 15:50:53 +0000 | [diff] [blame] | 34 | // Make sure __asan_init is called before any test case is run. |
| 35 | struct AsanInitCaller { |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 36 | AsanInitCaller() { |
| 37 | __asan::DisableReexec(); |
| 38 | __asan_init(); |
| 39 | } |
Alexey Samsonov | 05fa380 | 2013-09-16 15:50:53 +0000 | [diff] [blame] | 40 | }; |
| 41 | static AsanInitCaller asan_init_caller; |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 42 | |
| 43 | TEST(AddressSanitizer, InternalSimpleDeathTest) { |
| 44 | EXPECT_DEATH(exit(1), ""); |
| 45 | } |
| 46 | |
| 47 | static void MallocStress(size_t n) { |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 48 | u32 seed = my_rand(); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 49 | BufferedStackTrace stack1; |
| 50 | stack1.trace_buffer[0] = 0xa123; |
| 51 | stack1.trace_buffer[1] = 0xa456; |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 52 | stack1.size = 2; |
| 53 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 54 | BufferedStackTrace stack2; |
| 55 | stack2.trace_buffer[0] = 0xb123; |
| 56 | stack2.trace_buffer[1] = 0xb456; |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 57 | stack2.size = 2; |
| 58 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 59 | BufferedStackTrace stack3; |
| 60 | stack3.trace_buffer[0] = 0xc123; |
| 61 | stack3.trace_buffer[1] = 0xc456; |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 62 | stack3.size = 2; |
| 63 | |
| 64 | std::vector<void *> vec; |
| 65 | for (size_t i = 0; i < n; i++) { |
| 66 | if ((i % 3) == 0) { |
| 67 | if (vec.empty()) continue; |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 68 | size_t idx = my_rand_r(&seed) % vec.size(); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 69 | void *ptr = vec[idx]; |
| 70 | vec[idx] = vec.back(); |
| 71 | vec.pop_back(); |
Kostya Serebryany | fe6d916 | 2012-12-21 08:53:59 +0000 | [diff] [blame] | 72 | __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 73 | } else { |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 74 | size_t size = my_rand_r(&seed) % 1000 + 1; |
| 75 | switch ((my_rand_r(&seed) % 128)) { |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 76 | case 0: size += 1024; break; |
| 77 | case 1: size += 2048; break; |
| 78 | case 2: size += 4096; break; |
| 79 | } |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 80 | size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1); |
Kostya Serebryany | fe6d916 | 2012-12-21 08:53:59 +0000 | [diff] [blame] | 81 | char *ptr = (char*)__asan::asan_memalign(alignment, size, |
| 82 | &stack2, __asan::FROM_MALLOC); |
Alexey Samsonov | 1b17f5b | 2013-11-13 14:46:58 +0000 | [diff] [blame] | 83 | EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0)); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 84 | vec.push_back(ptr); |
| 85 | ptr[0] = 0; |
| 86 | ptr[size-1] = 0; |
| 87 | ptr[size/2] = 0; |
| 88 | } |
| 89 | } |
| 90 | for (size_t i = 0; i < vec.size(); i++) |
Kostya Serebryany | fe6d916 | 2012-12-21 08:53:59 +0000 | [diff] [blame] | 91 | __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | |
| 95 | TEST(AddressSanitizer, NoInstMallocTest) { |
Kostya Serebryany | d39a34e | 2013-03-14 13:16:09 +0000 | [diff] [blame] | 96 | MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000); |
| 97 | } |
| 98 | |
| 99 | TEST(AddressSanitizer, ThreadedMallocStressTest) { |
| 100 | const int kNumThreads = 4; |
| 101 | const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000; |
| 102 | pthread_t t[kNumThreads]; |
| 103 | for (int i = 0; i < kNumThreads; i++) { |
| 104 | PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))MallocStress, |
| 105 | (void*)kNumIterations); |
| 106 | } |
| 107 | for (int i = 0; i < kNumThreads; i++) { |
| 108 | PTHREAD_JOIN(t[i], 0); |
| 109 | } |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 110 | } |
| 111 | |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 112 | static void PrintShadow(const char *tag, uptr ptr, size_t size) { |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 113 | fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size); |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 114 | uptr prev_shadow = 0; |
Kostya Serebryany | ee39255 | 2012-05-31 15:02:07 +0000 | [diff] [blame] | 115 | for (sptr i = -32; i < (sptr)size + 32; i++) { |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 116 | uptr shadow = __asan::MemToShadow(ptr + i); |
Kostya Serebryany | ee39255 | 2012-05-31 15:02:07 +0000 | [diff] [blame] | 117 | if (i == 0 || i == (sptr)size) |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 118 | fprintf(stderr, "."); |
| 119 | if (shadow != prev_shadow) { |
| 120 | prev_shadow = shadow; |
Kostya Serebryany | ee39255 | 2012-05-31 15:02:07 +0000 | [diff] [blame] | 121 | fprintf(stderr, "%02x", (int)*(u8*)shadow); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 122 | } |
| 123 | } |
| 124 | fprintf(stderr, "\n"); |
| 125 | } |
| 126 | |
| 127 | TEST(AddressSanitizer, DISABLED_InternalPrintShadow) { |
| 128 | for (size_t size = 1; size <= 513; size++) { |
| 129 | char *ptr = new char[size]; |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 130 | PrintShadow("m", (uptr)ptr, size); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 131 | delete [] ptr; |
Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 132 | PrintShadow("f", (uptr)ptr, size); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 133 | } |
| 134 | } |
| 135 | |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 136 | TEST(AddressSanitizer, QuarantineTest) { |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 137 | BufferedStackTrace stack; |
| 138 | stack.trace_buffer[0] = 0x890; |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 139 | stack.size = 1; |
| 140 | |
Kostya Serebryany | d39a34e | 2013-03-14 13:16:09 +0000 | [diff] [blame] | 141 | const int size = 1024; |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 142 | void *p = __asan::asan_malloc(size, &stack); |
Kostya Serebryany | fe6d916 | 2012-12-21 08:53:59 +0000 | [diff] [blame] | 143 | __asan::asan_free(p, &stack, __asan::FROM_MALLOC); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 144 | size_t i; |
| 145 | size_t max_i = 1 << 30; |
| 146 | for (i = 0; i < max_i; i++) { |
| 147 | void *p1 = __asan::asan_malloc(size, &stack); |
Kostya Serebryany | fe6d916 | 2012-12-21 08:53:59 +0000 | [diff] [blame] | 148 | __asan::asan_free(p1, &stack, __asan::FROM_MALLOC); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 149 | if (p1 == p) break; |
| 150 | } |
Kostya Serebryany | d39a34e | 2013-03-14 13:16:09 +0000 | [diff] [blame] | 151 | EXPECT_GE(i, 10000U); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 152 | EXPECT_LT(i, max_i); |
| 153 | } |
| 154 | |
| 155 | void *ThreadedQuarantineTestWorker(void *unused) { |
Alexey Samsonov | 1a7741b | 2012-07-24 08:26:19 +0000 | [diff] [blame] | 156 | (void)unused; |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 157 | u32 seed = my_rand(); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 158 | BufferedStackTrace stack; |
| 159 | stack.trace_buffer[0] = 0x890; |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 160 | stack.size = 1; |
| 161 | |
| 162 | for (size_t i = 0; i < 1000; i++) { |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 163 | void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack); |
Kostya Serebryany | fe6d916 | 2012-12-21 08:53:59 +0000 | [diff] [blame] | 164 | __asan::asan_free(p, &stack, __asan::FROM_MALLOC); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 165 | } |
| 166 | return NULL; |
| 167 | } |
| 168 | |
| 169 | // Check that the thread local allocators are flushed when threads are |
| 170 | // destroyed. |
| 171 | TEST(AddressSanitizer, ThreadedQuarantineTest) { |
| 172 | const int n_threads = 3000; |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 173 | size_t mmaped1 = __sanitizer_get_heap_size(); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 174 | for (int i = 0; i < n_threads; i++) { |
| 175 | pthread_t t; |
Kostya Serebryany | 2697687 | 2012-12-03 09:43:56 +0000 | [diff] [blame] | 176 | PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0); |
| 177 | PTHREAD_JOIN(t, 0); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 178 | size_t mmaped2 = __sanitizer_get_heap_size(); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 179 | EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20)); |
| 180 | } |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 181 | } |
| 182 | |
| 183 | void *ThreadedOneSizeMallocStress(void *unused) { |
Alexey Samsonov | 1a7741b | 2012-07-24 08:26:19 +0000 | [diff] [blame] | 184 | (void)unused; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 185 | BufferedStackTrace stack; |
| 186 | stack.trace_buffer[0] = 0x890; |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 187 | stack.size = 1; |
| 188 | const size_t kNumMallocs = 1000; |
| 189 | for (int iter = 0; iter < 1000; iter++) { |
| 190 | void *p[kNumMallocs]; |
| 191 | for (size_t i = 0; i < kNumMallocs; i++) { |
| 192 | p[i] = __asan::asan_malloc(32, &stack); |
| 193 | } |
| 194 | for (size_t i = 0; i < kNumMallocs; i++) { |
Kostya Serebryany | fe6d916 | 2012-12-21 08:53:59 +0000 | [diff] [blame] | 195 | __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 196 | } |
| 197 | } |
| 198 | return NULL; |
| 199 | } |
| 200 | |
| 201 | TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) { |
| 202 | const int kNumThreads = 4; |
| 203 | pthread_t t[kNumThreads]; |
| 204 | for (int i = 0; i < kNumThreads; i++) { |
Kostya Serebryany | 2697687 | 2012-12-03 09:43:56 +0000 | [diff] [blame] | 205 | PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 206 | } |
| 207 | for (int i = 0; i < kNumThreads; i++) { |
Kostya Serebryany | 2697687 | 2012-12-03 09:43:56 +0000 | [diff] [blame] | 208 | PTHREAD_JOIN(t[i], 0); |
Kostya Serebryany | 1e172b4 | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 209 | } |
| 210 | } |
Kostya Serebryany | bff5336 | 2012-06-25 14:23:07 +0000 | [diff] [blame] | 211 | |
Alexey Samsonov | 05fa380 | 2013-09-16 15:50:53 +0000 | [diff] [blame] | 212 | TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) { |
Kostya Serebryany | e5ab968 | 2013-01-23 13:27:43 +0000 | [diff] [blame] | 213 | using __asan::kHighMemEnd; |
Alexey Samsonov | 05fa380 | 2013-09-16 15:50:53 +0000 | [diff] [blame] | 214 | // Check that __asan_region_is_poisoned works for shadow regions. |
| 215 | uptr ptr = kLowShadowBeg + 200; |
| 216 | EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); |
| 217 | ptr = kShadowGapBeg + 200; |
| 218 | EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); |
| 219 | ptr = kHighShadowBeg + 200; |
| 220 | EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); |
Kostya Serebryany | b9e1319 | 2013-02-27 13:38:19 +0000 | [diff] [blame] | 221 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 222 | |
| 223 | // Test __asan_load1 & friends. |
| 224 | TEST(AddressSanitizer, LoadStoreCallbacks) { |
| 225 | typedef void (*CB)(uptr p); |
| 226 | CB cb[2][5] = { |
| 227 | { |
| 228 | __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16, |
| 229 | }, { |
| 230 | __asan_store1, __asan_store2, __asan_store4, __asan_store8, |
| 231 | __asan_store16, |
| 232 | } |
| 233 | }; |
| 234 | |
| 235 | uptr buggy_ptr; |
| 236 | |
| 237 | __asan_test_only_reported_buggy_pointer = &buggy_ptr; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 238 | BufferedStackTrace stack; |
| 239 | stack.trace_buffer[0] = 0x890; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 240 | stack.size = 1; |
| 241 | |
| 242 | for (uptr len = 16; len <= 32; len++) { |
| 243 | char *ptr = (char*) __asan::asan_malloc(len, &stack); |
| 244 | uptr p = reinterpret_cast<uptr>(ptr); |
| 245 | for (uptr is_write = 0; is_write <= 1; is_write++) { |
| 246 | for (uptr size_log = 0; size_log <= 4; size_log++) { |
| 247 | uptr size = 1 << size_log; |
| 248 | CB call = cb[is_write][size_log]; |
| 249 | // Iterate only size-aligned offsets. |
| 250 | for (uptr offset = 0; offset <= len; offset += size) { |
| 251 | buggy_ptr = 0; |
| 252 | call(p + offset); |
| 253 | if (offset + size <= len) |
| 254 | EXPECT_EQ(buggy_ptr, 0U); |
| 255 | else |
| 256 | EXPECT_EQ(buggy_ptr, p + offset); |
| 257 | } |
| 258 | } |
| 259 | } |
| 260 | __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC); |
| 261 | } |
| 262 | __asan_test_only_reported_buggy_pointer = 0; |
| 263 | } |