aboutsummaryrefslogtreecommitdiff
path: root/lib/asan/tests
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2012-07-30 10:58:13 +0000
committerAndrew Turner <andrew@FreeBSD.org>2012-07-30 10:58:13 +0000
commit37dfff057418e02f8e5322da12684dd927e3d881 (patch)
tree40cc44a3d02ed86de24f2117a55680e4f0eb01a0 /lib/asan/tests
parent864a7b98b54e1f984c248f3be83dfcc082a382ea (diff)
downloadsrc-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')
-rw-r--r--lib/asan/tests/CMakeLists.txt118
-rw-r--r--lib/asan/tests/asan_benchmarks_test.cc2
-rw-r--r--lib/asan/tests/asan_break_optimization.cc3
-rw-r--r--lib/asan/tests/asan_globals_test.cc2
-rw-r--r--lib/asan/tests/asan_interface_test.cc334
-rw-r--r--lib/asan/tests/asan_mac_test.h5
-rw-r--r--lib/asan/tests/asan_mac_test.mm46
-rw-r--r--lib/asan/tests/asan_noinst_test.cc410
-rw-r--r--lib/asan/tests/asan_racy_double_free_test.cc32
-rw-r--r--lib/asan/tests/asan_test.cc642
-rw-r--r--lib/asan/tests/asan_test_config.h4
-rw-r--r--lib/asan/tests/asan_test_utils.h28
-rw-r--r--lib/asan/tests/dlclose-test-so.cc33
-rw-r--r--lib/asan/tests/dlclose-test.cc73
-rw-r--r--lib/asan/tests/dlclose-test.tmpl1
-rw-r--r--lib/asan/tests/global-overflow.cc12
-rw-r--r--lib/asan/tests/global-overflow.tmpl3
-rw-r--r--lib/asan/tests/heap-overflow.cc9
-rw-r--r--lib/asan/tests/heap-overflow.tmpl6
-rw-r--r--lib/asan/tests/heap-overflow.tmpl.Darwin8
-rw-r--r--lib/asan/tests/large_func_test.cc33
-rw-r--r--lib/asan/tests/large_func_test.tmpl8
-rwxr-xr-xlib/asan/tests/match_output.py35
-rw-r--r--lib/asan/tests/null_deref.cc7
-rw-r--r--lib/asan/tests/null_deref.tmpl4
-rw-r--r--lib/asan/tests/shared-lib-test-so.cc21
-rw-r--r--lib/asan/tests/shared-lib-test.cc37
-rw-r--r--lib/asan/tests/shared-lib-test.tmpl7
-rw-r--r--lib/asan/tests/stack-overflow.cc7
-rw-r--r--lib/asan/tests/stack-overflow.tmpl3
-rw-r--r--lib/asan/tests/stack-use-after-return.cc24
-rw-r--r--lib/asan/tests/stack-use-after-return.disabled3
-rw-r--r--lib/asan/tests/strncpy-overflow.cc9
-rw-r--r--lib/asan/tests/strncpy-overflow.tmpl7
-rwxr-xr-xlib/asan/tests/test_output.sh47
-rw-r--r--lib/asan/tests/use-after-free.c6
-rw-r--r--lib/asan/tests/use-after-free.cc6
-rw-r--r--lib/asan/tests/use-after-free.tmpl10
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