Newer
Older
//===-- asan_test.cc ----------------------===//
Kostya Serebryany
committed
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
Kostya Serebryany
committed
#include <strings.h>
Kostya Serebryany
committed
#include <pthread.h>
#include <stdint.h>
#include <setjmp.h>
#include <assert.h>
#if defined(__i386__) || defined(__x86_64__)
Kostya Serebryany
committed
#include <emmintrin.h>
#endif
#include "asan_test_config.h"
#include "asan_test_utils.h"
#ifndef __APPLE__
#include <malloc.h>
#include <malloc/malloc.h>
#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
#include <CoreFoundation/CFString.h>
Kostya Serebryany
committed
#endif // __APPLE__
#if ASAN_HAS_EXCEPTIONS
# define ASAN_THROW(x) throw (x)
#else
# define ASAN_THROW(x)
#endif
#include <sys/mman.h>
typedef uint8_t U1;
typedef uint16_t U2;
typedef uint32_t U4;
typedef uint64_t U8;
static const char *progname;
static const int kPageSize = 4096;
// Simple stand-alone pseudorandom number generator.
// Current algorithm is ANSI C linear congruential PRNG.
static inline uint32_t my_rand(uint32_t* state) {
return (*state = *state * 1103515245 + 12345) >> 16;
}
static uint32_t global_seed = 0;
const size_t kLargeMalloc = 1 << 24;
Timur Iskhodzhanov
committed
template<typename T>
NOINLINE void asan_write(T *a) {
Kostya Serebryany
committed
*a = 0;
}
NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
EXPECT_EQ(0U, ((uintptr_t)p % size));
Kostya Serebryany
committed
if (size == 1) asan_write((uint8_t*)p);
else if (size == 2) asan_write((uint16_t*)p);
else if (size == 4) asan_write((uint32_t*)p);
else if (size == 8) asan_write((uint64_t*)p);
}
NOINLINE void *malloc_fff(size_t size) {
Kostya Serebryany
committed
void *res = malloc/**/(size); break_optimization(0); return res;}
NOINLINE void *malloc_eee(size_t size) {
Kostya Serebryany
committed
void *res = malloc_fff(size); break_optimization(0); return res;}
NOINLINE void *malloc_ddd(size_t size) {
Kostya Serebryany
committed
void *res = malloc_eee(size); break_optimization(0); return res;}
NOINLINE void *malloc_ccc(size_t size) {
Kostya Serebryany
committed
void *res = malloc_ddd(size); break_optimization(0); return res;}
NOINLINE void *malloc_bbb(size_t size) {
Kostya Serebryany
committed
void *res = malloc_ccc(size); break_optimization(0); return res;}
NOINLINE void *malloc_aaa(size_t size) {
Kostya Serebryany
committed
void *res = malloc_bbb(size); break_optimization(0); return res;}
#ifndef __APPLE__
NOINLINE void *memalign_fff(size_t alignment, size_t size) {
Kostya Serebryany
committed
void *res = memalign/**/(alignment, size); break_optimization(0); return res;}
NOINLINE void *memalign_eee(size_t alignment, size_t size) {
Kostya Serebryany
committed
void *res = memalign_fff(alignment, size); break_optimization(0); return res;}
NOINLINE void *memalign_ddd(size_t alignment, size_t size) {
Kostya Serebryany
committed
void *res = memalign_eee(alignment, size); break_optimization(0); return res;}
NOINLINE void *memalign_ccc(size_t alignment, size_t size) {
Kostya Serebryany
committed
void *res = memalign_ddd(alignment, size); break_optimization(0); return res;}
NOINLINE void *memalign_bbb(size_t alignment, size_t size) {
Kostya Serebryany
committed
void *res = memalign_ccc(alignment, size); break_optimization(0); return res;}
NOINLINE void *memalign_aaa(size_t alignment, size_t size) {
Kostya Serebryany
committed
void *res = memalign_bbb(alignment, size); break_optimization(0); return res;}
#endif // __APPLE__
NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
Kostya Serebryany
committed
Timur Iskhodzhanov
committed
template<typename T>
NOINLINE void oob_test(int size, int off) {
Kostya Serebryany
committed
char *p = (char*)malloc_aaa(size);
// fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
// sizeof(T), p, p + size, off);
asan_write((T*)(p + off));
free_aaa(p);
}
Timur Iskhodzhanov
committed
template<typename T>
NOINLINE void uaf_test(int size, int off) {
Kostya Serebryany
committed
char *p = (char *)malloc_aaa(size);
free_aaa(p);
for (int i = 1; i < 100; i++)
free_aaa(malloc_aaa(i));
fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
(long)sizeof(T), p, off);
asan_write((T*)(p + off));
}
Kostya Serebryany
committed
TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
#if defined(__has_feature) && __has_feature(address_sanitizer)
bool asan = 1;
#else
bool asan = 0;
#endif
EXPECT_EQ(true, asan);
Kostya Serebryany
committed
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
}
TEST(AddressSanitizer, SimpleDeathTest) {
EXPECT_DEATH(exit(1), "");
}
TEST(AddressSanitizer, VariousMallocsTest) {
// fprintf(stderr, "malloc:\n");
int *a = (int*)malloc(100 * sizeof(int));
a[50] = 0;
free(a);
// fprintf(stderr, "realloc:\n");
int *r = (int*)malloc(10);
r = (int*)realloc(r, 2000 * sizeof(int));
r[1000] = 0;
free(r);
// fprintf(stderr, "operator new []\n");
int *b = new int[100];
b[50] = 0;
delete [] b;
// fprintf(stderr, "operator new\n");
int *c = new int;
*c = 0;
delete c;
#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__)
Kostya Serebryany
committed
// fprintf(stderr, "posix_memalign\n");
int *pm;
int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
EXPECT_EQ(0, pm_res);
free(pm);
Kostya Serebryany
committed
Alexey Samsonov
committed
#if !defined(__APPLE__)
Kostya Serebryany
committed
int *ma = (int*)memalign(kPageSize, kPageSize);
EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
Kostya Serebryany
committed
ma[123] = 0;
free(ma);
#endif // __APPLE__
}
TEST(AddressSanitizer, CallocTest) {
int *a = (int*)calloc(100, sizeof(int));
EXPECT_EQ(0, a[10]);
free(a);
}
TEST(AddressSanitizer, VallocTest) {
void *a = valloc(100);
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
Kostya Serebryany
committed
free(a);
}
#ifndef __APPLE__
TEST(AddressSanitizer, PvallocTest) {
char *a = (char*)pvalloc(kPageSize + 100);
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
Kostya Serebryany
committed
a[kPageSize + 101] = 1; // we should not report an error here.
free(a);
a = (char*)pvalloc(0); // pvalloc(0) should allocate at least one page.
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
Kostya Serebryany
committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
a[101] = 1; // we should not report an error here.
free(a);
}
#endif // __APPLE__
void *TSDWorker(void *test_key) {
if (test_key) {
pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
}
return NULL;
}
void TSDDestructor(void *tsd) {
// Spawning a thread will check that the current thread id is not -1.
pthread_t th;
pthread_create(&th, NULL, TSDWorker, NULL);
pthread_join(th, NULL);
}
// This tests triggers the thread-specific data destruction fiasco which occurs
// if we don't manage the TSD destructors ourselves. We create a new pthread
// key with a non-NULL destructor which is likely to be put after the destructor
// of AsanThread in the list of destructors.
// In this case the TSD for AsanThread will be destroyed before TSDDestructor
// is called for the child thread, and a CHECK will fail when we call
// pthread_create() to spawn the grandchild.
TEST(AddressSanitizer, DISABLED_TSDTest) {
pthread_t th;
pthread_key_t test_key;
pthread_key_create(&test_key, TSDDestructor);
pthread_create(&th, NULL, TSDWorker, &test_key);
pthread_join(th, NULL);
pthread_key_delete(test_key);
}
Timur Iskhodzhanov
committed
template<typename T>
Kostya Serebryany
committed
void OOBTest() {
char expected_str[100];
for (int size = sizeof(T); size < 20; size += 5) {
for (int i = -5; i < 0; i++) {
const char *str =
"is located.*%d byte.*to the left";
sprintf(expected_str, str, abs(i));
EXPECT_DEATH(oob_test<T>(size, i), expected_str);
}
for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
Kostya Serebryany
committed
oob_test<T>(size, i);
for (int i = size - sizeof(T) + 1; i <= (int)(size + 3 * sizeof(T)); i++) {
Kostya Serebryany
committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
const char *str =
"is located.*%d byte.*to the right";
int off = i >= size ? (i - size) : 0;
// we don't catch unaligned partially OOB accesses.
if (i % sizeof(T)) continue;
sprintf(expected_str, str, off);
EXPECT_DEATH(oob_test<T>(size, i), expected_str);
}
}
EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
"is located.*1 byte.*to the left");
EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
"is located.*0 byte.*to the right");
}
// TODO(glider): the following tests are EXTREMELY slow on Darwin:
// AddressSanitizer.OOB_char (125503 ms)
// AddressSanitizer.OOB_int (126890 ms)
// AddressSanitizer.OOBRightTest (315605 ms)
// AddressSanitizer.SimpleStackTest (366559 ms)
TEST(AddressSanitizer, OOB_char) {
OOBTest<U1>();
}
TEST(AddressSanitizer, OOB_int) {
OOBTest<U4>();
}
TEST(AddressSanitizer, OOBRightTest) {
for (size_t access_size = 1; access_size <= 8; access_size *= 2) {
for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
for (size_t offset = 0; offset <= 8; offset += access_size) {
void *p = malloc(alloc_size);
// allocated: [p, p + alloc_size)
// accessed: [p + offset, p + offset + access_size)
uint8_t *addr = (uint8_t*)p + offset;
if (offset + access_size <= alloc_size) {
asan_write_sized_aligned(addr, access_size);
} else {
int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
const char *str =
"is located.%d *byte.*to the right";
char expected_str[100];
sprintf(expected_str, str, outside_bytes);
EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
expected_str);
}
free(p);
}
}
}
}
TEST(AddressSanitizer, UAF_char) {
const char *uaf_string = "AddressSanitizer.*heap-use-after-free";
EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
}
#if ASAN_HAS_BLACKLIST
TEST(AddressSanitizer, IgnoreTest) {
int *x = Ident(new int);
delete Ident(x);
*x = 0;
}
#endif // ASAN_HAS_BLACKLIST
struct StructWithBitField {
int bf1:1;
int bf2:1;
int bf3:1;
int bf4:29;
};
TEST(AddressSanitizer, BitFieldPositiveTest) {
StructWithBitField *x = new StructWithBitField;
delete Ident(x);
EXPECT_DEATH(x->bf1 = 0, "use-after-free");
EXPECT_DEATH(x->bf2 = 0, "use-after-free");
EXPECT_DEATH(x->bf3 = 0, "use-after-free");
EXPECT_DEATH(x->bf4 = 0, "use-after-free");
Kostya Serebryany
committed
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
struct StructWithBitFields_8_24 {
int a:8;
int b:24;
};
TEST(AddressSanitizer, BitFieldNegativeTest) {
StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
x->a = 0;
x->b = 0;
delete Ident(x);
}
TEST(AddressSanitizer, OutOfMemoryTest) {
size_t size = __WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
EXPECT_EQ(0, realloc(0, size));
EXPECT_EQ(0, realloc(0, ~Ident(0)));
EXPECT_EQ(0, malloc(size));
EXPECT_EQ(0, malloc(~Ident(0)));
EXPECT_EQ(0, calloc(1, size));
EXPECT_EQ(0, calloc(1, ~Ident(0)));
}
#if ASAN_NEEDS_SEGV
TEST(AddressSanitizer, WildAddressTest) {
char *c = (char*)0x123;
EXPECT_DEATH(*c = 0, "AddressSanitizer crashed on unknown address");
}
#endif
static void MallocStress(size_t n) {
uint32_t seed = my_rand(&global_seed);
for (size_t iter = 0; iter < 10; iter++) {
vector<void *> vec;
for (size_t i = 0; i < n; i++) {
if ((i % 3) == 0) {
if (vec.empty()) continue;
size_t idx = my_rand(&seed) % vec.size();
void *ptr = vec[idx];
vec[idx] = vec.back();
vec.pop_back();
free_aaa(ptr);
} else {
size_t size = my_rand(&seed) % 1000 + 1;
#ifndef __APPLE__
size_t alignment = 1 << (my_rand(&seed) % 7 + 3);
char *ptr = (char*)memalign_aaa(alignment, size);
#else
char *ptr = (char*) malloc_aaa(size);
#endif
vec.push_back(ptr);
ptr[0] = 0;
ptr[size-1] = 0;
ptr[size/2] = 0;
}
}
for (size_t i = 0; i < vec.size(); i++)
free_aaa(vec[i]);
}
}
TEST(AddressSanitizer, MallocStressTest) {
MallocStress((ASAN_LOW_MEMORY) ? 20000 : 200000);
Kostya Serebryany
committed
}
static void TestLargeMalloc(size_t size) {
char buff[1024];
sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
}
TEST(AddressSanitizer, LargeMallocTest) {
for (int i = 113; i < (1 << 28); i = i * 2 + 13) {
TestLargeMalloc(i);
}
}
#if ASAN_LOW_MEMORY != 1
Kostya Serebryany
committed
TEST(AddressSanitizer, HugeMallocTest) {
#ifdef __APPLE__
// It was empirically found out that 1215 megabytes is the maximum amount of
// memory available to the process under AddressSanitizer on 32-bit Mac 10.6.
// 32-bit Mac 10.7 gives even less (< 1G).
Kostya Serebryany
committed
// (the libSystem malloc() allows allocating up to 2300 megabytes without
// ASan).
size_t n_megs = __WORDSIZE == 32 ? 500 : 4100;
Kostya Serebryany
committed
#else
size_t n_megs = __WORDSIZE == 32 ? 2600 : 4100;
#endif
TestLargeMalloc(n_megs << 20);
}
Kostya Serebryany
committed
TEST(AddressSanitizer, ThreadedMallocStressTest) {
const int kNumThreads = 4;
const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
Kostya Serebryany
committed
pthread_t t[kNumThreads];
for (int i = 0; i < kNumThreads; i++) {
pthread_create(&t[i], 0, (void* (*)(void *x))MallocStress,
(void*)kNumIterations);
Kostya Serebryany
committed
}
for (int i = 0; i < kNumThreads; i++) {
pthread_join(t[i], 0);
}
}
void *ManyThreadsWorker(void *a) {
for (int iter = 0; iter < 100; iter++) {
for (size_t size = 100; size < 2000; size *= 2) {
free(Ident(malloc(size)));
}
}
return 0;
}
TEST(AddressSanitizer, ManyThreadsTest) {
const size_t kNumThreads = __WORDSIZE == 32 ? 30 : 1000;
Kostya Serebryany
committed
pthread_t t[kNumThreads];
for (size_t i = 0; i < kNumThreads; i++) {
pthread_create(&t[i], 0, (void* (*)(void *x))ManyThreadsWorker, (void*)i);
}
for (size_t i = 0; i < kNumThreads; i++) {
pthread_join(t[i], 0);
}
}
TEST(AddressSanitizer, ReallocTest) {
const int kMinElem = 5;
int *ptr = (int*)malloc(sizeof(int) * kMinElem);
ptr[3] = 3;
for (int i = 0; i < 10000; i++) {
ptr = (int*)realloc(ptr,
(my_rand(&global_seed) % 1000 + kMinElem) * sizeof(int));
EXPECT_EQ(3, ptr[3]);
}
}
#ifndef __APPLE__
static const char *kMallocUsableSizeErrorMsg =
"AddressSanitizer attempting to call malloc_usable_size()";
TEST(AddressSanitizer, MallocUsableSizeTest) {
const size_t kArraySize = 100;
char *array = Ident((char*)malloc(kArraySize));
int *int_ptr = Ident(new int);
EXPECT_EQ(0U, malloc_usable_size(NULL));
EXPECT_EQ(kArraySize, malloc_usable_size(array));
EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
kMallocUsableSizeErrorMsg);
free(array);
EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
}
#endif
Kostya Serebryany
committed
void WrongFree() {
int *x = (int*)malloc(100 * sizeof(int));
// Use the allocated memory, otherwise Clang will optimize it out.
Ident(x);
free(x + 1);
}
TEST(AddressSanitizer, WrongFreeTest) {
Kostya Serebryany
committed
EXPECT_DEATH(WrongFree(),
"ERROR: AddressSanitizer attempting free.*not malloc");
Kostya Serebryany
committed
}
void DoubleFree() {
int *x = (int*)malloc(100 * sizeof(int));
fprintf(stderr, "DoubleFree: x=%p\n", x);
free(x);
free(x);
fprintf(stderr, "should have failed in the second free(%p)\n", x);
abort();
}
TEST(AddressSanitizer, DoubleFreeTest) {
Kostya Serebryany
committed
EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
"ERROR: AddressSanitizer attempting double-free"
".*is located 0 bytes inside of 400-byte region"
".*freed by thread T0 here"
".*previously allocated by thread T0 here");
Kostya Serebryany
committed
}
template<int kSize>
NOINLINE void SizedStackTest() {
Kostya Serebryany
committed
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
char a[kSize];
char *A = Ident((char*)&a);
for (size_t i = 0; i < kSize; i++)
A[i] = i;
EXPECT_DEATH(A[-1] = 0, "");
EXPECT_DEATH(A[-20] = 0, "");
EXPECT_DEATH(A[-31] = 0, "");
EXPECT_DEATH(A[kSize] = 0, "");
EXPECT_DEATH(A[kSize + 1] = 0, "");
EXPECT_DEATH(A[kSize + 10] = 0, "");
EXPECT_DEATH(A[kSize + 31] = 0, "");
}
TEST(AddressSanitizer, SimpleStackTest) {
SizedStackTest<1>();
SizedStackTest<2>();
SizedStackTest<3>();
SizedStackTest<4>();
SizedStackTest<5>();
SizedStackTest<6>();
SizedStackTest<7>();
SizedStackTest<16>();
SizedStackTest<25>();
SizedStackTest<34>();
SizedStackTest<43>();
SizedStackTest<51>();
SizedStackTest<62>();
SizedStackTest<64>();
SizedStackTest<128>();
}
TEST(AddressSanitizer, ManyStackObjectsTest) {
char XXX[10];
char YYY[20];
char ZZZ[30];
Ident(XXX);
Ident(YYY);
EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
}
NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
Kostya Serebryany
committed
char d[4] = {0};
char *D = Ident(d);
switch (frame) {
case 3: a[5]++; break;
case 2: b[5]++; break;
case 1: c[5]++; break;
case 0: D[5]++; break;
}
}
NOINLINE static void Frame1(int frame, char *a, char *b) {
Kostya Serebryany
committed
char c[4] = {0}; Frame0(frame, a, b, c);
break_optimization(0);
}
NOINLINE static void Frame2(int frame, char *a) {
Kostya Serebryany
committed
char b[4] = {0}; Frame1(frame, a, b);
break_optimization(0);
}
NOINLINE static void Frame3(int frame) {
Kostya Serebryany
committed
char a[4] = {0}; Frame2(frame, a);
break_optimization(0);
}
TEST(AddressSanitizer, GuiltyStackFrame0Test) {
EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
}
TEST(AddressSanitizer, GuiltyStackFrame1Test) {
EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
}
TEST(AddressSanitizer, GuiltyStackFrame2Test) {
EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
}
TEST(AddressSanitizer, GuiltyStackFrame3Test) {
EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
}
NOINLINE void LongJmpFunc1(jmp_buf buf) {
Kostya Serebryany
committed
// create three red zones for these two stack objects.
int a;
int b;
int *A = Ident(&a);
int *B = Ident(&b);
*A = *B;
longjmp(buf, 1);
}
NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
Kostya Serebryany
committed
// create three red zones for these two stack objects.
int a;
int b;
int *A = Ident(&a);
int *B = Ident(&b);
*A = *B;
_longjmp(buf, 1);
}
NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
Kostya Serebryany
committed
// create three red zones for these two stack objects.
int a;
int b;
int *A = Ident(&a);
int *B = Ident(&b);
*A = *B;
siglongjmp(buf, 1);
}
NOINLINE void TouchStackFunc() {
Kostya Serebryany
committed
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
int a[100]; // long array will intersect with redzones from LongJmpFunc1.
int *A = Ident(a);
for (int i = 0; i < 100; i++)
A[i] = i*i;
}
// Test that we handle longjmp and do not report fals positives on stack.
TEST(AddressSanitizer, LongJmpTest) {
static jmp_buf buf;
if (!setjmp(buf)) {
LongJmpFunc1(buf);
} else {
TouchStackFunc();
}
}
TEST(AddressSanitizer, UnderscopeLongJmpTest) {
static jmp_buf buf;
if (!_setjmp(buf)) {
UnderscopeLongJmpFunc1(buf);
} else {
TouchStackFunc();
}
}
TEST(AddressSanitizer, SigLongJmpTest) {
static sigjmp_buf buf;
if (!sigsetjmp(buf, 1)) {
SigLongJmpFunc1(buf);
} else {
TouchStackFunc();
}
}
#ifdef __EXCEPTIONS
NOINLINE void ThrowFunc() {
Kostya Serebryany
committed
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
// create three red zones for these two stack objects.
int a;
int b;
int *A = Ident(&a);
int *B = Ident(&b);
*A = *B;
ASAN_THROW(1);
}
TEST(AddressSanitizer, CxxExceptionTest) {
if (ASAN_UAR) return;
// TODO(kcc): this test crashes on 32-bit for some reason...
if (__WORDSIZE == 32) return;
try {
ThrowFunc();
} catch(...) {}
TouchStackFunc();
}
#endif
void *ThreadStackReuseFunc1(void *unused) {
// create three red zones for these two stack objects.
int a;
int b;
int *A = Ident(&a);
int *B = Ident(&b);
*A = *B;
pthread_exit(0);
return 0;
}
void *ThreadStackReuseFunc2(void *unused) {
TouchStackFunc();
return 0;
}
TEST(AddressSanitizer, ThreadStackReuseTest) {
pthread_t t;
pthread_create(&t, 0, ThreadStackReuseFunc1, 0);
pthread_join(t, 0);
pthread_create(&t, 0, ThreadStackReuseFunc2, 0);
pthread_join(t, 0);
}
#if defined(__i386__) || defined(__x86_64__)
Kostya Serebryany
committed
TEST(AddressSanitizer, Store128Test) {
char *a = Ident((char*)malloc(Ident(12)));
char *p = a;
if (((uintptr_t)a % 16) != 0)
p = a + 8;
assert(((uintptr_t)p % 16) == 0);
__m128i value_wide = _mm_set1_epi16(0x1234);
Kostya Serebryany
committed
EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
"AddressSanitizer heap-buffer-overflow");
Kostya Serebryany
committed
EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
"WRITE of size 16");
EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
"located 0 bytes to the right of 12-byte");
free(a);
}
#endif
static string RightOOBErrorMessage(int oob_distance) {
assert(oob_distance >= 0);
char expected_str[100];
sprintf(expected_str, "located %d bytes to the right", oob_distance);
return string(expected_str);
}
static string LeftOOBErrorMessage(int oob_distance) {
assert(oob_distance > 0);
char expected_str[100];
sprintf(expected_str, "located %d bytes to the left", oob_distance);
return string(expected_str);
}
Timur Iskhodzhanov
committed
template<typename T>
Kostya Serebryany
committed
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
void MemSetOOBTestTemplate(size_t length) {
if (length == 0) return;
size_t size = Ident(sizeof(T) * length);
T *array = Ident((T*)malloc(size));
int element = Ident(42);
int zero = Ident(0);
// memset interval inside array
memset(array, element, size);
memset(array, element, size - 1);
memset(array + length - 1, element, sizeof(T));
memset(array, element, 1);
// memset 0 bytes
memset(array - 10, element, zero);
memset(array - 1, element, zero);
memset(array, element, zero);
memset(array + length, 0, zero);
memset(array + length + 1, 0, zero);
// try to memset bytes to the right of array
EXPECT_DEATH(memset(array, 0, size + 1),
RightOOBErrorMessage(0));
EXPECT_DEATH(memset((char*)(array + length) - 1, element, 6),
RightOOBErrorMessage(4));
EXPECT_DEATH(memset(array + 1, element, size + sizeof(T)),
RightOOBErrorMessage(2 * sizeof(T) - 1));
// whole interval is to the right
EXPECT_DEATH(memset(array + length + 1, 0, 10),
RightOOBErrorMessage(sizeof(T)));
// try to memset bytes to the left of array
EXPECT_DEATH(memset((char*)array - 1, element, size),
LeftOOBErrorMessage(1));
EXPECT_DEATH(memset((char*)array - 5, 0, 6),
LeftOOBErrorMessage(5));
EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
LeftOOBErrorMessage(5 * sizeof(T)));
// whole interval is to the left
EXPECT_DEATH(memset(array - 2, 0, sizeof(T)),
LeftOOBErrorMessage(2 * sizeof(T)));
// try to memset bytes both to the left & to the right
EXPECT_DEATH(memset((char*)array - 2, element, size + 4),
LeftOOBErrorMessage(2));
free(array);
}
TEST(AddressSanitizer, MemSetOOBTest) {
MemSetOOBTestTemplate<char>(100);
MemSetOOBTestTemplate<int>(5);
MemSetOOBTestTemplate<double>(256);
// We can test arrays of structres/classes here, but what for?
}
// Same test for memcpy and memmove functions
Timur Iskhodzhanov
committed
template <typename T, class M>
Kostya Serebryany
committed
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
void MemTransferOOBTestTemplate(size_t length) {
if (length == 0) return;
size_t size = Ident(sizeof(T) * length);
T *src = Ident((T*)malloc(size));
T *dest = Ident((T*)malloc(size));
int zero = Ident(0);
// valid transfer of bytes between arrays
M::transfer(dest, src, size);
M::transfer(dest + 1, src, size - sizeof(T));
M::transfer(dest, src + length - 1, sizeof(T));
M::transfer(dest, src, 1);
// transfer zero bytes
M::transfer(dest - 1, src, 0);
M::transfer(dest + length, src, zero);
M::transfer(dest, src - 1, zero);
M::transfer(dest, src, zero);
// try to change mem to the right of dest
EXPECT_DEATH(M::transfer(dest + 1, src, size),
RightOOBErrorMessage(sizeof(T) - 1));
EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
RightOOBErrorMessage(3));
// try to change mem to the left of dest
EXPECT_DEATH(M::transfer(dest - 2, src, size),
LeftOOBErrorMessage(2 * sizeof(T)));
EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
LeftOOBErrorMessage(3));
// try to access mem to the right of src
EXPECT_DEATH(M::transfer(dest, src + 2, size),
RightOOBErrorMessage(2 * sizeof(T) - 1));
EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
RightOOBErrorMessage(2));
// try to access mem to the left of src
EXPECT_DEATH(M::transfer(dest, src - 1, size),
LeftOOBErrorMessage(sizeof(T)));
EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
LeftOOBErrorMessage(6));
// Generally we don't need to test cases where both accessing src and writing
// to dest address to poisoned memory.
T *big_src = Ident((T*)malloc(size * 2));
T *big_dest = Ident((T*)malloc(size * 2));
// try to change mem to both sides of dest
EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
LeftOOBErrorMessage(sizeof(T)));
// try to access mem to both sides of src
EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
LeftOOBErrorMessage(2 * sizeof(T)));
free(src);
free(dest);
free(big_src);
free(big_dest);
}
class MemCpyWrapper {
public:
static void* transfer(void *to, const void *from, size_t size) {
return memcpy(to, from, size);
}
};
TEST(AddressSanitizer, MemCpyOOBTest) {
MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
}
class MemMoveWrapper {
public:
static void* transfer(void *to, const void *from, size_t size) {
return memmove(to, from, size);
}
};
TEST(AddressSanitizer, MemMoveOOBTest) {
MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
}
// Tests for string functions
// Used for string functions tests
static char global_string[] = "global";
static size_t global_string_length = 6;
// Input to a test is a zero-terminated string str with given length
// Accesses to the bytes to the left and to the right of str
// are presumed to produce OOB errors
void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
// Normal strlen calls
EXPECT_EQ(strlen(str), length);
if (length > 0) {
EXPECT_EQ(length - 1, strlen(str + 1));
EXPECT_EQ(0U, strlen(str + length));
Kostya Serebryany
committed
}
// Arg of strlen is not malloced, OOB access
if (!is_global) {
// We don't insert RedZones to the left of global variables
EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBErrorMessage(1));
EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBErrorMessage(5));
}
EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBErrorMessage(0));
// Overwrite terminator
str[length] = 'a';
// String is not zero-terminated, strlen will lead to OOB access
EXPECT_DEATH(Ident(strlen(str)), RightOOBErrorMessage(0));
EXPECT_DEATH(Ident(strlen(str + length)), RightOOBErrorMessage(0));
// Restore terminator
str[length] = 0;
}
TEST(AddressSanitizer, StrLenOOBTest) {
// Check heap-allocated string
size_t length = Ident(10);
char *heap_string = Ident((char*)malloc(length + 1));
char stack_string[10 + 1];
for (size_t i = 0; i < length; i++) {
Kostya Serebryany
committed
heap_string[i] = 'a';
stack_string[i] = 'b';
}
heap_string[length] = 0;
stack_string[length] = 0;
StrLenOOBTestTemplate(heap_string, length, false);
// TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
// make test for stack_string work. Or move it to output tests.
// StrLenOOBTestTemplate(stack_string, length, false);
StrLenOOBTestTemplate(global_string, global_string_length, true);
free(heap_string);
}
static inline char* MallocAndMemsetString(size_t size, char ch) {
Kostya Serebryany
committed
char *s = Ident((char*)malloc(size));
Kostya Serebryany
committed
return s;
}
static inline char* MallocAndMemsetString(size_t size) {
return MallocAndMemsetString(size, 'z');
}
Kostya Serebryany
committed
Kostya Serebryany
committed
#ifndef __APPLE__
TEST(AddressSanitizer, StrNLenOOBTest) {
size_t size = Ident(123);
Kostya Serebryany
committed
char *str = MallocAndMemsetString(size);
Kostya Serebryany
committed
// Normal strnlen calls.
Ident(strnlen(str - 1, 0));
Ident(strnlen(str, size));
Ident(strnlen(str + size - 1, 1));
str[size - 1] = '\0';
Ident(strnlen(str, 2 * size));
// Argument points to not allocated memory.
EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBErrorMessage(1));
EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBErrorMessage(0));
// Overwrite the terminating '\0' and hit unallocated memory.
str[size - 1] = 'z';
EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBErrorMessage(0));
free(str);
}
#endif
TEST(AddressSanitizer, StrDupOOBTest) {
size_t size = Ident(42);
Kostya Serebryany
committed
char *str = MallocAndMemsetString(size);
Kostya Serebryany
committed
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
char *new_str;
// Normal strdup calls.
str[size - 1] = '\0';
new_str = strdup(str);
free(new_str);
new_str = strdup(str + size - 1);
free(new_str);
// Argument points to not allocated memory.
EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBErrorMessage(1));
EXPECT_DEATH(Ident(strdup(str + size)), RightOOBErrorMessage(0));
// Overwrite the terminating '\0' and hit unallocated memory.
str[size - 1] = 'z';
EXPECT_DEATH(Ident(strdup(str)), RightOOBErrorMessage(0));
free(str);
}
TEST(AddressSanitizer, StrCpyOOBTest) {
size_t to_size = Ident(30);
size_t from_size = Ident(6); // less than to_size
char *to = Ident((char*)malloc(to_size));
char *from = Ident((char*)malloc(from_size));
// Normal strcpy calls.
strcpy(from, "hello");
strcpy(to, from);
strcpy(to + to_size - from_size, from);
// Length of "from" is too small.