summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2013-09-16 15:50:53 +0000
committerAlexey Samsonov <samsonov@google.com>2013-09-16 15:50:53 +0000
commit05fa3808f6ac96023cdf583a1a1b7220e5b451b8 (patch)
tree61a33375c8c0db94fbf2fcf72a641ab1a48250cf
parent22e21b044c9337a2fa921f268b7d221c693ad78b (diff)
downloadcompiler-rt-05fa3808f6ac96023cdf583a1a1b7220e5b451b8.tar.gz
compiler-rt-05fa3808f6ac96023cdf583a1a1b7220e5b451b8.tar.bz2
compiler-rt-05fa3808f6ac96023cdf583a1a1b7220e5b451b8.tar.xz
[ASan] Split ASan unit tests into two different binaries:
(1) instrumented, i.e. compiled and linked with -fsanitize=address (2) not instrumented, compiled w/o -fsanitize=address and linked with ASan runtime statically. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@190788 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--cmake/Modules/AddCompilerRT.cmake12
-rw-r--r--lib/asan/CMakeLists.txt42
-rw-r--r--lib/asan/tests/CMakeLists.txt166
-rw-r--r--lib/asan/tests/asan_interface_test.cc426
-rw-r--r--lib/asan/tests/asan_noinst_test.cc502
-rw-r--r--lib/asan/tests/asan_test.cc29
6 files changed, 643 insertions, 534 deletions
diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake
index 1ece3eb9..021920c9 100644
--- a/cmake/Modules/AddCompilerRT.cmake
+++ b/cmake/Modules/AddCompilerRT.cmake
@@ -6,13 +6,16 @@ include(CompilerRTUtils)
# with name "<name>.<arch>" if architecture can be targeted.
# add_compiler_rt_object_library(<name> <arch>
# SOURCES <source files>
-# CFLAGS <compile flags>)
+# CFLAGS <compile flags>
+# DEFS <compile definitions>)
macro(add_compiler_rt_object_library name arch)
if(CAN_TARGET_${arch})
- parse_arguments(LIB "SOURCES;CFLAGS" "" ${ARGN})
+ parse_arguments(LIB "SOURCES;CFLAGS;DEFS" "" ${ARGN})
add_library(${name}.${arch} OBJECT ${LIB_SOURCES})
set_target_compile_flags(${name}.${arch}
${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
+ set_property(TARGET ${name}.${arch} APPEND PROPERTY
+ COMPILE_DEFINITIONS ${LIB_DEFS})
else()
message(FATAL_ERROR "Archtecture ${arch} can't be targeted")
endif()
@@ -23,12 +26,15 @@ endmacro()
# add_compiler_rt_osx_object_library(<name> ARCH <architectures>
# SOURCES <source files>
# CFLAGS <compile flags>)
+# DEFS <compile definitions>)
macro(add_compiler_rt_osx_object_library name)
- parse_arguments(LIB "ARCH;SOURCES;CFLAGS" "" ${ARGN})
+ parse_arguments(LIB "ARCH;SOURCES;CFLAGS;DEFS" "" ${ARGN})
set(libname "${name}.osx")
add_library(${libname} OBJECT ${LIB_SOURCES})
set_target_compile_flags(${libname} ${LIB_CFLAGS})
set_target_properties(${libname} PROPERTIES OSX_ARCHITECTURES "${LIB_ARCH}")
+ set_property(TARGET ${libname} APPEND PROPERTY
+ COMPILE_DEFINITIONS ${LIB_DEFS})
endmacro()
# Adds static runtime for a given architecture and puts it in the proper
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index b590ffc3..17552b3a 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -21,9 +21,6 @@ set(ASAN_SOURCES
asan_thread.cc
asan_win.cc)
-set(ASAN_DYLIB_SOURCES
- ${ASAN_SOURCES})
-
include_directories(..)
if (NOT MSVC)
@@ -58,12 +55,32 @@ endif()
filter_available_targets(ASAN_SUPPORTED_ARCH
x86_64 i386 powerpc64)
+# Compile ASan sources into an object library.
+if(APPLE)
+ add_compiler_rt_osx_object_library(RTAsan
+ ARCH ${ASAN_SUPPORTED_ARCH}
+ SOURCES ${ASAN_SOURCES}
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+elseif(ANDROID)
+ add_library(RTAsan.arm.android OBJECT ${ASAN_SOURCES})
+ set_target_compile_flags(RTAsan.arm.android ${ASAN_CFLAGS})
+ set_property(TARGET RTAsan.arm.android APPEND PROPERTY
+ COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
+else()
+ foreach(arch ${ASAN_SUPPORTED_ARCH})
+ add_compiler_rt_object_library(RTAsan ${arch}
+ SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ endforeach()
+endif()
+
+# Build ASan runtimes shipped with Clang.
set(ASAN_RUNTIME_LIBRARIES)
if(APPLE)
- # Build universal binary on APPLE.
add_compiler_rt_osx_dynamic_runtime(clang_rt.asan_osx_dynamic
ARCH ${ASAN_SUPPORTED_ARCH}
- SOURCES ${ASAN_DYLIB_SOURCES}
+ SOURCES $<TARGET_OBJECTS:RTAsan.osx>
$<TARGET_OBJECTS:RTInterception.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
$<TARGET_OBJECTS:RTLSanCommon.osx>
@@ -76,10 +93,9 @@ if(APPLE)
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_osx_dynamic)
elseif(ANDROID)
add_library(clang_rt.asan-arm-android SHARED
- ${ASAN_SOURCES}
+ $<TARGET_OBJECTS:RTAsan.arm.android>
$<TARGET_OBJECTS:RTInterception.arm.android>
- $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>
- )
+ $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>)
set_target_compile_flags(clang_rt.asan-arm-android
${ASAN_CFLAGS})
set_property(TARGET clang_rt.asan-arm-android APPEND PROPERTY
@@ -87,20 +103,20 @@ elseif(ANDROID)
target_link_libraries(clang_rt.asan-arm-android dl)
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-arm-android)
else()
- # Otherwise, build separate libraries for each target.
-
+ # Build separate libraries for each target.
foreach(arch ${ASAN_SUPPORTED_ARCH})
- set(ASAN_SOURCE_LIBS
+ set(ASAN_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan.${arch}>
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
if (NOT MSVC)
# We can't build Leak Sanitizer on Windows yet.
- list(APPEND ASAN_SOURCE_LIBS $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+ list(APPEND ASAN_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
endif()
add_compiler_rt_static_runtime(clang_rt.asan-${arch} ${arch}
- SOURCES ${ASAN_SOURCES} ${ASAN_SOURCE_LIBS}
+ SOURCES ${ASAN_RUNTIME_OBJECTS}
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch})
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index ffe16147..8600fc0b 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -39,10 +39,6 @@ set(ASAN_UNITTEST_COMMON_CFLAGS
-Werror=sign-compare
-g
-O2)
-
-if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -fPIE)
-endif()
if(SUPPORTS_NO_VARIADIC_MACROS_FLAG)
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -Wno-variadic-macros)
endif()
@@ -62,24 +58,7 @@ else()
-DASAN_NEEDS_SEGV=1)
endif()
-set(ASAN_LINK_FLAGS)
-if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
- list(APPEND ASAN_LINK_FLAGS -pie)
-endif()
-# On Android, we link with ASan runtime manually. On other platforms we depend
-# on Clang driver behavior, passing -fsanitize=address flag.
-if(NOT ANDROID)
- list(APPEND ASAN_LINK_FLAGS -fsanitize=address)
-endif()
-# Unit tests on Mac depend on Foundation.
-if(APPLE)
- list(APPEND ASAN_LINK_FLAGS -framework Foundation)
-endif()
-# Unit tests require libstdc++.
-list(APPEND ASAN_LINK_FLAGS -lstdc++)
-
set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore")
-
set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
${ASAN_UNITTEST_COMMON_CFLAGS}
-fsanitize=address
@@ -95,11 +74,30 @@ if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
-fsanitize-address-zero-base-shadow)
endif()
+# Unit tests require libstdc++.
+set(ASAN_UNITTEST_COMMON_LINKFLAGS -lstdc++)
+# Unit tests on Mac depend on Foundation.
+if(APPLE)
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -framework Foundation)
+endif()
+
+set(ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS
+ ${ASAN_UNITTEST_COMMON_LINKFLAGS})
+# On Android, we link with ASan runtime manually. On other platforms we depend
+# on Clang driver behavior, passing -fsanitize=address flag.
+if(NOT ANDROID)
+ list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address)
+endif()
+
+set(ASAN_UNITTEST_NOINST_LINKFLAGS
+ ${ASAN_UNITTEST_COMMON_LINKFLAGS}
+ -lpthread -ldl)
+
# Compile source for the given architecture, using compiler
# options in ${ARGN}, and add it to the object list.
macro(asan_compile obj_list source arch)
get_filename_component(basename ${source} NAME)
- set(output_obj "${basename}.${arch}.o")
+ set(output_obj "${obj_list}.${basename}.${arch}.o")
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
clang_compile(${output_obj} ${source}
CFLAGS ${ARGN} ${TARGET_CFLAGS}
@@ -110,13 +108,19 @@ macro(asan_compile obj_list source arch)
endmacro()
# Link ASan unit test for a given architecture from a set
-# of objects in ${ARGN}.
+# of objects in with given linker flags.
macro(add_asan_test test_suite test_name arch)
+ parse_arguments(TEST "OBJECTS;LINKFLAGS" "WITH_TEST_RUNTIME" ${ARGN})
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
+ set(TEST_DEPS ${ASAN_RUNTIME_LIBRARIES} ${TEST_OBJECTS})
+ if(TEST_WITH_TEST_RUNTIME)
+ list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME})
+ list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a)
+ endif()
add_compiler_rt_test(${test_suite} ${test_name}
- OBJECTS ${ARGN}
- DEPS ${ASAN_RUNTIME_LIBRARIES} ${ARGN}
- LINK_FLAGS ${ASAN_LINK_FLAGS}
+ OBJECTS ${TEST_OBJECTS}
+ DEPS ${TEST_DEPS}
+ LINK_FLAGS ${TEST_LINKFLAGS}
${TARGET_LINK_FLAGS})
endmacro()
@@ -127,64 +131,90 @@ set_target_properties(AsanUnitTests PROPERTIES FOLDER "ASan unit tests")
add_custom_target(AsanBenchmarks)
set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Asan benchmarks")
-if (NOT APPLE AND NOT ANDROID)
-# Do not build asan_fake_stack_test.cc on OS X and Android, since it requires
-# exposing additional functions from the runtime.
-# See also https://code.google.com/p/address-sanitizer/issues/detail?id=222
-set(ASAN_NOINST_TEST_SOURCES
- asan_fake_stack_test.cc
- asan_noinst_test.cc
- asan_test_main.cc)
-else()
set(ASAN_NOINST_TEST_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
asan_noinst_test.cc
asan_test_main.cc)
+if(NOT APPLE AND NOT ANDROID)
+ # Do not build asan_fake_stack_test.cc on OS X and Android, since it requires
+ # exposing additional functions from the runtime.
+ # See also https://code.google.com/p/address-sanitizer/issues/detail?id=222
+ list(APPEND ASAN_NOINST_TEST_SOURCES asan_fake_stack_test.cc)
endif()
set(ASAN_INST_TEST_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
asan_globals_test.cc
+ asan_interface_test.cc
asan_test.cc
asan_oob_test.cc
asan_mem_test.cc
- asan_str_test.cc)
+ asan_str_test.cc
+ asan_test_main.cc)
+if(APPLE)
+ list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc)
+endif()
+
+set(ASAN_BENCHMARKS_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
+ asan_benchmarks_test.cc)
# Adds ASan unit tests and benchmarks for architecture.
macro(add_asan_tests_for_arch arch)
- # Build gtest instrumented with ASan.
- set(ASAN_INST_GTEST)
- asan_compile(ASAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
# Instrumented tests.
set(ASAN_INST_TEST_OBJECTS)
foreach(src ${ASAN_INST_TEST_SOURCES})
asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch}
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
endforeach()
- # Add Mac-specific tests.
if (APPLE)
- asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test.cc ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ # Add Mac-specific helper.
asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch}
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC)
endif()
+ add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch}
+ OBJECTS ${ASAN_INST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+
+ # Add static ASan runtime that will be linked with uninstrumented tests.
+ set(ASAN_TEST_RUNTIME RTAsanTest.${arch})
+ if(APPLE)
+ set(ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan.osx>
+ $<TARGET_OBJECTS:RTInterception.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommon.osx>
+ $<TARGET_OBJECTS:RTLSanCommon.osx>)
+ else()
+ set(ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+ endif()
+ add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
+ set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Uninstrumented tests.
set(ASAN_NOINST_TEST_OBJECTS)
foreach(src ${ASAN_NOINST_TEST_SOURCES})
asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch}
${ASAN_UNITTEST_COMMON_CFLAGS})
endforeach()
- # Link everything together.
- add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch}
- ${ASAN_NOINST_TEST_OBJECTS}
- ${ASAN_INST_TEST_OBJECTS} ${ASAN_INST_GTEST})
+ add_asan_test(AsanUnitTests "Asan-${arch}-Noinst-Test" ${arch}
+ OBJECTS ${ASAN_NOINST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_NOINST_LINKFLAGS}
+ WITH_TEST_RUNTIME)
- # Instrumented benchmarks.
+ # Benchmarks.
set(ASAN_BENCHMARKS_OBJECTS)
- asan_compile(ASAN_BENCHMARKS_OBJECTS asan_benchmarks_test.cc ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
- # Link benchmarks.
+ foreach(src ${ASAN_BENCHMARKS_SOURCES})
+ asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ endforeach()
add_asan_test(AsanBenchmarks "Asan-${arch}-Benchmark" ${arch}
- ${ASAN_BENCHMARKS_OBJECTS} ${ASAN_INST_GTEST})
+ OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
endmacro()
if(COMPILER_RT_CAN_EXECUTE_TESTS)
@@ -196,20 +226,28 @@ endif()
if(ANDROID)
# We assume that unit tests on Android are built in a build
# tree with fresh Clang as a host compiler.
- add_library(asan_noinst_test OBJECT ${ASAN_NOINST_TEST_SOURCES})
- set_target_compile_flags(asan_noinst_test ${ASAN_UNITTEST_COMMON_CFLAGS})
- add_library(asan_inst_test OBJECT
- ${ASAN_INST_TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE})
- set_target_compile_flags(asan_inst_test ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+
+ # Test w/o ASan instrumentation. Link it with ASan statically.
+ add_executable(AsanNoinstTest
+ $<TARGET_OBJECTS:RTAsan.arm.android>
+ $<TARGET_OBJECTS:RTInterception.arm.android>
+ $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>
+ ${COMPILER_RT_GTEST_SOURCE}
+ ${ASAN_NOINST_TEST_SOURCES})
+ set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS})
+ set_target_link_flags(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LINKFLAGS})
+
+ # Test with ASan instrumentation. Link with ASan dynamic runtime.
add_executable(AsanTest
- $<TARGET_OBJECTS:asan_noinst_test>
- $<TARGET_OBJECTS:asan_inst_test>
- )
+ ${COMPILER_RT_GTEST_SOURCE}
+ ${ASAN_INST_TEST_SOURCES})
+ set_target_compile_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ set_target_link_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ target_link_libraries(AsanTest clang_rt.asan-arm-android)
+
# Setup correct output directory and link flags.
- set_target_properties(AsanTest PROPERTIES
+ set_target_properties(AsanNoinstTest AsanTest PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
- set_target_link_flags(AsanTest ${ASAN_LINK_FLAGS})
- target_link_libraries(AsanTest clang_rt.asan-arm-android)
# Add unit test to test suite.
- add_dependencies(AsanUnitTests AsanTest)
+ add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
endif()
diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc
new file mode 100644
index 00000000..f3667901
--- /dev/null
+++ b/lib/asan/tests/asan_interface_test.cc
@@ -0,0 +1,426 @@
+//===-- asan_interface_test.cc --------------------------------------------===//
+//
+// 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 "asan_test_utils.h"
+#include "sanitizer/asan_interface.h"
+
+TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
+ EXPECT_EQ(0U, __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_FALSE(__asan_get_ownership(wild_addr));
+ EXPECT_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg);
+ EXPECT_FALSE(__asan_get_ownership(array + kArraySize / 2));
+ EXPECT_DEATH(__asan_get_allocated_size(array + kArraySize / 2),
+ kGetAllocatedSizeErrorMsg);
+
+ // NULL is not owned, but is a valid argument for __asan_get_allocated_size().
+ EXPECT_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_FALSE(__asan_get_ownership(array));
+ EXPECT_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg);
+ delete int_ptr;
+
+ void *zero_alloc = Ident(malloc(0));
+ if (zero_alloc != 0) {
+ // If malloc(0) is not null, this pointer is owned and should have valid
+ // allocated size.
+ EXPECT_TRUE(__asan_get_ownership(zero_alloc));
+ // Allocated size is 0 or 1 depending on the allocator used.
+ EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U);
+ }
+ free(zero_alloc);
+}
+
+TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
+ 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);
+}
+
+TEST(AddressSanitizerInterface, GetHeapSizeTest) {
+ // asan_allocator2 does not keep huge chunks in free list, but unmaps them.
+ // The chunk should be greater than the quarantine size,
+ // otherwise it will be stuck in quarantine instead of being unmaped.
+ static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
+ free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
+ size_t old_heap_size = __asan_get_heap_size();
+ for (int i = 0; i < 3; i++) {
+ // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
+ free(Ident(malloc(kLargeMallocSize)));
+ EXPECT_EQ(old_heap_size, __asan_get_heap_size());
+ }
+}
+
+static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
+static const size_t kManyThreadsIterations = 250;
+static const size_t kManyThreadsNumThreads =
+ (SANITIZER_WORDSIZE == 32) ? 40 : 200;
+
+static 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])));
+ }
+ }
+ // Just one large allocation.
+ free(Ident(malloc(1 << 20)));
+ 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));
+}
+
+static void DoDoubleFree() {
+ int *x = Ident(new int);
+ delete Ident(x);
+ delete Ident(x);
+}
+
+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_address_is_poisoned(ptr + offset))
+
+#define BAD_ACCESS(ptr, offset) \
+ EXPECT_TRUE(__asan_address_is_poisoned(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);
+ char value;
+ EXPECT_DEATH(value = Ident(array[40]), 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));
+ }
+ }
+ }
+ }
+ }
+ free(arr);
+}
+
+TEST(AddressSanitizerInterface, GlobalRedzones) {
+ GOOD_ACCESS(glob1, 1 - 1);
+ GOOD_ACCESS(glob2, 2 - 1);
+ GOOD_ACCESS(glob3, 3 - 1);
+ GOOD_ACCESS(glob4, 4 - 1);
+ GOOD_ACCESS(glob5, 5 - 1);
+ GOOD_ACCESS(glob6, 6 - 1);
+ GOOD_ACCESS(glob7, 7 - 1);
+ GOOD_ACCESS(glob8, 8 - 1);
+ GOOD_ACCESS(glob9, 9 - 1);
+ GOOD_ACCESS(glob10, 10 - 1);
+ GOOD_ACCESS(glob11, 11 - 1);
+ GOOD_ACCESS(glob12, 12 - 1);
+ GOOD_ACCESS(glob13, 13 - 1);
+ GOOD_ACCESS(glob14, 14 - 1);
+ GOOD_ACCESS(glob15, 15 - 1);
+ GOOD_ACCESS(glob16, 16 - 1);
+ GOOD_ACCESS(glob17, 17 - 1);
+ GOOD_ACCESS(glob1000, 1000 - 1);
+ GOOD_ACCESS(glob10000, 10000 - 1);
+ GOOD_ACCESS(glob100000, 100000 - 1);
+
+ BAD_ACCESS(glob1, 1);
+ BAD_ACCESS(glob2, 2);
+ BAD_ACCESS(glob3, 3);
+ BAD_ACCESS(glob4, 4);
+ BAD_ACCESS(glob5, 5);
+ BAD_ACCESS(glob6, 6);
+ BAD_ACCESS(glob7, 7);
+ BAD_ACCESS(glob8, 8);
+ BAD_ACCESS(glob9, 9);
+ BAD_ACCESS(glob10, 10);
+ BAD_ACCESS(glob11, 11);
+ BAD_ACCESS(glob12, 12);
+ BAD_ACCESS(glob13, 13);
+ BAD_ACCESS(glob14, 14);
+ BAD_ACCESS(glob15, 15);
+ BAD_ACCESS(glob16, 16);
+ BAD_ACCESS(glob17, 17);
+ BAD_ACCESS(glob1000, 1000);
+ BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
+ BAD_ACCESS(glob10000, 10000);
+ BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
+ BAD_ACCESS(glob100000, 100000);
+ BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
+}
+
+TEST(AddressSanitizerInterface, PoisonedRegion) {
+ size_t rz = 16;
+ for (size_t size = 1; size <= 64; size++) {
+ char *p = new char[size];
+ for (size_t beg = 0; beg < size + rz; beg++) {
+ for (size_t end = beg; end < size + rz; end++) {
+ void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg);
+ if (beg == end) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg < size && end <= size) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg >= size) {
+ EXPECT_EQ(p + beg, first_poisoned);
+ } else {
+ EXPECT_GT(end, size);
+ EXPECT_EQ(p + size, first_poisoned);
+ }
+ }
+ }
+ delete [] p;
+ }
+}
+
+// This is a performance benchmark for manual runs.
+// asan's memset interceptor calls mem_is_zero for the entire shadow region.
+// the profile should look like this:
+// 89.10% [.] __memset_sse2
+// 10.50% [.] __sanitizer::mem_is_zero
+// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
+// than memset itself.
+TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
+ size_t size = 1 << 20;
+ char *x = new char[size];
+ for (int i = 0; i < 100000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+
+// Same here, but we run memset with small sizes.
+TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
+ size_t size = 32;
+ char *x = new char[size];
+ for (int i = 0; i < 100000000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+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) {
+ int report_len = strlen(report);
+ ASSERT_EQ(6, write(2, "ABCDEF", 6));
+ ASSERT_EQ(report_len, write(2, report, report_len));
+ ASSERT_EQ(6, write(2, "ABCDEF", 6));
+ _exit(1);
+}
+
+TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
+ __asan_set_error_report_callback(ErrorReportCallbackOneToZ);
+ EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1),
+ ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
+ __asan_set_error_report_callback(NULL);
+}
+
+TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
+ std::vector<char *> pointers;
+ std::vector<size_t> sizes;
+ const size_t kNumMallocs = 1 << 9;
+ 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_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc
index 8168b3ec..b170314a 100644
--- a/lib/asan/tests/asan_noinst_test.cc
+++ b/lib/asan/tests/asan_noinst_test.cc
@@ -25,6 +25,46 @@
#include <vector>
#include <limits>
+#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
+// Manually set correct ASan mapping scale and offset, as they won't be
+// exported from instrumented sources (there are none).
+# define FLEXIBLE_SHADOW_SCALE kDefaultShadowScale
+# if SANITIZER_ANDROID
+# define FLEXIBLE_SHADOW_OFFSET (0)
+# else
+# if SANITIZER_WORDSIZE == 32
+# if defined(__mips__)
+# define FLEXIBLE_SHADOW_OFFSET kMIPS32_ShadowOffset32
+# else
+# define FLEXIBLE_SHADOW_OFFSET kDefaultShadowOffset32
+# endif
+# else
+# if defined(__powerpc64__)
+# define FLEXIBLE_SHADOW_OFFSET kPPC64_ShadowOffset64
+# elif SANITIZER_MAC
+# define FLEXIBLE_SHADOW_OFFSET kDefaultShadowOffset64
+# else
+# define FLEXIBLE_SHADOW_OFFSET kDefaultShort64bitShadowOffset
+# endif
+# endif
+# endif
+SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale = FLEXIBLE_SHADOW_SCALE;
+SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset =
+ FLEXIBLE_SHADOW_OFFSET;
+#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
+
+extern "C" {
+// Set specific ASan options for uninstrumented unittest.
+const char* __asan_default_options() {
+ return "allow_reexec=0";
+}
+} // extern "C"
+
+// Make sure __asan_init is called before any test case is run.
+struct AsanInitCaller {
+ AsanInitCaller() { __asan_init(); }
+};
+static AsanInitCaller asan_init_caller;
TEST(AddressSanitizer, InternalSimpleDeathTest) {
EXPECT_DEATH(exit(1), "");
@@ -333,459 +373,13 @@ TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
}
}
-TEST(AddressSanitizer, MemsetWildAddressTest) {
+TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
using __asan::kHighMemEnd;
- 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 + 200), 0, 100),
- (kLowShadowEnd == 0) ? "unknown-crash.*shadow gap"
- : "unknown-crash.*low shadow");
- EXPECT_DEATH(libc_memset((void*)(kShadowGapBeg + 200), 0, 100),
- "unknown-crash.*shadow gap");
- EXPECT_DEATH(libc_memset((void*)(kHighShadowBeg + 200), 0, 100),
- "unknown-crash.*high shadow");
-}
-
-TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
- EXPECT_EQ(0U, __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_FALSE(__asan_get_ownership(wild_addr));
- EXPECT_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg);
- EXPECT_FALSE(__asan_get_ownership(array + kArraySize / 2));
- EXPECT_DEATH(__asan_get_allocated_size(array + kArraySize / 2),
- kGetAllocatedSizeErrorMsg);
-
- // NULL is not owned, but is a valid argument for __asan_get_allocated_size().
- EXPECT_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_FALSE(__asan_get_ownership(array));
- EXPECT_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg);
- delete int_ptr;
-
- void *zero_alloc = Ident(malloc(0));
- if (zero_alloc != 0) {
- // If malloc(0) is not null, this pointer is owned and should have valid
- // allocated size.
- EXPECT_TRUE(__asan_get_ownership(zero_alloc));
- // Allocated size is 0 or 1 depending on the allocator used.
- EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U);
- }
- free(zero_alloc);
-}
-
-TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
- 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);
-}
-
-TEST(AddressSanitizerInterface, GetHeapSizeTest) {
- // asan_allocator2 does not keep huge chunks in free list, but unmaps them.
- // The chunk should be greater than the quarantine size,
- // otherwise it will be stuck in quarantine instead of being unmaped.
- static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
- free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
- uptr old_heap_size = __asan_get_heap_size();
- for (int i = 0; i < 3; i++) {
- // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
- free(Ident(malloc(kLargeMallocSize)));
- EXPECT_EQ(old_heap_size, __asan_get_heap_size());
- }
-}
-
-static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
-static const size_t kManyThreadsIterations = 250;
-static const size_t kManyThreadsNumThreads =
- (SANITIZER_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])));
- }
- }
- // Just one large allocation.
- free(Ident(malloc(1 << 20)));
- 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);
-}
-
-TEST(AddressSanitizerInterface, GlobalRedzones) {
- GOOD_ACCESS(glob1, 1 - 1);
- GOOD_ACCESS(glob2, 2 - 1);
- GOOD_ACCESS(glob3, 3 - 1);
- GOOD_ACCESS(glob4, 4 - 1);
- GOOD_ACCESS(glob5, 5 - 1);
- GOOD_ACCESS(glob6, 6 - 1);
- GOOD_ACCESS(glob7, 7 - 1);
- GOOD_ACCESS(glob8, 8 - 1);
- GOOD_ACCESS(glob9, 9 - 1);
- GOOD_ACCESS(glob10, 10 - 1);
- GOOD_ACCESS(glob11, 11 - 1);
- GOOD_ACCESS(glob12, 12 - 1);
- GOOD_ACCESS(glob13, 13 - 1);
- GOOD_ACCESS(glob14, 14 - 1);
- GOOD_ACCESS(glob15, 15 - 1);
- GOOD_ACCESS(glob16, 16 - 1);
- GOOD_ACCESS(glob17, 17 - 1);
- GOOD_ACCESS(glob1000, 1000 - 1);
- GOOD_ACCESS(glob10000, 10000 - 1);
- GOOD_ACCESS(glob100000, 100000 - 1);
-
- BAD_ACCESS(glob1, 1);
- BAD_ACCESS(glob2, 2);
- BAD_ACCESS(glob3, 3);
- BAD_ACCESS(glob4, 4);
- BAD_ACCESS(glob5, 5);
- BAD_ACCESS(glob6, 6);
- BAD_ACCESS(glob7, 7);
- BAD_ACCESS(glob8, 8);
- BAD_ACCESS(glob9, 9);
- BAD_ACCESS(glob10, 10);
- BAD_ACCESS(glob11, 11);
- BAD_ACCESS(glob12, 12);
- BAD_ACCESS(glob13, 13);
- BAD_ACCESS(glob14, 14);
- BAD_ACCESS(glob15, 15);
- BAD_ACCESS(glob16, 16);
- BAD_ACCESS(glob17, 17);
- BAD_ACCESS(glob1000, 1000);
- BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
- BAD_ACCESS(glob10000, 10000);
- BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
- BAD_ACCESS(glob100000, 100000);
- BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
-}
-
-// 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));
- }
- }
- }
- }
- }
- free(arr);
-}
-
-TEST(AddressSanitizerInterface, PoisonedRegion) {
- size_t rz = 16;
- for (size_t size = 1; size <= 64; size++) {
- char *p = new char[size];
- uptr x = reinterpret_cast<uptr>(p);
- for (size_t beg = 0; beg < size + rz; beg++) {
- for (size_t end = beg; end < size + rz; end++) {
- uptr first_poisoned = __asan_region_is_poisoned(x + beg, end - beg);
- if (beg == end) {
- EXPECT_FALSE(first_poisoned);
- } else if (beg < size && end <= size) {
- EXPECT_FALSE(first_poisoned);
- } else if (beg >= size) {
- EXPECT_EQ(x + beg, first_poisoned);
- } else {
- EXPECT_GT(end, size);
- EXPECT_EQ(x + size, first_poisoned);
- }
- }
- }
- delete [] p;
- }
-}
-
-// This is a performance benchmark for manual runs.
-// asan's memset interceptor calls mem_is_zero for the entire shadow region.
-// the profile should look like this:
-// 89.10% [.] __memset_sse2
-// 10.50% [.] __sanitizer::mem_is_zero
-// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
-// than memset itself.
-TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
- size_t size = 1 << 20;
- char *x = new char[size];
- for (int i = 0; i < 100000; i++)
- Ident(memset)(x, 0, size);
- delete [] x;
-}
-
-// Same here, but we run memset with small sizes.
-TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
- size_t size = 32;
- char *x = new char[size];
- for (int i = 0; i < 100000000; i++)
- Ident(memset)(x, 0, size);
- delete [] x;
-}
-
-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) {
- int report_len = strlen(report);
- ASSERT_EQ(6, write(2, "ABCDEF", 6));
- ASSERT_EQ(report_len, write(2, report, report_len));
- ASSERT_EQ(6, write(2, "ABCDEF", 6));
- _exit(1);
-}
-
-TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
- __asan_set_error_report_callback(ErrorReportCallbackOneToZ);
- EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1),
- ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
- __asan_set_error_report_callback(NULL);
-}
-
-TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
- std::vector<char *> pointers;
- std::vector<size_t> sizes;
- const size_t kNumMallocs = 1 << 9;
- 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]);
-}
-
-
-TEST(AddressSanitizerInterface, CallocOverflow32) {
-#if SANITIZER_WORDSIZE == 32
- size_t kArraySize = 112;
- volatile size_t kArraySize2 = 43878406;
- void *p = 0;
- EXPECT_DEATH(p = calloc(kArraySize, kArraySize2),
- "allocator is terminating the process instead of returning 0");
- assert(!p);
-#endif
-}
-
-TEST(AddressSanitizerInterface, CallocReturnsZeroMem) {
- size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
- for (size_t s = 0; s < ARRAY_SIZE(sizes); s++) {
- size_t size = sizes[s];
- for (size_t iter = 0; iter < 5; iter++) {
- char *x = Ident((char*)calloc(1, size));
- EXPECT_EQ(x[0], 0);
- EXPECT_EQ(x[size - 1], 0);
- EXPECT_EQ(x[size / 2], 0);
- EXPECT_EQ(x[size / 3], 0);
- EXPECT_EQ(x[size / 4], 0);
- memset(x, 0x42, size);
- free(Ident(x));
- free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
- }
- }
+ // Check that __asan_region_is_poisoned works for shadow regions.
+ uptr ptr = kLowShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kShadowGapBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kHighShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
}
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 292cfdb8..ba7bd838 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -111,6 +111,35 @@ TEST(AddressSanitizer, CallocTest) {
free(a);
}
+TEST(AddressSanitizer, CallocOverflow32) {
+#if SANITIZER_WORDSIZE == 32
+ size_t kArraySize = 112;
+ volatile size_t kArraySize2 = 43878406;
+ void *p = 0;
+ EXPECT_DEATH(p = calloc(kArraySize, kArraySize2),
+ "allocator is terminating the process instead of returning 0");
+ assert(!p);
+#endif
+}
+
+TEST(AddressSanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+ free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
+ }
+ }
+}
+
TEST(AddressSanitizer, VallocTest) {
void *a = valloc(100);
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);