diff options
author | Andrew Turner <andrew@FreeBSD.org> | 2012-07-30 10:58:13 +0000 |
---|---|---|
committer | Andrew Turner <andrew@FreeBSD.org> | 2012-07-30 10:58:13 +0000 |
commit | 37dfff057418e02f8e5322da12684dd927e3d881 (patch) | |
tree | 40cc44a3d02ed86de24f2117a55680e4f0eb01a0 /lib/asan/tests | |
parent | 864a7b98b54e1f984c248f3be83dfcc082a382ea (diff) | |
download | src-37dfff057418e02f8e5322da12684dd927e3d881.tar.gz src-37dfff057418e02f8e5322da12684dd927e3d881.zip |
Import compiler-rt r160957.vendor/compiler-rt/compiler-rt-r160957
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=238901
svn path=/vendor/compiler-rt/compiler-rt-r160957/; revision=238902; tag=vendor/compiler-rt/compiler-rt-r160957
Diffstat (limited to 'lib/asan/tests')
38 files changed, 986 insertions, 1059 deletions
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt new file mode 100644 index 000000000000..d409d50b995e --- /dev/null +++ b/lib/asan/tests/CMakeLists.txt @@ -0,0 +1,118 @@ +# Testing rules for AddressSanitizer. +# +# These are broken into two buckets. One set of tests directly interacts with +# the runtime library and checks its functionality. These are the +# no-instrumentation tests. +# +# Another group of tests relies upon the ability to compile the test with +# address sanitizer instrumentation pass. These tests form "integration" tests +# and have some elements of version skew -- they test the *host* compiler's +# instrumentation against the just-built runtime library. + +include(CheckCXXCompilerFlag) + +include_directories(..) +include_directories(../..) + +set(ASAN_UNITTEST_COMMON_CFLAGS + -Wall + -Wno-format + -fvisibility=hidden +) +# Support 64-bit and 32-bit builds. +if(LLVM_BUILD_32_BITS) + list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -m32) +else() + list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -m64) +endif() + +set(ASAN_GTEST_INCLUDE_CFLAGS + -I${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include + -I${LLVM_MAIN_SRC_DIR}/include + -I${LLVM_BINARY_DIR}/include + -D__STDC_CONSTANT_MACROS + -D__STDC_LIMIT_MACROS +) + +set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS + ${ASAN_UNITTEST_COMMON_CFLAGS} + ${ASAN_GTEST_INCLUDE_CFLAGS} + -faddress-sanitizer + -O2 + -g + -mllvm "-asan-blacklist=${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore" + -DASAN_HAS_BLACKLIST=1 + -DASAN_HAS_EXCEPTIONS=1 + -DASAN_NEEDS_SEGV=1 + -DASAN_UAR=0 +) + +add_custom_target(AsanTests) +set_target_properties(AsanTests PROPERTIES FOLDER "ASan tests") +function(add_asan_test testname) + add_unittest(AsanTests ${testname} ${ARGN}) + if(LLVM_BUILD_32_BITS) + target_link_libraries(${testname} clang_rt.asan-i386) + else() + target_link_libraries(${testname} clang_rt.asan-x86_64) + endif() + if (APPLE) + # Darwin-specific linker flags. + set_property(TARGET ${testname} APPEND PROPERTY + LINK_FLAGS "-framework Foundation") + elseif (UNIX) + # Linux-specific linker flags. + set_property(TARGET ${testname} APPEND PROPERTY + LINK_FLAGS "-lpthread -ldl -export-dynamic") + endif() + set(add_compile_flags "") + get_property(compile_flags TARGET ${testname} PROPERTY COMPILE_FLAGS) + foreach(arg ${ASAN_UNITTEST_COMMON_CFLAGS}) + set(add_compile_flags "${add_compile_flags} ${arg}") + endforeach(arg ${ASAN_UNITTEST_COMMON_CFLAGS}) + set_property(TARGET ${testname} PROPERTY COMPILE_FLAGS + "${compile_flags} ${add_compile_flags}") +endfunction() + +set(ASAN_NOINST_TEST_SOURCES + asan_noinst_test.cc + asan_break_optimization.cc +) + +set(ASAN_INST_TEST_OBJECTS) + +# We only support building instrumented tests when we're not cross compiling +# and targeting a unix-like system where we can predict viable compilation and +# linking strategies. +if("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}" AND UNIX) + + # This function is a custom routine to manage manually compiling source files + # for unit tests with the just-built Clang binary, using the ASan + # instrumentation, and linking them into a test executable. + function(add_asan_compile_command source extra_cflags) + set(output_obj "${source}.asan.o") + add_custom_command( + OUTPUT ${output_obj} + COMMAND clang + ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} + ${extra_cflags} + -c -o "${output_obj}" + ${CMAKE_CURRENT_SOURCE_DIR}/${source} + MAIN_DEPENDENCY ${source} + DEPENDS clang clang_rt.asan-i386 clang_rt.asan-x86_64 ${ARGN} + ) + endfunction() + + add_asan_compile_command(asan_globals_test.cc "") + add_asan_compile_command(asan_test.cc "") + list(APPEND ASAN_INST_TEST_OBJECTS asan_globals_test.cc.asan.o + asan_test.cc.asan.o) + if (APPLE) + add_asan_compile_command(asan_mac_test.mm "-ObjC") + list(APPEND ASAN_INST_TEST_OBJECTS asan_mac_test.mm.asan.o) + endif() + +endif() + +add_asan_test(AsanTest ${ASAN_NOINST_TEST_SOURCES} + ${ASAN_INST_TEST_OBJECTS}) diff --git a/lib/asan/tests/asan_benchmarks_test.cc b/lib/asan/tests/asan_benchmarks_test.cc index b72cc3fbe14b..a142fd23e1b8 100644 --- a/lib/asan/tests/asan_benchmarks_test.cc +++ b/lib/asan/tests/asan_benchmarks_test.cc @@ -1,4 +1,4 @@ -//===-- asan_benchmarks_test.cc ------------*- C++ -*-===// +//===-- asan_benchmarks_test.cc ----------------------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/asan/tests/asan_break_optimization.cc b/lib/asan/tests/asan_break_optimization.cc index acd042701e1e..022a9f8b8505 100644 --- a/lib/asan/tests/asan_break_optimization.cc +++ b/lib/asan/tests/asan_break_optimization.cc @@ -1,4 +1,4 @@ -//===-- asan_break_optimization.cc ------------*- C++ -*-===// +//===-- asan_break_optimization.cc ----------------------===// // // The LLVM Compiler Infrastructure // @@ -15,4 +15,5 @@ // Have this function in a separate file to avoid inlining. // (Yes, we know about cross-file inlining, but let's assume we don't use it). extern "C" void break_optimization(void *x) { + (void)x; } diff --git a/lib/asan/tests/asan_globals_test.cc b/lib/asan/tests/asan_globals_test.cc index 2303f8bdc43b..6467524ca32c 100644 --- a/lib/asan/tests/asan_globals_test.cc +++ b/lib/asan/tests/asan_globals_test.cc @@ -1,4 +1,4 @@ -//===-- asan_globals_test.cc ------------*- C++ -*-===// +//===-- asan_globals_test.cc ----------------------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc deleted file mode 100644 index c26ed92468b3..000000000000 --- a/lib/asan/tests/asan_interface_test.cc +++ /dev/null @@ -1,334 +0,0 @@ -//===-- asan_interface_test.cc ------------*- C++ -*-===// -// -// 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 <pthread.h> -#include <stdio.h> -#include <string.h> - -#include "asan_test_config.h" -#include "asan_test_utils.h" -#include "asan_interface.h" - -TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) { - EXPECT_EQ(1, __asan_get_estimated_allocated_size(0)); - 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])); - } -} - -static const char* kGetAllocatedSizeErrorMsg = - "__asan_get_allocated_size failed"; - -TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) { - const size_t kArraySize = 100; - char *array = Ident((char*)malloc(kArraySize)); - int *int_ptr = Ident(new int); - - // Allocated memory is owned by allocator. Allocated size should be - // equal to requested size. - EXPECT_EQ(true, __asan_get_ownership(array)); - EXPECT_EQ(kArraySize, __asan_get_allocated_size(array)); - EXPECT_EQ(true, __asan_get_ownership(int_ptr)); - EXPECT_EQ(sizeof(int), __asan_get_allocated_size(int_ptr)); - - // 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_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg); - EXPECT_EQ(false, __asan_get_ownership(array + kArraySize / 2)); - EXPECT_DEATH(__asan_get_allocated_size(array + kArraySize / 2), - kGetAllocatedSizeErrorMsg); - - // NULL is a valid argument and is owned. - EXPECT_EQ(true, __asan_get_ownership(NULL)); - EXPECT_EQ(0, __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_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg); - - delete int_ptr; -} - -TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) { - size_t before_malloc, after_malloc, after_free; - char *array; - const size_t kMallocSize = 100; - before_malloc = __asan_get_current_allocated_bytes(); - - array = Ident((char*)malloc(kMallocSize)); - after_malloc = __asan_get_current_allocated_bytes(); - EXPECT_EQ(before_malloc + kMallocSize, after_malloc); - - free(array); - after_free = __asan_get_current_allocated_bytes(); - EXPECT_EQ(before_malloc, after_free); -} - -static void DoDoubleFree() { - int *x = Ident(new int); - delete Ident(x); - delete Ident(x); -} - -// 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. -static void RunGetHeapSizeTestAndDie() { - size_t old_heap_size, new_heap_size, heap_growth; - // We unlikely have have chunk of this size in free list. - static const size_t kLargeMallocSize = 1 << 29; // 512M - old_heap_size = __asan_get_heap_size(); - fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize); - free(Ident(malloc(kLargeMallocSize))); - new_heap_size = __asan_get_heap_size(); - heap_growth = new_heap_size - old_heap_size; - fprintf(stderr, "heap growth after first malloc: %zu\n", heap_growth); - ASSERT_GE(heap_growth, kLargeMallocSize); - ASSERT_LE(heap_growth, 2 * kLargeMallocSize); - - // Now large chunk should fall into free list, and can be - // allocated without increasing heap size. - old_heap_size = new_heap_size; - free(Ident(malloc(kLargeMallocSize))); - heap_growth = __asan_get_heap_size() - old_heap_size; - fprintf(stderr, "heap growth after second malloc: %zu\n", heap_growth); - ASSERT_LT(heap_growth, kLargeMallocSize); - - // Test passed. Now die with expected double-free. - DoDoubleFree(); -} - -TEST(AddressSanitizerInterface, GetHeapSizeTest) { - EXPECT_DEATH(RunGetHeapSizeTestAndDie(), "double-free"); -} - -// Note: use ASSERT_* instead of EXPECT_* here. -static void DoLargeMallocForGetFreeBytesTestAndDie() { - 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 - // into quarantine and will be available for future requests. - old_free_bytes = __asan_get_free_bytes(); - fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize); - fprintf(stderr, "free bytes before malloc: %zu\n", old_free_bytes); - free(Ident(malloc(kLargeMallocSize))); - 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); - // 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; - // 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; - } - // Deleting these chunks will move them to quarantine, number of free - // bytes won't increase. - for (i = 0; i < kNumOfChunks; i++) { - free(chunks[i]); - EXPECT_EQ(old_free_bytes, __asan_get_free_bytes()); - } - EXPECT_DEATH(DoLargeMallocForGetFreeBytesTestAndDie(), "double-free"); -} - -static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<20, 357}; -static const size_t kManyThreadsIterations = 250; -static const size_t kManyThreadsNumThreads = 200; - -void *ManyThreadsWithStatsWorker(void *arg) { - for (size_t iter = 0; iter < kManyThreadsIterations; iter++) { - for (size_t size_index = 0; size_index < 4; size_index++) { - free(Ident(malloc(kManyThreadsMallocSizes[size_index]))); - } - } - return 0; -} - -TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) { - size_t before_test, after_test, i; - pthread_t threads[kManyThreadsNumThreads]; - before_test = __asan_get_current_allocated_bytes(); - for (i = 0; i < kManyThreadsNumThreads; i++) { - pthread_create(&threads[i], 0, - (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i); - } - for (i = 0; i < kManyThreadsNumThreads; i++) { - pthread_join(threads[i], 0); - } - after_test = __asan_get_current_allocated_bytes(); - // ASan stats also reflect memory usage of internal ASan RTL structs, - // so we can't check for equality here. - EXPECT_LT(after_test, before_test + (1UL<<20)); -} - -TEST(AddressSanitizerInterface, ExitCode) { - int original_exit_code = __asan_set_error_exit_code(7); - EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), ""); - EXPECT_EQ(7, __asan_set_error_exit_code(8)); - EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), ""); - EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code)); - EXPECT_EXIT(DoDoubleFree(), - ::testing::ExitedWithCode(original_exit_code), ""); -} - -static const char* kUseAfterPoisonErrorMessage = "use-after-poison"; - -#define ACCESS(ptr, offset) Ident(*(ptr + offset)) - -#define DIE_ON_ACCESS(ptr, offset) \ - EXPECT_DEATH(Ident(*(ptr + offset)), kUseAfterPoisonErrorMessage) - -TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) { - char *array = Ident((char*)malloc(120)); - // poison array[40..80) - ASAN_POISON_MEMORY_REGION(array + 40, 40); - ACCESS(array, 39); - ACCESS(array, 80); - DIE_ON_ACCESS(array, 40); - DIE_ON_ACCESS(array, 60); - DIE_ON_ACCESS(array, 79); - ASAN_UNPOISON_MEMORY_REGION(array + 40, 40); - // access previously poisoned memory. - ACCESS(array, 40); - ACCESS(array, 79); - free(array); -} - -TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) { - char *array = Ident((char*)malloc(120)); - // Poison [0..40) and [80..120) - ASAN_POISON_MEMORY_REGION(array, 40); - ASAN_POISON_MEMORY_REGION(array + 80, 40); - DIE_ON_ACCESS(array, 20); - ACCESS(array, 60); - DIE_ON_ACCESS(array, 100); - // Poison whole array - [0..120) - ASAN_POISON_MEMORY_REGION(array, 120); - DIE_ON_ACCESS(array, 60); - // Unpoison [24..96) - ASAN_UNPOISON_MEMORY_REGION(array + 24, 72); - DIE_ON_ACCESS(array, 23); - ACCESS(array, 24); - ACCESS(array, 60); - ACCESS(array, 95); - DIE_ON_ACCESS(array, 96); - free(array); -} - -TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) { - // Vector of capacity 20 - char *vec = Ident((char*)malloc(20)); - ASAN_POISON_MEMORY_REGION(vec, 20); - for (size_t i = 0; i < 7; i++) { - // Simulate push_back. - ASAN_UNPOISON_MEMORY_REGION(vec + i, 1); - ACCESS(vec, i); - DIE_ON_ACCESS(vec, i + 1); - } - for (size_t i = 7; i > 0; i--) { - // Simulate pop_back. - ASAN_POISON_MEMORY_REGION(vec + i - 1, 1); - DIE_ON_ACCESS(vec, i - 1); - if (i > 1) ACCESS(vec, i - 2); - } - free(vec); -} - -// Make sure that each aligned block of size "2^granularity" doesn't have -// "true" value before "false" value. -static void MakeShadowValid(bool *shadow, int length, int granularity) { - bool can_be_poisoned = true; - for (int i = length - 1; i >= 0; i--) { - can_be_poisoned &= shadow[i]; - shadow[i] &= can_be_poisoned; - if (i % (1 << granularity) == 0) { - can_be_poisoned = true; - } - } -} - -TEST(AddressSanitizerInterface, PoisoningStressTest) { - const size_t kSize = 24; - bool expected[kSize]; - char *arr = Ident((char*)malloc(kSize)); - for (size_t l1 = 0; l1 < kSize; l1++) { - for (size_t s1 = 1; l1 + s1 <= kSize; s1++) { - for (size_t l2 = 0; l2 < kSize; l2++) { - for (size_t s2 = 1; l2 + s2 <= kSize; s2++) { - // Poison [l1, l1+s1), [l2, l2+s2) and check result. - ASAN_UNPOISON_MEMORY_REGION(arr, kSize); - ASAN_POISON_MEMORY_REGION(arr + l1, s1); - ASAN_POISON_MEMORY_REGION(arr + l2, s2); - memset(expected, false, kSize); - memset(expected + l1, true, s1); - MakeShadowValid(expected, 24, /*granularity*/ 3); - memset(expected + l2, true, s2); - MakeShadowValid(expected, 24, /*granularity*/ 3); - for (size_t i = 0; i < kSize; i++) { - ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i)); - } - // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result. - ASAN_POISON_MEMORY_REGION(arr, kSize); - ASAN_UNPOISON_MEMORY_REGION(arr + l1, s1); - ASAN_UNPOISON_MEMORY_REGION(arr + l2, s2); - memset(expected, true, kSize); - memset(expected + l1, false, s1); - MakeShadowValid(expected, 24, /*granularity*/ 3); - memset(expected + l2, false, s2); - MakeShadowValid(expected, 24, /*granularity*/ 3); - for (size_t i = 0; i < kSize; i++) { - ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i)); - } - } - } - } - } -} - -static const char *kInvalidPoisonMessage = "invalid-poison-memory-range"; -static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range"; - -TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) { - char *array = Ident((char*)malloc(120)); - ASAN_UNPOISON_MEMORY_REGION(array, 120); - // Try to unpoison not owned memory - EXPECT_DEATH(ASAN_UNPOISON_MEMORY_REGION(array, 121), - kInvalidUnpoisonMessage); - EXPECT_DEATH(ASAN_UNPOISON_MEMORY_REGION(array - 1, 120), - kInvalidUnpoisonMessage); - - ASAN_POISON_MEMORY_REGION(array, 120); - // Try to poison not owned memory. - EXPECT_DEATH(ASAN_POISON_MEMORY_REGION(array, 121), kInvalidPoisonMessage); - EXPECT_DEATH(ASAN_POISON_MEMORY_REGION(array - 1, 120), - kInvalidPoisonMessage); - free(array); -} diff --git a/lib/asan/tests/asan_mac_test.h b/lib/asan/tests/asan_mac_test.h index e3ad8273ae14..441547a5a3dc 100644 --- a/lib/asan/tests/asan_mac_test.h +++ b/lib/asan/tests/asan_mac_test.h @@ -1,5 +1,5 @@ extern "C" { - void CFAllocatorDefaultDoubleFree(); + void *CFAllocatorDefaultDoubleFree(void *unused); void CFAllocatorSystemDefaultDoubleFree(); void CFAllocatorMallocDoubleFree(); void CFAllocatorMallocZoneDoubleFree(); @@ -13,4 +13,7 @@ extern "C" { void TestGCDSourceEvent(); void TestGCDSourceCancel(); void TestGCDGroupAsync(); + void TestOOBNSObjects(); + void TestNSURLDeallocation(); + void TestPassCFMemoryToAnotherThread(); } diff --git a/lib/asan/tests/asan_mac_test.mm b/lib/asan/tests/asan_mac_test.mm index b5dbbde4f315..4e5873b74485 100644 --- a/lib/asan/tests/asan_mac_test.mm +++ b/lib/asan/tests/asan_mac_test.mm @@ -7,11 +7,14 @@ #import <CoreFoundation/CFBase.h> #import <Foundation/NSObject.h> +#import <Foundation/NSURL.h> -void CFAllocatorDefaultDoubleFree() { +// This is a (void*)(void*) function so it can be passed to pthread_create. +void *CFAllocatorDefaultDoubleFree(void *unused) { void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0); CFAllocatorDeallocate(kCFAllocatorDefault, mem); CFAllocatorDeallocate(kCFAllocatorDefault, mem); + return 0; } void CFAllocatorSystemDefaultDoubleFree() { @@ -32,6 +35,10 @@ void CFAllocatorMallocZoneDoubleFree() { CFAllocatorDeallocate(kCFAllocatorMallocZone, mem); } +__attribute__((noinline)) +void access_memory(char *a) { + *a = 0; +} // Test the +load instrumentation. // Because the +load methods are invoked before anything else is initialized, @@ -51,7 +58,7 @@ char kStartupStr[] = +(void) load { for (int i = 0; i < strlen(kStartupStr); i++) { - volatile char ch = kStartupStr[i]; // make sure no optimizations occur. + access_memory(&kStartupStr[i]); // make sure no optimizations occur. } // Don't print anything here not to interfere with the death tests. } @@ -66,7 +73,7 @@ void worker_do_alloc(int size) { void worker_do_crash(int size) { char * volatile mem = malloc(size); - mem[size] = 0; // BOOM + access_memory(&mem[size]); // BOOM free(mem); } @@ -162,7 +169,7 @@ void TestGCDSourceEvent() { dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0); char * volatile mem = malloc(10); dispatch_source_set_event_handler(timer, ^{ - mem[10] = 1; + access_memory(&mem[10]); }); dispatch_resume(timer); sleep(2); @@ -186,7 +193,7 @@ void TestGCDSourceCancel() { dispatch_source_cancel(timer); }); dispatch_source_set_cancel_handler(timer, ^{ - mem[10] = 1; + access_memory(&mem[10]); }); dispatch_resume(timer); sleep(2); @@ -197,7 +204,34 @@ void TestGCDGroupAsync() { dispatch_group_t group = dispatch_group_create(); char * volatile mem = malloc(10); dispatch_group_async(group, queue, ^{ - mem[10] = 1; + access_memory(&mem[10]); }); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); } + +@interface FixedArray : NSObject { + int items[10]; +} +@end + +@implementation FixedArray +-(int) access: (int)index { + return items[index]; +} +@end + +void TestOOBNSObjects() { + id anObject = [FixedArray new]; + [anObject access:1]; + [anObject access:11]; + [anObject release]; +} + +void TestNSURLDeallocation() { + NSURL *base = + [[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"]; + volatile NSURL *u = + [[NSURL alloc] initWithString:@"Saved Application State" + relativeToURL:base]; + [u release]; +} diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc index 204c0dacc342..44d4c3c845b2 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 ------------*- C++ -*-===// +//===-- asan_noinst_test.cc ----------------------===// // // The LLVM Compiler Infrastructure // @@ -21,17 +21,18 @@ #include <assert.h> #include <stdio.h> #include <stdlib.h> -#include <vector> +#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 uint32_t my_rand(uint32_t* state) { +static inline u32 my_rand(u32* state) { return (*state = *state * 1103515245 + 12345) >> 16; } -static uint32_t global_seed = 0; +static u32 global_seed = 0; TEST(AddressSanitizer, InternalSimpleDeathTest) { @@ -39,7 +40,7 @@ TEST(AddressSanitizer, InternalSimpleDeathTest) { } static void MallocStress(size_t n) { - uint32_t seed = my_rand(&global_seed); + u32 seed = my_rand(&global_seed); __asan::AsanStackTrace stack1; stack1.trace[0] = 0xa123; stack1.trace[1] = 0xa456; @@ -92,16 +93,16 @@ TEST(AddressSanitizer, NoInstMallocTest) { #endif } -static void PrintShadow(const char *tag, uintptr_t ptr, size_t size) { +static void PrintShadow(const char *tag, uptr ptr, size_t size) { fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size); - uintptr_t prev_shadow = 0; - for (intptr_t i = -32; i < (intptr_t)size + 32; i++) { - uintptr_t shadow = __asan::MemToShadow(ptr + i); - if (i == 0 || i == (intptr_t)size) + uptr prev_shadow = 0; + for (sptr i = -32; i < (sptr)size + 32; i++) { + uptr shadow = __asan::MemToShadow(ptr + i); + if (i == 0 || i == (sptr)size) fprintf(stderr, "."); if (shadow != prev_shadow) { prev_shadow = shadow; - fprintf(stderr, "%02x", (int)*(uint8_t*)shadow); + fprintf(stderr, "%02x", (int)*(u8*)shadow); } } fprintf(stderr, "\n"); @@ -110,13 +111,13 @@ static void PrintShadow(const char *tag, uintptr_t ptr, size_t size) { TEST(AddressSanitizer, DISABLED_InternalPrintShadow) { for (size_t size = 1; size <= 513; size++) { char *ptr = new char[size]; - PrintShadow("m", (uintptr_t)ptr, size); + PrintShadow("m", (uptr)ptr, size); delete [] ptr; - PrintShadow("f", (uintptr_t)ptr, size); + PrintShadow("f", (uptr)ptr, size); } } -static uintptr_t pc_array[] = { +static uptr pc_array[] = { #if __WORDSIZE == 64 0x7effbf756068ULL, 0x7effbf75e5abULL, @@ -207,19 +208,20 @@ static uintptr_t pc_array[] = { }; void CompressStackTraceTest(size_t n_iter) { - uint32_t seed = my_rand(&global_seed); + u32 seed = my_rand(&global_seed); const size_t kNumPcs = ASAN_ARRAY_SIZE(pc_array); - uint32_t compressed[2 * kNumPcs]; + 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; 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(&seed) % stack0.size)); size_t compress_size = std::max((size_t)2, (size_t)my_rand(&seed) % (2 * kNumPcs)); size_t n_frames = __asan::AsanStackTrace::CompressStack(&stack0, compressed, compress_size); + Ident(n_frames); assert(n_frames <= stack0.size); __asan::AsanStackTrace::UncompressStack(&stack1, compressed, compress_size); assert(stack1.size == n_frames); @@ -235,7 +237,7 @@ TEST(AddressSanitizer, CompressStackTraceTest) { void CompressStackTraceBenchmark(size_t n_iter) { const size_t kNumPcs = ASAN_ARRAY_SIZE(pc_array); - uint32_t compressed[2 * kNumPcs]; + u32 compressed[2 * kNumPcs]; std::random_shuffle(pc_array, pc_array + kNumPcs); __asan::AsanStackTrace stack0; @@ -274,7 +276,8 @@ TEST(AddressSanitizer, QuarantineTest) { } void *ThreadedQuarantineTestWorker(void *unused) { - uint32_t seed = my_rand(&global_seed); + (void)unused; + u32 seed = my_rand(&global_seed); __asan::AsanStackTrace stack; stack.trace[0] = 0x890; stack.size = 1; @@ -301,6 +304,7 @@ TEST(AddressSanitizer, ThreadedQuarantineTest) { } void *ThreadedOneSizeMallocStress(void *unused) { + (void)unused; __asan::AsanStackTrace stack; stack.trace[0] = 0x890; stack.size = 1; @@ -327,3 +331,371 @@ TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) { pthread_join(t[i], 0); } } + +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), + "unknown-crash.*low shadow"); + EXPECT_DEATH(libc_memset((void*)(kShadowGapBeg + kPageSize), 0, 100), + "unknown-crash.*shadow gap"); + EXPECT_DEATH(libc_memset((void*)(kHighShadowBeg + kPageSize), 0, 100), + "unknown-crash.*high shadow"); +} + +TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) { + EXPECT_EQ(1U, __asan_get_estimated_allocated_size(0)); + 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])); + } +} + +static const char* kGetAllocatedSizeErrorMsg = + "attempting to call __asan_get_allocated_size()"; + +TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) { + const size_t kArraySize = 100; + char *array = Ident((char*)malloc(kArraySize)); + int *int_ptr = Ident(new int); + + // Allocated memory is owned by allocator. Allocated size should be + // equal to requested size. + EXPECT_EQ(true, __asan_get_ownership(array)); + EXPECT_EQ(kArraySize, __asan_get_allocated_size(array)); + EXPECT_EQ(true, __asan_get_ownership(int_ptr)); + EXPECT_EQ(sizeof(int), __asan_get_allocated_size(int_ptr)); + + // 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_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg); + EXPECT_EQ(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_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_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg); + + delete int_ptr; +} + +TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) { + size_t before_malloc, after_malloc, after_free; + char *array; + const size_t kMallocSize = 100; + before_malloc = __asan_get_current_allocated_bytes(); + + array = Ident((char*)malloc(kMallocSize)); + after_malloc = __asan_get_current_allocated_bytes(); + EXPECT_EQ(before_malloc + kMallocSize, after_malloc); + + free(array); + after_free = __asan_get_current_allocated_bytes(); + EXPECT_EQ(before_malloc, after_free); +} + +static void DoDoubleFree() { + int *x = Ident(new int); + delete Ident(x); + delete Ident(x); +} + +// 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. +static void RunGetHeapSizeTestAndDie() { + size_t old_heap_size, new_heap_size, heap_growth; + // We unlikely have have chunk of this size in free list. + static const size_t kLargeMallocSize = 1 << 29; // 512M + old_heap_size = __asan_get_heap_size(); + fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize); + free(Ident(malloc(kLargeMallocSize))); + new_heap_size = __asan_get_heap_size(); + heap_growth = new_heap_size - old_heap_size; + fprintf(stderr, "heap growth after first malloc: %zu\n", heap_growth); + ASSERT_GE(heap_growth, kLargeMallocSize); + ASSERT_LE(heap_growth, 2 * kLargeMallocSize); + + // Now large chunk should fall into free list, and can be + // allocated without increasing heap size. + old_heap_size = new_heap_size; + free(Ident(malloc(kLargeMallocSize))); + heap_growth = __asan_get_heap_size() - old_heap_size; + fprintf(stderr, "heap growth after second malloc: %zu\n", heap_growth); + ASSERT_LT(heap_growth, kLargeMallocSize); + + // Test passed. Now die with expected double-free. + DoDoubleFree(); +} + +TEST(AddressSanitizerInterface, GetHeapSizeTest) { + EXPECT_DEATH(RunGetHeapSizeTestAndDie(), "double-free"); +} + +// Note: use ASSERT_* instead of EXPECT_* here. +static void DoLargeMallocForGetFreeBytesTestAndDie() { + 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 + // into quarantine and will be available for future requests. + old_free_bytes = __asan_get_free_bytes(); + fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize); + fprintf(stderr, "free bytes before malloc: %zu\n", old_free_bytes); + free(Ident(malloc(kLargeMallocSize))); + 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); + // 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; + // 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; + } + EXPECT_DEATH(DoLargeMallocForGetFreeBytesTestAndDie(), "double-free"); +} + +static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<20, 357}; +static const size_t kManyThreadsIterations = 250; +static const size_t kManyThreadsNumThreads = (__WORDSIZE == 32) ? 40 : 200; + +void *ManyThreadsWithStatsWorker(void *arg) { + (void)arg; + for (size_t iter = 0; iter < kManyThreadsIterations; iter++) { + for (size_t size_index = 0; size_index < 4; size_index++) { + free(Ident(malloc(kManyThreadsMallocSizes[size_index]))); + } + } + return 0; +} + +TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) { + size_t before_test, after_test, i; + pthread_t threads[kManyThreadsNumThreads]; + before_test = __asan_get_current_allocated_bytes(); + for (i = 0; i < kManyThreadsNumThreads; i++) { + pthread_create(&threads[i], 0, + (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i); + } + for (i = 0; i < kManyThreadsNumThreads; i++) { + pthread_join(threads[i], 0); + } + after_test = __asan_get_current_allocated_bytes(); + // ASan stats also reflect memory usage of internal ASan RTL structs, + // so we can't check for equality here. + EXPECT_LT(after_test, before_test + (1UL<<20)); +} + +TEST(AddressSanitizerInterface, ExitCode) { + int original_exit_code = __asan_set_error_exit_code(7); + EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), ""); + EXPECT_EQ(7, __asan_set_error_exit_code(8)); + EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), ""); + EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code)); + EXPECT_EXIT(DoDoubleFree(), + ::testing::ExitedWithCode(original_exit_code), ""); +} + +static void MyDeathCallback() { + fprintf(stderr, "MyDeathCallback\n"); +} + +TEST(AddressSanitizerInterface, DeathCallbackTest) { + __asan_set_death_callback(MyDeathCallback); + EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback"); + __asan_set_death_callback(NULL); +} + +static const char* kUseAfterPoisonErrorMessage = "use-after-poison"; + +#define GOOD_ACCESS(ptr, offset) \ + EXPECT_FALSE(__asan::AddressIsPoisoned((uptr)(ptr + offset))) + +#define BAD_ACCESS(ptr, offset) \ + EXPECT_TRUE(__asan::AddressIsPoisoned((uptr)(ptr + offset))) + +TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) { + char *array = Ident((char*)malloc(120)); + // poison array[40..80) + __asan_poison_memory_region(array + 40, 40); + GOOD_ACCESS(array, 39); + GOOD_ACCESS(array, 80); + BAD_ACCESS(array, 40); + BAD_ACCESS(array, 60); + BAD_ACCESS(array, 79); + EXPECT_DEATH(__asan_report_error(0, 0, 0, (uptr)(array + 40), true, 1), + kUseAfterPoisonErrorMessage); + __asan_unpoison_memory_region(array + 40, 40); + // access previously poisoned memory. + GOOD_ACCESS(array, 40); + GOOD_ACCESS(array, 79); + free(array); +} + +TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) { + char *array = Ident((char*)malloc(120)); + // Poison [0..40) and [80..120) + __asan_poison_memory_region(array, 40); + __asan_poison_memory_region(array + 80, 40); + BAD_ACCESS(array, 20); + GOOD_ACCESS(array, 60); + BAD_ACCESS(array, 100); + // Poison whole array - [0..120) + __asan_poison_memory_region(array, 120); + BAD_ACCESS(array, 60); + // Unpoison [24..96) + __asan_unpoison_memory_region(array + 24, 72); + BAD_ACCESS(array, 23); + GOOD_ACCESS(array, 24); + GOOD_ACCESS(array, 60); + GOOD_ACCESS(array, 95); + BAD_ACCESS(array, 96); + free(array); +} + +TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) { + // Vector of capacity 20 + char *vec = Ident((char*)malloc(20)); + __asan_poison_memory_region(vec, 20); + for (size_t i = 0; i < 7; i++) { + // Simulate push_back. + __asan_unpoison_memory_region(vec + i, 1); + GOOD_ACCESS(vec, i); + BAD_ACCESS(vec, i + 1); + } + for (size_t i = 7; i > 0; i--) { + // Simulate pop_back. + __asan_poison_memory_region(vec + i - 1, 1); + BAD_ACCESS(vec, i - 1); + if (i > 1) GOOD_ACCESS(vec, i - 2); + } + free(vec); +} + +// Make sure that each aligned block of size "2^granularity" doesn't have +// "true" value before "false" value. +static void MakeShadowValid(bool *shadow, int length, int granularity) { + bool can_be_poisoned = true; + for (int i = length - 1; i >= 0; i--) { + if (!shadow[i]) + can_be_poisoned = false; + if (!can_be_poisoned) + shadow[i] = false; + if (i % (1 << granularity) == 0) { + can_be_poisoned = true; + } + } +} + +TEST(AddressSanitizerInterface, PoisoningStressTest) { + const size_t kSize = 24; + bool expected[kSize]; + char *arr = Ident((char*)malloc(kSize)); + for (size_t l1 = 0; l1 < kSize; l1++) { + for (size_t s1 = 1; l1 + s1 <= kSize; s1++) { + for (size_t l2 = 0; l2 < kSize; l2++) { + for (size_t s2 = 1; l2 + s2 <= kSize; s2++) { + // Poison [l1, l1+s1), [l2, l2+s2) and check result. + __asan_unpoison_memory_region(arr, kSize); + __asan_poison_memory_region(arr + l1, s1); + __asan_poison_memory_region(arr + l2, s2); + memset(expected, false, kSize); + memset(expected + l1, true, s1); + MakeShadowValid(expected, kSize, /*granularity*/ 3); + memset(expected + l2, true, s2); + MakeShadowValid(expected, kSize, /*granularity*/ 3); + for (size_t i = 0; i < kSize; i++) { + ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i)); + } + // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result. + __asan_poison_memory_region(arr, kSize); + __asan_unpoison_memory_region(arr + l1, s1); + __asan_unpoison_memory_region(arr + l2, s2); + memset(expected, true, kSize); + memset(expected + l1, false, s1); + MakeShadowValid(expected, kSize, /*granularity*/ 3); + memset(expected + l2, false, s2); + MakeShadowValid(expected, kSize, /*granularity*/ 3); + for (size_t i = 0; i < kSize; i++) { + ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i)); + } + } + } + } + } +} + +static const char *kInvalidPoisonMessage = "invalid-poison-memory-range"; +static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range"; + +TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) { + char *array = Ident((char*)malloc(120)); + __asan_unpoison_memory_region(array, 120); + // Try to unpoison not owned memory + EXPECT_DEATH(__asan_unpoison_memory_region(array, 121), + kInvalidUnpoisonMessage); + EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120), + kInvalidUnpoisonMessage); + + __asan_poison_memory_region(array, 120); + // Try to poison not owned memory. + EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage); + EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120), + kInvalidPoisonMessage); + free(array); +} + +static void ErrorReportCallbackOneToZ(const char *report) { + write(2, "ABCDEF", 6); +} + +TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) { + __asan_set_error_report_callback(ErrorReportCallbackOneToZ); + EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1), "ABCDEF"); + __asan_set_error_report_callback(NULL); +} + +TEST(AddressSanitizerInterface, GetOwnershipStressTest) { + std::vector<char *> pointers; + std::vector<size_t> sizes; + const size_t kNumMallocs = + (__WORDSIZE <= 32 || ASAN_LOW_MEMORY) ? 1 << 10 : 1 << 14; + for (size_t i = 0; i < kNumMallocs; i++) { + size_t size = i * 100 + 1; + pointers.push_back((char*)malloc(size)); + sizes.push_back(size); + } + for (size_t i = 0; i < 4000000; i++) { + EXPECT_FALSE(__asan_get_ownership(&pointers)); + EXPECT_FALSE(__asan_get_ownership((void*)0x1234)); + size_t idx = i % kNumMallocs; + EXPECT_TRUE(__asan_get_ownership(pointers[idx])); + EXPECT_EQ(sizes[idx], __asan_get_allocated_size(pointers[idx])); + } + for (size_t i = 0, n = pointers.size(); i < n; i++) + free(pointers[i]); +} diff --git a/lib/asan/tests/asan_racy_double_free_test.cc b/lib/asan/tests/asan_racy_double_free_test.cc new file mode 100644 index 000000000000..deeeb4f45e2f --- /dev/null +++ b/lib/asan/tests/asan_racy_double_free_test.cc @@ -0,0 +1,32 @@ +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> + +const int N = 1000; +void *x[N]; + +void *Thread1(void *unused) { + for (int i = 0; i < N; i++) { + fprintf(stderr, "%s %d\n", __FUNCTION__, i); + free(x[i]); + } + return NULL; +} + +void *Thread2(void *unused) { + for (int i = 0; i < N; i++) { + fprintf(stderr, "%s %d\n", __FUNCTION__, i); + free(x[i]); + } + return NULL; +} + +int main() { + for (int i = 0; i < N; i++) + x[i] = malloc(128); + pthread_t t[2]; + pthread_create(&t[0], 0, Thread1, 0); + pthread_create(&t[1], 0, Thread2, 0); + pthread_join(t[0], 0); + pthread_join(t[1], 0); +} diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 0ff72d3cf6d8..8e967e929899 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -1,4 +1,4 @@ -//===-- asan_test.cc ------------*- C++ -*-===// +//===-- asan_test.cc ----------------------===// // // The LLVM Compiler Infrastructure // @@ -20,7 +20,7 @@ #include <setjmp.h> #include <assert.h> -#if defined(__i386__) or defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #include <emmintrin.h> #endif @@ -29,13 +29,10 @@ #ifndef __APPLE__ #include <malloc.h> -#endif // __APPLE__ - -#ifdef __APPLE__ -static bool APPLE = true; #else -static bool APPLE = false; -#endif +#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_* +#include <CoreFoundation/CFString.h> +#endif // __APPLE__ #if ASAN_HAS_EXCEPTIONS # define ASAN_THROW(x) throw (x) @@ -61,99 +58,14 @@ static inline uint32_t my_rand(uint32_t* state) { static uint32_t global_seed = 0; -class ObjdumpOfMyself { - public: - explicit ObjdumpOfMyself(const string &binary) { - is_correct = true; - string objdump_name = APPLE ? "gobjdump" : "objdump"; - string prog = objdump_name + " -d " + binary; - // TODO(glider): popen() succeeds even if the file does not exist. - FILE *pipe = popen(prog.c_str(), "r"); - string objdump; - if (pipe) { - const int kBuffSize = 4096; - char buff[kBuffSize+1]; - int read_bytes; - while ((read_bytes = fread(buff, 1, kBuffSize, pipe)) > 0) { - buff[read_bytes] = 0; - objdump.append(buff); - } - pclose(pipe); - } else { - is_correct = false; - } - // cut the objdump into functions - string fn, next_fn; - size_t next_start; - for (size_t start = fn_start(objdump, 0, &fn); - start != string::npos; - start = next_start, fn = next_fn) { - next_start = fn_start(objdump, start, &next_fn); - // fprintf(stderr, "start: %d next_start = %d fn: %s\n", - // (int)start, (int)next_start, fn.c_str()); - // Mac OS adds the "_" prefix to function names. - if (fn.find(APPLE ? "_Disasm" : "Disasm") == string::npos) { - continue; - } - string fn_body = objdump.substr(start, next_start - start); - // fprintf(stderr, "%s:\n%s", fn.c_str(), fn_body.c_str()); - functions_[fn] = fn_body; - } - } - - string &GetFuncDisasm(const string &fn) { - return functions_[fn]; - } - - int CountInsnInFunc(const string &fn, const vector<string> &insns) { - // Mac OS adds the "_" prefix to function names. - string fn_ref = APPLE ? "_" + fn : fn; - const string &disasm = GetFuncDisasm(fn_ref); - if (disasm.empty()) return -1; - size_t counter = 0; - for (size_t i = 0; i < insns.size(); i++) { - size_t pos = 0; - while ((pos = disasm.find(insns[i], pos)) != string::npos) { - counter++; - pos++; - } - } - return counter; - } - - bool IsCorrect() { return is_correct; } - - private: - size_t fn_start(const string &objdump, size_t start_pos, string *fn) { - size_t pos = objdump.find(">:\n", start_pos); - if (pos == string::npos) - return string::npos; - size_t beg = pos; - while (beg > 0 && objdump[beg - 1] != '<') - beg--; - *fn = objdump.substr(beg, pos - beg); - return pos + 3; - } - - map<string, string> functions_; - bool is_correct; -}; - -static ObjdumpOfMyself *objdump_of_myself() { - static ObjdumpOfMyself *o = new ObjdumpOfMyself(progname); - return o; -} - const size_t kLargeMalloc = 1 << 24; -template<class T> -__attribute__((noinline)) -void asan_write(T *a) { +template<typename T> +NOINLINE void asan_write(T *a) { *a = 0; } -__attribute__((noinline)) -void asan_write_sized_aligned(uint8_t *p, size_t size) { +NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) { EXPECT_EQ(0, ((uintptr_t)p % size)); if (size == 1) asan_write((uint8_t*)p); else if (size == 2) asan_write((uint16_t*)p); @@ -161,45 +73,41 @@ void asan_write_sized_aligned(uint8_t *p, size_t size) { else if (size == 8) asan_write((uint64_t*)p); } -__attribute__((noinline)) void *malloc_fff(size_t size) { +NOINLINE void *malloc_fff(size_t size) { void *res = malloc/**/(size); break_optimization(0); return res;} -__attribute__((noinline)) void *malloc_eee(size_t size) { +NOINLINE void *malloc_eee(size_t size) { void *res = malloc_fff(size); break_optimization(0); return res;} -__attribute__((noinline)) void *malloc_ddd(size_t size) { +NOINLINE void *malloc_ddd(size_t size) { void *res = malloc_eee(size); break_optimization(0); return res;} -__attribute__((noinline)) void *malloc_ccc(size_t size) { +NOINLINE void *malloc_ccc(size_t size) { void *res = malloc_ddd(size); break_optimization(0); return res;} -__attribute__((noinline)) void *malloc_bbb(size_t size) { +NOINLINE void *malloc_bbb(size_t size) { void *res = malloc_ccc(size); break_optimization(0); return res;} -__attribute__((noinline)) void *malloc_aaa(size_t size) { +NOINLINE void *malloc_aaa(size_t size) { void *res = malloc_bbb(size); break_optimization(0); return res;} #ifndef __APPLE__ -__attribute__((noinline)) void *memalign_fff(size_t alignment, size_t size) { +NOINLINE void *memalign_fff(size_t alignment, size_t size) { void *res = memalign/**/(alignment, size); break_optimization(0); return res;} -__attribute__((noinline)) void *memalign_eee(size_t alignment, size_t size) { +NOINLINE void *memalign_eee(size_t alignment, size_t size) { void *res = memalign_fff(alignment, size); break_optimization(0); return res;} -__attribute__((noinline)) void *memalign_ddd(size_t alignment, size_t size) { +NOINLINE void *memalign_ddd(size_t alignment, size_t size) { void *res = memalign_eee(alignment, size); break_optimization(0); return res;} -__attribute__((noinline)) void *memalign_ccc(size_t alignment, size_t size) { +NOINLINE void *memalign_ccc(size_t alignment, size_t size) { void *res = memalign_ddd(alignment, size); break_optimization(0); return res;} -__attribute__((noinline)) void *memalign_bbb(size_t alignment, size_t size) { +NOINLINE void *memalign_bbb(size_t alignment, size_t size) { void *res = memalign_ccc(alignment, size); break_optimization(0); return res;} -__attribute__((noinline)) void *memalign_aaa(size_t alignment, size_t size) { +NOINLINE void *memalign_aaa(size_t alignment, size_t size) { void *res = memalign_bbb(alignment, size); break_optimization(0); return res;} #endif // __APPLE__ -__attribute__((noinline)) - void free_ccc(void *p) { free(p); break_optimization(0);} -__attribute__((noinline)) - void free_bbb(void *p) { free_ccc(p); break_optimization(0);} -__attribute__((noinline)) - void free_aaa(void *p) { free_bbb(p); break_optimization(0);} +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);} -template<class T> -__attribute__((noinline)) -void oob_test(int size, int off) { +template<typename T> +NOINLINE void oob_test(int size, int off) { 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); @@ -208,9 +116,8 @@ void oob_test(int size, int off) { } -template<class T> -__attribute__((noinline)) -void uaf_test(int size, int off) { +template<typename T> +NOINLINE void uaf_test(int size, int off) { char *p = (char *)malloc_aaa(size); free_aaa(p); for (int i = 1; i < 100; i++) @@ -255,13 +162,15 @@ TEST(AddressSanitizer, VariousMallocsTest) { *c = 0; delete c; -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(ANDROID) // fprintf(stderr, "posix_memalign\n"); int *pm; int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize); EXPECT_EQ(0, pm_res); free(pm); +#endif +#if !defined(__APPLE__) int *ma = (int*)memalign(kPageSize, kPageSize); EXPECT_EQ(0, (uintptr_t)ma % kPageSize); ma[123] = 0; @@ -295,48 +204,6 @@ TEST(AddressSanitizer, PvallocTest) { } #endif // __APPLE__ -void NoOpSignalHandler(int unused) { - fprintf(stderr, "NoOpSignalHandler (should not happen). Aborting\n"); - abort(); -} - -void NoOpSigaction(int, siginfo_t *siginfo, void *context) { - fprintf(stderr, "NoOpSigaction (should not happen). Aborting\n"); - abort(); -} - -TEST(AddressSanitizer, SignalTest) { - signal(SIGSEGV, NoOpSignalHandler); - signal(SIGILL, NoOpSignalHandler); - // If asan did not intercept sigaction NoOpSigaction will fire. - char *x = Ident((char*)malloc(5)); - EXPECT_DEATH(x[6]++, "is located 1 bytes to the right"); - free(Ident(x)); -} - -TEST(AddressSanitizer, SigactionTest) { - { - struct sigaction sigact; - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_sigaction = NoOpSigaction;; - sigact.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &sigact, 0); - } - - { - struct sigaction sigact; - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_sigaction = NoOpSigaction;; - sigact.sa_flags = SA_SIGINFO; - sigaction(SIGILL, &sigact, 0); - } - - // If asan did not intercept sigaction NoOpSigaction will fire. - char *x = Ident((char*)malloc(5)); - EXPECT_DEATH(x[6]++, "is located 1 bytes to the right"); - free(Ident(x)); -} - void *TSDWorker(void *test_key) { if (test_key) { pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface); @@ -367,7 +234,7 @@ TEST(AddressSanitizer, DISABLED_TSDTest) { pthread_key_delete(test_key); } -template<class T> +template<typename T> void OOBTest() { char expected_str[100]; for (int size = sizeof(T); size < 20; size += 5) { @@ -531,7 +398,7 @@ static void MallocStress(size_t n) { } TEST(AddressSanitizer, MallocStressTest) { - MallocStress(200000); + MallocStress((ASAN_LOW_MEMORY) ? 20000 : 200000); } static void TestLargeMalloc(size_t size) { @@ -546,24 +413,29 @@ TEST(AddressSanitizer, LargeMallocTest) { } } +#if ASAN_LOW_MEMORY != 1 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 Darwin. + // memory available to the process under AddressSanitizer on 32-bit Mac 10.6. + // 32-bit Mac 10.7 gives even less (< 1G). // (the libSystem malloc() allows allocating up to 2300 megabytes without // ASan). - size_t n_megs = __WORDSIZE == 32 ? 1200 : 4100; + size_t n_megs = __WORDSIZE == 32 ? 500 : 4100; #else size_t n_megs = __WORDSIZE == 32 ? 2600 : 4100; #endif TestLargeMalloc(n_megs << 20); } +#endif TEST(AddressSanitizer, ThreadedMallocStressTest) { const int kNumThreads = 4; + const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000; pthread_t t[kNumThreads]; for (int i = 0; i < kNumThreads; i++) { - pthread_create(&t[i], 0, (void* (*)(void *x))MallocStress, (void*)100000); + pthread_create(&t[i], 0, (void* (*)(void *x))MallocStress, + (void*)kNumIterations); } for (int i = 0; i < kNumThreads; i++) { pthread_join(t[i], 0); @@ -601,6 +473,25 @@ TEST(AddressSanitizer, ReallocTest) { } } +#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(0, 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 + void WrongFree() { int *x = (int*)malloc(100 * sizeof(int)); // Use the allocated memory, otherwise Clang will optimize it out. @@ -623,12 +514,15 @@ void DoubleFree() { } TEST(AddressSanitizer, DoubleFreeTest) { - EXPECT_DEATH(DoubleFree(), "ERROR: AddressSanitizer attempting double-free"); + 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"); } template<int kSize> -__attribute__((noinline)) -void SizedStackTest() { +NOINLINE void SizedStackTest() { char a[kSize]; char *A = Ident((char*)&a); for (size_t i = 0; i < kSize; i++) @@ -669,8 +563,7 @@ TEST(AddressSanitizer, ManyStackObjectsTest) { EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ"); } -__attribute__((noinline)) -static void Frame0(int frame, char *a, char *b, char *c) { +NOINLINE static void Frame0(int frame, char *a, char *b, char *c) { char d[4] = {0}; char *D = Ident(d); switch (frame) { @@ -680,15 +573,15 @@ static void Frame0(int frame, char *a, char *b, char *c) { case 0: D[5]++; break; } } -__attribute__((noinline)) static void Frame1(int frame, char *a, char *b) { +NOINLINE static void Frame1(int frame, char *a, char *b) { char c[4] = {0}; Frame0(frame, a, b, c); break_optimization(0); } -__attribute__((noinline)) static void Frame2(int frame, char *a) { +NOINLINE static void Frame2(int frame, char *a) { char b[4] = {0}; Frame1(frame, a, b); break_optimization(0); } -__attribute__((noinline)) static void Frame3(int frame) { +NOINLINE static void Frame3(int frame) { char a[4] = {0}; Frame2(frame, a); break_optimization(0); } @@ -706,8 +599,7 @@ TEST(AddressSanitizer, GuiltyStackFrame3Test) { EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3"); } -__attribute__((noinline)) -void LongJmpFunc1(jmp_buf buf) { +NOINLINE void LongJmpFunc1(jmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -718,8 +610,7 @@ void LongJmpFunc1(jmp_buf buf) { longjmp(buf, 1); } -__attribute__((noinline)) -void UnderscopeLongJmpFunc1(jmp_buf buf) { +NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -730,8 +621,7 @@ void UnderscopeLongJmpFunc1(jmp_buf buf) { _longjmp(buf, 1); } -__attribute__((noinline)) -void SigLongJmpFunc1(sigjmp_buf buf) { +NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -743,8 +633,7 @@ void SigLongJmpFunc1(sigjmp_buf buf) { } -__attribute__((noinline)) -void TouchStackFunc() { +NOINLINE void TouchStackFunc() { int a[100]; // long array will intersect with redzones from LongJmpFunc1. int *A = Ident(a); for (int i = 0; i < 100; i++) @@ -780,8 +669,7 @@ TEST(AddressSanitizer, SigLongJmpTest) { } #ifdef __EXCEPTIONS -__attribute__((noinline)) -void ThrowFunc() { +NOINLINE void ThrowFunc() { // create three red zones for these two stack objects. int a; int b; @@ -828,7 +716,7 @@ TEST(AddressSanitizer, ThreadStackReuseTest) { pthread_join(t, 0); } -#if defined(__i386__) or defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) TEST(AddressSanitizer, Store128Test) { char *a = Ident((char*)malloc(Ident(12))); char *p = a; @@ -860,7 +748,7 @@ static string LeftOOBErrorMessage(int oob_distance) { return string(expected_str); } -template<class T> +template<typename T> void MemSetOOBTestTemplate(size_t length) { if (length == 0) return; size_t size = Ident(sizeof(T) * length); @@ -917,7 +805,7 @@ TEST(AddressSanitizer, MemSetOOBTest) { } // Same test for memcpy and memmove functions -template <class T, class M> +template <typename T, class M> void MemTransferOOBTestTemplate(size_t length) { if (length == 0) return; size_t size = Ident(sizeof(T) * length); @@ -1051,11 +939,14 @@ TEST(AddressSanitizer, StrLenOOBTest) { free(heap_string); } -static inline char* MallocAndMemsetString(size_t size) { +static inline char* MallocAndMemsetString(size_t size, char ch) { char *s = Ident((char*)malloc(size)); - memset(s, 'z', size); + memset(s, ch, size); return s; } +static inline char* MallocAndMemsetString(size_t size) { + return MallocAndMemsetString(size, 'z'); +} #ifndef __APPLE__ TEST(AddressSanitizer, StrNLenOOBTest) { @@ -1355,6 +1246,47 @@ TEST(AddressSanitizer, StrCatOOBTest) { EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0)); // length of "to" is just enough. strcat(to, from + 1); + + free(to); + free(from); +} + +TEST(AddressSanitizer, StrNCatOOBTest) { + size_t to_size = Ident(100); + char *to = MallocAndMemsetString(to_size); + to[0] = '\0'; + size_t from_size = Ident(20); + char *from = MallocAndMemsetString(from_size); + // Normal strncat calls. + strncat(to, from, 0); + strncat(to, from, from_size); + from[from_size - 1] = '\0'; + strncat(to, from, 2 * from_size); + // Catenating empty string is not an error. + strncat(to - 1, from, 0); + strncat(to, from + from_size - 1, 10); + // One of arguments points to not allocated memory. + EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBErrorMessage(1)); + EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBErrorMessage(1)); + EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBErrorMessage(0)); + EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBErrorMessage(0)); + + memset(from, 'z', from_size); + memset(to, 'z', to_size); + to[0] = '\0'; + // "from" is too short. + EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBErrorMessage(0)); + // "to" is not zero-terminated. + EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBErrorMessage(0)); + // "to" is too short to fit "from". + to[0] = 'z'; + to[to_size - from_size + 1] = '\0'; + EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBErrorMessage(0)); + // "to" is just enough. + strncat(to, from, from_size - 2); + + free(to); + free(from); } static string OverlapErrorMessage(const string &func) { @@ -1365,14 +1297,22 @@ TEST(AddressSanitizer, StrArgsOverlapTest) { size_t size = Ident(100); char *str = Ident((char*)malloc(size)); +// Do not check memcpy() on OS X 10.7 and later, where it actually aliases +// memmove(). +#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \ + (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) // Check "memcpy". Use Ident() to avoid inlining. memset(str, 'z', size); Ident(memcpy)(str + 1, str + 11, 10); Ident(memcpy)(str, str, 0); EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy")); EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy")); - EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1), - OverlapErrorMessage("memcpy")); +#endif + + // We do not treat memcpy with to==from as a bug. + // See http://llvm.org/bugs/show_bug.cgi?id=11763. + // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1), + // OverlapErrorMessage("memcpy")); // Check "strcpy". memset(str, 'z', size); @@ -1403,9 +1343,117 @@ TEST(AddressSanitizer, StrArgsOverlapTest) { EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat")); EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat")); + // Check "strncat". + memset(str, 'z', size); + str[10] = '\0'; + strncat(str, str + 10, 10); // from is empty + strncat(str, str + 11, 10); + str[10] = '\0'; + str[20] = '\0'; + strncat(str + 5, str, 5); + str[10] = '\0'; + EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat")); + EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat")); + free(str); } +void CallAtoi(const char *nptr) { + Ident(atoi(nptr)); +} +void CallAtol(const char *nptr) { + Ident(atol(nptr)); +} +void CallAtoll(const char *nptr) { + Ident(atoll(nptr)); +} +typedef void(*PointerToCallAtoi)(const char*); + +void RunAtoiOOBTest(PointerToCallAtoi Atoi) { + char *array = MallocAndMemsetString(10, '1'); + // Invalid pointer to the string. + EXPECT_DEATH(Atoi(array + 11), RightOOBErrorMessage(1)); + EXPECT_DEATH(Atoi(array - 1), LeftOOBErrorMessage(1)); + // Die if a buffer doesn't have terminating NULL. + EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0)); + // Make last symbol a terminating NULL or other non-digit. + array[9] = '\0'; + Atoi(array); + array[9] = 'a'; + Atoi(array); + Atoi(array + 9); + // Sometimes we need to detect overflow if no digits are found. + memset(array, ' ', 10); + EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0)); + array[9] = '-'; + EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0)); + EXPECT_DEATH(Atoi(array + 9), RightOOBErrorMessage(0)); + array[8] = '-'; + Atoi(array); + delete array; +} + +TEST(AddressSanitizer, AtoiAndFriendsOOBTest) { + RunAtoiOOBTest(&CallAtoi); + RunAtoiOOBTest(&CallAtol); + RunAtoiOOBTest(&CallAtoll); +} + +void CallStrtol(const char *nptr, char **endptr, int base) { + Ident(strtol(nptr, endptr, base)); +} +void CallStrtoll(const char *nptr, char **endptr, int base) { + Ident(strtoll(nptr, endptr, base)); +} +typedef void(*PointerToCallStrtol)(const char*, char**, int); + +void RunStrtolOOBTest(PointerToCallStrtol Strtol) { + char *array = MallocAndMemsetString(3); + char *endptr = NULL; + array[0] = '1'; + array[1] = '2'; + array[2] = '3'; + // Invalid pointer to the string. + EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBErrorMessage(0)); + EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBErrorMessage(1)); + // Buffer overflow if there is no terminating null (depends on base). + Strtol(array, &endptr, 3); + EXPECT_EQ(array + 2, endptr); + EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0)); + array[2] = 'z'; + Strtol(array, &endptr, 35); + EXPECT_EQ(array + 2, endptr); + EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBErrorMessage(0)); + // Add terminating zero to get rid of overflow. + array[2] = '\0'; + Strtol(array, NULL, 36); + // Don't check for overflow if base is invalid. + Strtol(array - 1, NULL, -1); + Strtol(array + 3, NULL, 1); + // Sometimes we need to detect overflow if no digits are found. + array[0] = array[1] = array[2] = ' '; + EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0)); + array[2] = '+'; + EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0)); + array[2] = '-'; + EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0)); + array[1] = '+'; + Strtol(array, NULL, 0); + array[1] = array[2] = 'z'; + Strtol(array, &endptr, 0); + EXPECT_EQ(array, endptr); + Strtol(array + 2, NULL, 0); + EXPECT_EQ(array, endptr); + delete array; +} + +TEST(AddressSanitizer, StrtollOOBTest) { + RunStrtolOOBTest(&CallStrtoll); +} +TEST(AddressSanitizer, StrtolOOBTest) { + RunStrtolOOBTest(&CallStrtol); +} + // At the moment we instrument memcpy/memove/memset calls at compile time so we // can't handle OOB error if these functions are called by pointer, see disabled // MemIntrinsicCallByPointerTest below @@ -1446,8 +1494,7 @@ TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) { // TODO(samsonov): Add a test with malloc(0) // TODO(samsonov): Add tests for str* and mem* functions. -__attribute__((noinline)) -static int LargeFunction(bool do_bad_access) { +NOINLINE static int LargeFunction(bool do_bad_access) { int *x = new int[100]; x[0]++; x[1]++; @@ -1544,8 +1591,7 @@ TEST(AddressSanitizer, ShadowGapTest) { #endif // ASAN_NEEDS_SEGV extern "C" { -__attribute__((noinline)) -static void UseThenFreeThenUse() { +NOINLINE static void UseThenFreeThenUse() { char *x = Ident((char*)malloc(8)); *x = 1; free_aaa(x); @@ -1561,76 +1607,6 @@ TEST(AddressSanitizer, StrDupTest) { free(strdup(Ident("123"))); } -TEST(AddressSanitizer, ObjdumpTest) { - ObjdumpOfMyself *o = objdump_of_myself(); - EXPECT_TRUE(o->IsCorrect()); -} - -extern "C" { -__attribute__((noinline)) -static void DisasmSimple() { - Ident(0); -} - -__attribute__((noinline)) -static void DisasmParamWrite(int *a) { - *a = 1; -} - -__attribute__((noinline)) -static void DisasmParamInc(int *a) { - (*a)++; -} - -__attribute__((noinline)) -static void DisasmParamReadIfWrite(int *a) { - if (*a) - *a = 1; -} - -__attribute__((noinline)) -static int DisasmParamIfReadWrite(int *a, int cond) { - int res = 0; - if (cond) - res = *a; - *a = 0; - return res; -} - -static int GLOBAL; - -__attribute__((noinline)) -static void DisasmWriteGlob() { - GLOBAL = 1; -} -} // extern "C" - -TEST(AddressSanitizer, DisasmTest) { - int a; - DisasmSimple(); - DisasmParamWrite(&a); - DisasmParamInc(&a); - Ident(DisasmWriteGlob)(); - DisasmParamReadIfWrite(&a); - - a = 7; - EXPECT_EQ(7, DisasmParamIfReadWrite(&a, Ident(1))); - EXPECT_EQ(0, a); - - ObjdumpOfMyself *o = objdump_of_myself(); - vector<string> insns; - insns.push_back("ud2"); - insns.push_back("__asan_report_"); - EXPECT_EQ(0, o->CountInsnInFunc("DisasmSimple", insns)); - EXPECT_EQ(1, o->CountInsnInFunc("DisasmParamWrite", insns)); - EXPECT_EQ(1, o->CountInsnInFunc("DisasmParamInc", insns)); - EXPECT_EQ(0, o->CountInsnInFunc("DisasmWriteGlob", insns)); - - // TODO(kcc): implement these (needs just one __asan_report). - EXPECT_EQ(2, o->CountInsnInFunc("DisasmParamReadIfWrite", insns)); - EXPECT_EQ(2, o->CountInsnInFunc("DisasmParamIfReadWrite", insns)); -} - // Currently we create and poison redzone at right of global variables. char glob5[5]; static char static110[110]; @@ -1718,8 +1694,7 @@ TEST(AddressSanitizer, LocalReferenceReturnTest) { #endif template <int kSize> -__attribute__((noinline)) -static void FuncWithStack() { +NOINLINE static void FuncWithStack() { char x[kSize]; Ident(x)[0] = 0; Ident(x)[kSize-1] = 0; @@ -1758,9 +1733,21 @@ TEST(AddressSanitizer, ThreadedStressStackReuseTest) { } } +static void *PthreadExit(void *a) { + pthread_exit(0); + return 0; +} + +TEST(AddressSanitizer, PthreadExitTest) { + pthread_t t; + for (int i = 0; i < 1000; i++) { + pthread_create(&t, 0, PthreadExit, 0); + pthread_join(t, 0); + } +} + #ifdef __EXCEPTIONS -__attribute__((noinline)) -static void StackReuseAndException() { +NOINLINE static void StackReuseAndException() { int large_stack[1000]; Ident(large_stack); ASAN_THROW(1); @@ -1784,6 +1771,28 @@ TEST(AddressSanitizer, MlockTest) { EXPECT_EQ(0, munlock((void*)0x987, 0x654)); } +struct LargeStruct { + int foo[100]; +}; + +// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763. +// Struct copy should not cause asan warning even if lhs == rhs. +TEST(AddressSanitizer, LargeStructCopyTest) { + LargeStruct a; + *Ident(&a) = *Ident(&a); +} + +__attribute__((no_address_safety_analysis)) +static void NoAddressSafety() { + char *foo = new char[10]; + Ident(foo)[10] = 0; + delete [] foo; +} + +TEST(AddressSanitizer, AttributeNoAddressSafetyTest) { + Ident(NoAddressSafety)(); +} + // ------------------ demo tests; run each one-by-one ------------- // e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests TEST(AddressSanitizer, DISABLED_DemoThreadedTest) { @@ -1873,23 +1882,75 @@ TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) { } } +// http://code.google.com/p/address-sanitizer/issues/detail?id=66 +TEST(AddressSanitizer, BufferOverflowAfterManyFrees) { + for (int i = 0; i < 1000000; i++) { + delete [] (Ident(new char [8644])); + } + char *x = new char[8192]; + EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer heap-buffer-overflow"); + delete [] Ident(x); +} + #ifdef __APPLE__ #include "asan_mac_test.h" -// TODO(glider): figure out whether we still need these tests. Is it correct -// to intercept CFAllocator? -TEST(AddressSanitizerMac, DISABLED_CFAllocatorDefaultDoubleFree) { +TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) { EXPECT_DEATH( - CFAllocatorDefaultDoubleFree(), + CFAllocatorDefaultDoubleFree(NULL), "attempting double-free"); } +void CFAllocator_DoubleFreeOnPthread() { + pthread_t child; + pthread_create(&child, NULL, CFAllocatorDefaultDoubleFree, NULL); + pthread_join(child, NULL); // Shouldn't be reached. +} + +TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) { + EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free"); +} + +namespace { + +void *GLOB; + +void *CFAllocatorAllocateToGlob(void *unused) { + GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0); + return NULL; +} + +void *CFAllocatorDeallocateFromGlob(void *unused) { + char *p = (char*)GLOB; + p[100] = 'A'; // ASan should report an error here. + CFAllocatorDeallocate(NULL, GLOB); + return NULL; +} + +void CFAllocator_PassMemoryToAnotherThread() { + pthread_t th1, th2; + pthread_create(&th1, NULL, CFAllocatorAllocateToGlob, NULL); + pthread_join(th1, NULL); + pthread_create(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL); + pthread_join(th2, NULL); +} + +TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) { + EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(), + "heap-buffer-overflow"); +} + +} // namespace + +// TODO(glider): figure out whether we still need these tests. Is it correct +// to intercept the non-default CFAllocators? TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) { EXPECT_DEATH( CFAllocatorSystemDefaultDoubleFree(), "attempting double-free"); } -TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocDoubleFree) { +// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan. +TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) { EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free"); } @@ -2012,8 +2073,37 @@ TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) { pthread_join(th, NULL); pthread_key_delete(test_key); } + +// Test that CFStringCreateCopy does not copy constant strings. +TEST(AddressSanitizerMac, CFStringCreateCopy) { + CFStringRef str = CFSTR("Hello world!\n"); + CFStringRef str2 = CFStringCreateCopy(0, str); + EXPECT_EQ(str, str2); +} + +TEST(AddressSanitizerMac, NSObjectOOB) { + // Make sure that our allocators are used for NSObjects. + EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow"); +} + +// Make sure that correct pointer is passed to free() when deallocating a +// NSURL object. +// See http://code.google.com/p/address-sanitizer/issues/detail?id=70. +TEST(AddressSanitizerMac, NSURLDeallocation) { + TestNSURLDeallocation(); +} #endif // __APPLE__ +// Test that instrumentation of stack allocations takes into account +// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double). +// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details. +TEST(AddressSanitizer, LongDoubleNegativeTest) { + long double a, b; + static long double c; + memcpy(Ident(&a), Ident(&b), sizeof(long double)); + memcpy(Ident(&c), Ident(&b), sizeof(long double)); +}; + int main(int argc, char **argv) { progname = argv[0]; testing::GTEST_FLAG(death_test_style) = "threadsafe"; diff --git a/lib/asan/tests/asan_test_config.h b/lib/asan/tests/asan_test_config.h index de4ae95bd244..6cf0e6958484 100644 --- a/lib/asan/tests/asan_test_config.h +++ b/lib/asan/tests/asan_test_config.h @@ -39,6 +39,10 @@ using std::map; # error "please define ASAN_NEEDS_SEGV" #endif +#ifndef ASAN_LOW_MEMORY +#define ASAN_LOW_MEMORY 0 +#endif + #define ASAN_PCRE_DOTALL "" #endif // ASAN_TEST_CONFIG_H diff --git a/lib/asan/tests/asan_test_utils.h b/lib/asan/tests/asan_test_utils.h index a4809812dcf0..fb509cc43e30 100644 --- a/lib/asan/tests/asan_test_utils.h +++ b/lib/asan/tests/asan_test_utils.h @@ -14,13 +14,39 @@ #ifndef ASAN_TEST_UTILS_H #define ASAN_TEST_UTILS_H +#if defined(_WIN32) +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +# define NOINLINE __declspec(noinline) +#else // defined(_WIN32) +# define NOINLINE __attribute__((noinline)) +#endif // defined(_WIN32) + +#if !defined(__has_feature) +#define __has_feature(x) 0 +#endif + +#ifndef __WORDSIZE +#if __LP64__ || defined(_WIN64) +#define __WORDSIZE 64 +#else +#define __WORDSIZE 32 +#endif +#endif + // Make the compiler think that something is going on there. extern "C" void break_optimization(void *); // This function returns its parameter but in such a way that compiler // can not prove it. template<class T> -__attribute__((noinline)) +NOINLINE static T Ident(T t) { T ret = t; break_optimization(&ret); diff --git a/lib/asan/tests/dlclose-test-so.cc b/lib/asan/tests/dlclose-test-so.cc deleted file mode 100644 index fae2f813abb7..000000000000 --- a/lib/asan/tests/dlclose-test-so.cc +++ /dev/null @@ -1,33 +0,0 @@ -//===-- asan_rtl.cc ------------*- C++ -*-===// -// -// 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. -// -// Regression test for -// http://code.google.com/p/address-sanitizer/issues/detail?id=19 -//===----------------------------------------------------------------------===// -#include <stdio.h> - -static int pad1; -static int static_var; -static int pad2; - -extern "C" -int *get_address_of_static_var() { - return &static_var; -} - -__attribute__((constructor)) -void at_dlopen() { - printf("%s: I am being dlopened\n", __FILE__); -} -__attribute__((destructor)) -void at_dlclose() { - printf("%s: I am being dlclosed\n", __FILE__); -} diff --git a/lib/asan/tests/dlclose-test.cc b/lib/asan/tests/dlclose-test.cc deleted file mode 100644 index 307886667b15..000000000000 --- a/lib/asan/tests/dlclose-test.cc +++ /dev/null @@ -1,73 +0,0 @@ -//===-- asan_rtl.cc ------------*- C++ -*-===// -// -// 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. -// -// Regression test for -// http://code.google.com/p/address-sanitizer/issues/detail?id=19 -// Bug description: -// 1. application dlopens foo.so -// 2. asan registers all globals from foo.so -// 3. application dlcloses foo.so -// 4. application mmaps some memory to the location where foo.so was before -// 5. application starts using this mmaped memory, but asan still thinks there -// are globals. -// 6. BOOM -//===----------------------------------------------------------------------===// -#include <assert.h> -#include <dlfcn.h> -#include <stdio.h> -#include <string.h> -#include <sys/mman.h> - -#include <string> - -using std::string; - -static const int kPageSize = 4096; - -typedef int *(fun_t)(); - -int main(int argc, char *argv[]) { - string path = string(argv[0]) + "-so.so"; - printf("opening %s ... \n", path.c_str()); - void *lib = dlopen(path.c_str(), RTLD_NOW); - if (!lib) { - printf("error in dlopen(): %s\n", dlerror()); - return 1; - } - fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var"); - if (!get) { - printf("failed dlsym\n"); - return 1; - } - int *addr = get(); - assert(((size_t)addr % 32) == 0); // should be 32-byte aligned. - printf("addr: %p\n", addr); - addr[0] = 1; // make sure we can write there. - - // Now dlclose the shared library. - printf("attempting to dlclose\n"); - if (dlclose(lib)) { - printf("failed to dlclose\n"); - return 1; - } - // Now, the page where 'addr' is unmapped. Map it. - size_t page_beg = ((size_t)addr) & ~(kPageSize - 1); - void *res = mmap((void*)(page_beg), kPageSize, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0); - if (res == (char*)-1L) { - printf("failed to mmap\n"); - return 1; - } - addr[1] = 2; // BOOM (if the bug is not fixed). - printf("PASS\n"); - return 0; -} diff --git a/lib/asan/tests/dlclose-test.tmpl b/lib/asan/tests/dlclose-test.tmpl deleted file mode 100644 index 7ef22e9a431a..000000000000 --- a/lib/asan/tests/dlclose-test.tmpl +++ /dev/null @@ -1 +0,0 @@ -PASS diff --git a/lib/asan/tests/global-overflow.cc b/lib/asan/tests/global-overflow.cc deleted file mode 100644 index b85c4d2a18bf..000000000000 --- a/lib/asan/tests/global-overflow.cc +++ /dev/null @@ -1,12 +0,0 @@ -#include <string.h> -int main(int argc, char **argv) { - static char XXX[10]; - static char YYY[10]; - static char ZZZ[10]; - memset(XXX, 0, 10); - memset(YYY, 0, 10); - memset(ZZZ, 0, 10); - int res = YYY[argc * 10]; // BOOOM - res += XXX[argc] + ZZZ[argc]; - return res; -} diff --git a/lib/asan/tests/global-overflow.tmpl b/lib/asan/tests/global-overflow.tmpl deleted file mode 100644 index c5d54428143b..000000000000 --- a/lib/asan/tests/global-overflow.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -READ of size 1 at 0x.* thread T0 - #0 0x.* in main .*global-overflow.cc:9 -0x.* is located 0 bytes to the right of global variable .*YYY.* of size 10 diff --git a/lib/asan/tests/heap-overflow.cc b/lib/asan/tests/heap-overflow.cc deleted file mode 100644 index 475d1637385a..000000000000 --- a/lib/asan/tests/heap-overflow.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include <stdlib.h> -#include <string.h> -int main(int argc, char **argv) { - char *x = (char*)malloc(10 * sizeof(char)); - memset(x, 0, 10); - int res = x[argc * 10]; // BOOOM - free(x); - return res; -} diff --git a/lib/asan/tests/heap-overflow.tmpl b/lib/asan/tests/heap-overflow.tmpl deleted file mode 100644 index e2ab65f17d82..000000000000 --- a/lib/asan/tests/heap-overflow.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -READ of size 1 at 0x.* thread T0 - #0 0x.* in main .*heap-overflow.cc:6 -0x.* is located 0 bytes to the right of 10-byte region -allocated by thread T0 here: - #0 0x.* in malloc - #1 0x.* in main .*heap-overflow.cc:[45] diff --git a/lib/asan/tests/heap-overflow.tmpl.Darwin b/lib/asan/tests/heap-overflow.tmpl.Darwin deleted file mode 100644 index e4611d067abe..000000000000 --- a/lib/asan/tests/heap-overflow.tmpl.Darwin +++ /dev/null @@ -1,8 +0,0 @@ -READ of size 1 at 0x.* thread T0 - #0 0x.* in main .*heap-overflow.cc:6 -0x.* is located 0 bytes to the right of 10-byte region -allocated by thread T0 here: - #0 0x.* in .*mz_malloc.* _asan_rtl_ - #1 0x.* in malloc_zone_malloc.* - #2 0x.* in malloc.* - #3 0x.* in main heap-overflow.cc:4 diff --git a/lib/asan/tests/large_func_test.cc b/lib/asan/tests/large_func_test.cc deleted file mode 100644 index 70bc36f40b87..000000000000 --- a/lib/asan/tests/large_func_test.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include <stdlib.h> -__attribute__((noinline)) -static void LargeFunction(int *x, int zero) { - x[0]++; - x[1]++; - x[2]++; - x[3]++; - x[4]++; - x[5]++; - x[6]++; - x[7]++; - x[8]++; - x[9]++; - - x[zero + 111]++; // we should report this exact line - - x[10]++; - x[11]++; - x[12]++; - x[13]++; - x[14]++; - x[15]++; - x[16]++; - x[17]++; - x[18]++; - x[19]++; -} - -int main(int argc, char **argv) { - int *x = new int[100]; - LargeFunction(x, argc - 1); - delete x; -} diff --git a/lib/asan/tests/large_func_test.tmpl b/lib/asan/tests/large_func_test.tmpl deleted file mode 100644 index 45a13d0bc5bd..000000000000 --- a/lib/asan/tests/large_func_test.tmpl +++ /dev/null @@ -1,8 +0,0 @@ -.*ERROR: AddressSanitizer heap-buffer-overflow on address 0x.* at pc 0x.* bp 0x.* sp 0x.* -READ of size 4 at 0x.* thread T0 - #0 0x.* in LargeFunction .*large_func_test.cc:15 - #1 0x.* in main .*large_func_test.cc:3[012] -0x.* is located 44 bytes to the right of 400-byte region -allocated by thread T0 here: - #0 0x.* in operator new.* - #1 0x.* in main .*large_func_test.cc:30 diff --git a/lib/asan/tests/match_output.py b/lib/asan/tests/match_output.py deleted file mode 100755 index 31095f3f62f2..000000000000 --- a/lib/asan/tests/match_output.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python - -import re -import sys - -def matchFile(f, f_re): - for line_re in f_re: - line_re = line_re.rstrip() - if not line_re: - continue - if line_re[0] == '#': - continue - match = False - for line in f: - line = line.rstrip() - # print line - if re.search(line_re, line): - match = True - #print 'match: %s =~ %s' % (line, line_re) - break - if not match: - print 'no match for: %s' % (line_re) - return False - return True - -if len(sys.argv) != 2: - print >>sys.stderr, 'Usage: %s <template file>' - sys.exit(1) - -f = sys.stdin -f_re = open(sys.argv[1]) - -if not matchFile(f, f_re): - print >>sys.stderr, 'File does not match the template' - sys.exit(1) diff --git a/lib/asan/tests/null_deref.cc b/lib/asan/tests/null_deref.cc deleted file mode 100644 index f7ba4dd5f63f..000000000000 --- a/lib/asan/tests/null_deref.cc +++ /dev/null @@ -1,7 +0,0 @@ -__attribute__((noinline)) -static void NullDeref(int *ptr) { - ptr[10]++; -} -int main() { - NullDeref((int*)0); -} diff --git a/lib/asan/tests/null_deref.tmpl b/lib/asan/tests/null_deref.tmpl deleted file mode 100644 index d27cccc06bc8..000000000000 --- a/lib/asan/tests/null_deref.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -.*ERROR: AddressSanitizer crashed on unknown address 0x0*00028 .*pc 0x.* -AddressSanitizer can not provide additional info. ABORTING - #0 0x.* in NullDeref.*null_deref.cc:3 - #1 0x.* in main.*null_deref.cc:[67] diff --git a/lib/asan/tests/shared-lib-test-so.cc b/lib/asan/tests/shared-lib-test-so.cc deleted file mode 100644 index c3b3bc22aed2..000000000000 --- a/lib/asan/tests/shared-lib-test-so.cc +++ /dev/null @@ -1,21 +0,0 @@ -//===-- asan_rtl.cc ------------*- C++ -*-===// -// -// 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> - -int pad[10]; -int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -extern "C" -void inc(int index) { - GLOB[index]++; -} diff --git a/lib/asan/tests/shared-lib-test.cc b/lib/asan/tests/shared-lib-test.cc deleted file mode 100644 index e492572c7280..000000000000 --- a/lib/asan/tests/shared-lib-test.cc +++ /dev/null @@ -1,37 +0,0 @@ -//===-- asan_rtl.cc ------------*- C++ -*-===// -// -// 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 <dlfcn.h> -#include <stdio.h> -#include <string.h> - -#include <string> - -using std::string; - -typedef void (fun_t)(int x); - -int main(int argc, char *argv[]) { - string path = string(argv[0]) + "-so.so"; - printf("opening %s ... \n", path.c_str()); - void *lib = dlopen(path.c_str(), RTLD_NOW); - if (!lib) { - printf("error in dlopen(): %s\n", dlerror()); - return 1; - } - fun_t *inc = (fun_t*)dlsym(lib, "inc"); - if (!inc) return 1; - printf("ok\n"); - inc(1); - inc(-1); - return 0; -} diff --git a/lib/asan/tests/shared-lib-test.tmpl b/lib/asan/tests/shared-lib-test.tmpl deleted file mode 100644 index 564e3eb5cb8c..000000000000 --- a/lib/asan/tests/shared-lib-test.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -#.*ERROR: AddressSanitizer global-buffer-overflow on address 0x.* at pc 0x.* bp 0x.* sp 0x.* -#READ of size 4 at 0x.* thread T0 -# #0 0x.* in inc .*shared-lib-test-so.cc:11 -# #1 0x.* in main .*shared-lib-test.cc:33 -# #2 0x.* in __libc_start_main.* -#0x.* is located 4 bytes to the left of global variable 'GLOB' (.*) of size 40 -#0x.* is located 52 bytes to the right of global variable 'pad' (.*) of size 40 diff --git a/lib/asan/tests/stack-overflow.cc b/lib/asan/tests/stack-overflow.cc deleted file mode 100644 index dd86aa32514a..000000000000 --- a/lib/asan/tests/stack-overflow.cc +++ /dev/null @@ -1,7 +0,0 @@ -#include <string.h> -int main(int argc, char **argv) { - char x[10]; - memset(x, 0, 10); - int res = x[argc * 10]; // BOOOM - return res; -} diff --git a/lib/asan/tests/stack-overflow.tmpl b/lib/asan/tests/stack-overflow.tmpl deleted file mode 100644 index 6aa717a82b28..000000000000 --- a/lib/asan/tests/stack-overflow.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -READ of size 1 at 0x.* thread T0 - #0 0x.* in main .*stack-overflow.cc:5 -Address 0x.* is .* frame <main> diff --git a/lib/asan/tests/stack-use-after-return.cc b/lib/asan/tests/stack-use-after-return.cc deleted file mode 100644 index 9098edf0adb8..000000000000 --- a/lib/asan/tests/stack-use-after-return.cc +++ /dev/null @@ -1,24 +0,0 @@ -#include <stdio.h> - -__attribute__((noinline)) -char *Ident(char *x) { - fprintf(stderr, "1: %p\n", x); - return x; -} - -__attribute__((noinline)) -char *Func1() { - char local; - return Ident(&local); -} - -__attribute__((noinline)) -void Func2(char *x) { - fprintf(stderr, "2: %p\n", x); - *x = 1; -} - -int main(int argc, char **argv) { - Func2(Func1()); - return 0; -} diff --git a/lib/asan/tests/stack-use-after-return.disabled b/lib/asan/tests/stack-use-after-return.disabled deleted file mode 100644 index 02729bc43a74..000000000000 --- a/lib/asan/tests/stack-use-after-return.disabled +++ /dev/null @@ -1,3 +0,0 @@ -WRITE of size 1 .* thread T0 -#0.*Func2.*stack-use-after-return.cc:18 -is located in frame <.*Func1.*> of T0's stack diff --git a/lib/asan/tests/strncpy-overflow.cc b/lib/asan/tests/strncpy-overflow.cc deleted file mode 100644 index 044f6494bfa1..000000000000 --- a/lib/asan/tests/strncpy-overflow.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include <string.h> -#include <stdlib.h> -int main(int argc, char **argv) { - char *hello = (char*)malloc(6); - strcpy(hello, "hello"); - char *short_buffer = (char*)malloc(9); - strncpy(short_buffer, hello, 10); // BOOM - return short_buffer[8]; -} diff --git a/lib/asan/tests/strncpy-overflow.tmpl b/lib/asan/tests/strncpy-overflow.tmpl deleted file mode 100644 index 3780aa81921f..000000000000 --- a/lib/asan/tests/strncpy-overflow.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -WRITE of size 1 at 0x.* thread T0 - #0 0x.* in strncpy - #1 0x.* in main .*strncpy-overflow.cc:[78] -0x.* is located 0 bytes to the right of 9-byte region -allocated by thread T0 here: - #0 0x.* in malloc - #1 0x.* in main .*strncpy-overflow.cc:6 diff --git a/lib/asan/tests/test_output.sh b/lib/asan/tests/test_output.sh deleted file mode 100755 index c54b2364b2c3..000000000000 --- a/lib/asan/tests/test_output.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -set -e # fail on any error - -OS=`uname` -CXX=$1 -CC=$2 -CXXFLAGS="-mno-omit-leaf-frame-pointer -fno-omit-frame-pointer" -SYMBOLIZER=../scripts/asan_symbolize.py - -C_TEST=use-after-free -echo "Sanity checking a test in pure C" -$CC -g -faddress-sanitizer -O2 $C_TEST.c -./a.out 2>&1 | grep "heap-use-after-free" > /dev/null -rm ./a.out - -echo "Sanity checking a test in pure C with -pie" -$CC -g -faddress-sanitizer -O2 $C_TEST.c -pie -./a.out 2>&1 | grep "heap-use-after-free" > /dev/null -rm ./a.out - -for t in *.tmpl; do - for b in 32 64; do - for O in 0 1 2 3; do - c=`basename $t .tmpl` - c_so=$c-so - exe=$c.$b.O$O - so=$c.$b.O$O-so.so - echo testing $exe - $CXX $CXXFLAGS -g -m$b -faddress-sanitizer -O$O $c.cc -o $exe - [ -e "$c_so.cc" ] && $CXX $CXXFLAGS -g -m$b -faddress-sanitizer -O$O $c_so.cc -fPIC -shared -o $so - # If there's an OS-specific template, use it. - # Please minimize the use of OS-specific templates. - if [ -e "$t.$OS" ] - then - actual_t="$t.$OS" - else - actual_t="$t" - fi - ./$exe 2>&1 | $SYMBOLIZER 2> /dev/null | c++filt | ./match_output.py $actual_t - rm ./$exe - [ -e "$so" ] && rm ./$so - done - done -done - -exit 0 diff --git a/lib/asan/tests/use-after-free.c b/lib/asan/tests/use-after-free.c deleted file mode 100644 index 60626bff778a..000000000000 --- a/lib/asan/tests/use-after-free.c +++ /dev/null @@ -1,6 +0,0 @@ -#include <stdlib.h> -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; -} diff --git a/lib/asan/tests/use-after-free.cc b/lib/asan/tests/use-after-free.cc deleted file mode 100644 index 60626bff778a..000000000000 --- a/lib/asan/tests/use-after-free.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include <stdlib.h> -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; -} diff --git a/lib/asan/tests/use-after-free.tmpl b/lib/asan/tests/use-after-free.tmpl deleted file mode 100644 index c4b5c74d9887..000000000000 --- a/lib/asan/tests/use-after-free.tmpl +++ /dev/null @@ -1,10 +0,0 @@ -.*ERROR: AddressSanitizer heap-use-after-free on address 0x.* at pc 0x.* bp 0x.* sp 0x.* -READ of size 1 at 0x.* thread T0 - #0 0x.* in main .*use-after-free.cc:5 -0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.* -freed by thread T0 here: - #0 0x.* in free - #1 0x.* in main .*use-after-free.cc:[45] -previously allocated by thread T0 here: - #0 0x.* in malloc - #1 0x.* in main .*use-after-free.cc:3 |