aboutsummaryrefslogtreecommitdiff
path: root/lib/asan
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asan')
-rw-r--r--lib/asan/CMakeLists.txt172
-rw-r--r--lib/asan/Makefile.mk11
-rw-r--r--lib/asan/README.txt7
-rw-r--r--lib/asan/asan_activation.cc88
-rw-r--r--lib/asan/asan_activation.h (renamed from lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc)21
-rw-r--r--lib/asan/asan_allocator.h74
-rw-r--r--lib/asan/asan_allocator2.cc203
-rw-r--r--lib/asan/asan_blacklist.txt3
-rw-r--r--lib/asan/asan_debugging.cc141
-rw-r--r--lib/asan/asan_dll_thunk.cc196
-rw-r--r--lib/asan/asan_fake_stack.cc65
-rw-r--r--lib/asan/asan_fake_stack.h8
-rw-r--r--lib/asan/asan_flags.h68
-rw-r--r--lib/asan/asan_globals.cc95
-rw-r--r--lib/asan/asan_init_version.h32
-rw-r--r--lib/asan/asan_intercepted_functions.h79
-rw-r--r--lib/asan/asan_interceptors.cc471
-rw-r--r--lib/asan/asan_interceptors.h72
-rw-r--r--lib/asan/asan_interface_internal.h112
-rw-r--r--lib/asan/asan_internal.h64
-rw-r--r--lib/asan/asan_linux.cc149
-rw-r--r--lib/asan/asan_mac.cc97
-rw-r--r--lib/asan/asan_mac.h59
-rw-r--r--lib/asan/asan_malloc_linux.cc115
-rw-r--r--lib/asan/asan_malloc_mac.cc40
-rw-r--r--lib/asan/asan_malloc_win.cc124
-rw-r--r--lib/asan/asan_mapping.h93
-rw-r--r--lib/asan/asan_new_delete.cc74
-rw-r--r--lib/asan/asan_poisoning.cc181
-rw-r--r--lib/asan/asan_poisoning.h32
-rw-r--r--lib/asan/asan_posix.cc107
-rw-r--r--lib/asan/asan_preinit.cc16
-rw-r--r--lib/asan/asan_report.cc723
-rw-r--r--lib/asan/asan_report.h74
-rw-r--r--lib/asan/asan_rtl.cc496
-rw-r--r--lib/asan/asan_stack.cc34
-rw-r--r--lib/asan/asan_stack.h92
-rw-r--r--lib/asan/asan_stats.cc13
-rw-r--r--lib/asan/asan_stats.h4
-rw-r--r--lib/asan/asan_suppressions.cc87
-rw-r--r--lib/asan/asan_suppressions.h29
-rw-r--r--lib/asan/asan_thread.cc92
-rw-r--r--lib/asan/asan_thread.h51
-rw-r--r--lib/asan/asan_win.cc132
-rw-r--r--lib/asan/asan_win_dll_thunk.cc376
-rw-r--r--lib/asan/asan_win_dynamic_runtime_thunk.cc52
-rw-r--r--lib/asan/lit_tests/32bitConfig/lit.site.cfg.in13
-rw-r--r--lib/asan/lit_tests/64bitConfig/lit.site.cfg.in12
-rw-r--r--lib/asan/lit_tests/CMakeLists.txt42
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c41
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg9
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc51
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc5
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/echo-env.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc2
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc15
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc4
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt3
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc5
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc6
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc3
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc9
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg3
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc28
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/clone_test.cc44
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/coverage.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob.cc29
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc23
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc54
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc36
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc23
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc59
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_test.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c35
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/lit.local.cfg9
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc56
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc51
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/preinit_test.cc27
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/ptrace.cc52
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc90
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/syscalls.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc39
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/uar_signals.cc70
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc35
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc33
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc12
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg4
-rw-r--r--lib/asan/lit_tests/TestCases/allocator_returns_null.cc81
-rw-r--r--lib/asan/lit_tests/TestCases/allow_user_segv.cc48
-rw-r--r--lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc39
-rw-r--r--lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc8
-rw-r--r--lib/asan/lit_tests/TestCases/atexit_stats.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/blacklist.cc38
-rw-r--r--lib/asan/lit_tests/TestCases/contiguous_container.cc47
-rw-r--r--lib/asan/lit_tests/TestCases/current_allocated_bytes.cc43
-rw-r--r--lib/asan/lit_tests/TestCases/deep_call_stack.cc25
-rw-r--r--lib/asan/lit_tests/TestCases/deep_stack_uaf.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/deep_tail_call.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/deep_thread_stack.cc57
-rw-r--r--lib/asan/lit_tests/TestCases/default_blacklist.cc3
-rw-r--r--lib/asan/lit_tests/TestCases/default_options.cc15
-rw-r--r--lib/asan/lit_tests/TestCases/dlclose-test.cc81
-rw-r--r--lib/asan/lit_tests/TestCases/double-free.cc25
-rw-r--r--lib/asan/lit_tests/TestCases/force_inline_opt0.cc14
-rw-r--r--lib/asan/lit_tests/TestCases/free_hook_realloc.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/global-demangle.cc17
-rw-r--r--lib/asan/lit_tests/TestCases/global-overflow.cc21
-rw-r--r--lib/asan/lit_tests/TestCases/heap-overflow.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/init-order-atexit.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/init-order-dlopen.cc57
-rw-r--r--lib/asan/lit_tests/TestCases/init-order-pthread-create.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-blacklist.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-bug.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-constexpr.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-nobug.cc48
-rw-r--r--lib/asan/lit_tests/TestCases/inline.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/interface_test.cc8
-rw-r--r--lib/asan/lit_tests/TestCases/invalid-free.cc21
-rw-r--r--lib/asan/lit_tests/TestCases/ioctl.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/large_func_test.cc51
-rw-r--r--lib/asan/lit_tests/TestCases/log-path_test.cc39
-rw-r--r--lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled22
-rw-r--r--lib/asan/lit_tests/TestCases/lsan_annotations.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/malloc_context_size.cc27
-rw-r--r--lib/asan/lit_tests/TestCases/malloc_fill.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/malloc_hook.cc36
-rw-r--r--lib/asan/lit_tests/TestCases/memcmp_strict_test.cc15
-rw-r--r--lib/asan/lit_tests/TestCases/memcmp_test.cc17
-rw-r--r--lib/asan/lit_tests/TestCases/null_deref.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/on_error_callback.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/partial_right.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/poison_partial.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/print_summary.cc14
-rw-r--r--lib/asan/lit_tests/TestCases/readv.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/sanity_check_pure_c.c19
-rw-r--r--lib/asan/lit_tests/TestCases/shared-lib-test.cc42
-rw-r--r--lib/asan/lit_tests/TestCases/sleep_before_dying.c10
-rw-r--r--lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/stack-frame-demangle.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/stack-oob-frames.cc59
-rw-r--r--lib/asan/lit_tests/TestCases/stack-overflow.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/stack-use-after-return.cc77
-rw-r--r--lib/asan/lit_tests/TestCases/strdup_oob_test.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/strerror_r_test.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/strip_path_prefix.c12
-rw-r--r--lib/asan/lit_tests/TestCases/strncpy-overflow.cc28
-rw-r--r--lib/asan/lit_tests/TestCases/symbolize_callback.cc17
-rw-r--r--lib/asan/lit_tests/TestCases/throw_call_test.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/throw_invoke_test.cc50
-rw-r--r--lib/asan/lit_tests/TestCases/time_interceptor.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/uar_and_exceptions.cc40
-rw-r--r--lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc52
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-free-right.cc34
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-free.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-poison.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc25
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc27
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc14
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope-temp.cc29
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/wait.cc63
-rw-r--r--lib/asan/lit_tests/Unit/lit.site.cfg.in16
-rw-r--r--lib/asan/lit_tests/lit.cfg95
-rw-r--r--lib/asan/scripts/CMakeLists.txt4
-rwxr-xr-xlib/asan/scripts/asan_device_setup267
-rwxr-xr-xlib/asan/scripts/asan_symbolize.py199
-rw-r--r--lib/asan/tests/CMakeLists.txt219
-rw-r--r--lib/asan/tests/asan_asm_test.cc267
-rw-r--r--lib/asan/tests/asan_fake_stack_test.cc10
-rw-r--r--lib/asan/tests/asan_interface_test.cc67
-rw-r--r--lib/asan/tests/asan_mem_test.cc15
-rw-r--r--lib/asan/tests/asan_noinst_test.cc110
-rw-r--r--lib/asan/tests/asan_oob_test.cc4
-rw-r--r--lib/asan/tests/asan_racy_double_free_test.cc4
-rw-r--r--lib/asan/tests/asan_str_test.cc52
-rw-r--r--lib/asan/tests/asan_test.cc193
-rw-r--r--lib/asan/tests/asan_test_config.h12
-rw-r--r--lib/asan/tests/asan_test_utils.h20
193 files changed, 4650 insertions, 5836 deletions
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index ad3f05488ebf..47486b7caf89 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -2,6 +2,8 @@
set(ASAN_SOURCES
asan_allocator2.cc
+ asan_activation.cc
+ asan_debugging.cc
asan_fake_stack.cc
asan_globals.cc
asan_interceptors.cc
@@ -10,81 +12,85 @@ set(ASAN_SOURCES
asan_malloc_linux.cc
asan_malloc_mac.cc
asan_malloc_win.cc
- asan_new_delete.cc
asan_poisoning.cc
asan_posix.cc
- asan_preinit.cc
asan_report.cc
asan_rtl.cc
asan_stack.cc
asan_stats.cc
+ asan_suppressions.cc
asan_thread.cc
asan_win.cc)
+set(ASAN_CXX_SOURCES
+ asan_new_delete.cc)
+
+set(ASAN_PREINIT_SOURCES
+ asan_preinit.cc)
+
include_directories(..)
-if (NOT MSVC)
- set(ASAN_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fno-rtti)
-else()
- set(ASAN_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- /GR-)
-endif()
+set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(ASAN_CFLAGS)
set(ASAN_COMMON_DEFINITIONS
ASAN_HAS_EXCEPTIONS=1)
if(ANDROID)
list(APPEND ASAN_COMMON_DEFINITIONS
- ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
- ASAN_NEEDS_SEGV=0
ASAN_LOW_MEMORY=1)
-elseif(MSVC)
- list(APPEND ASAN_COMMON_DEFINITIONS
- ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
- ASAN_NEEDS_SEGV=0)
-else()
- list(APPEND ASAN_COMMON_DEFINITIONS
- ASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
- ASAN_NEEDS_SEGV=1)
endif()
-# Architectures supported by ASan.
-filter_available_targets(ASAN_SUPPORTED_ARCH
- x86_64 i386 powerpc64)
+set(ASAN_DYNAMIC_DEFINITIONS
+ ${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)
+append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS)
+
+set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS})
+append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
+ -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
+append_list_if(MSVC /DEBUG ASAN_DYNAMIC_CFLAGS)
+
+append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS)
+
+append_list_if(ANDROID log ASAN_DYNAMIC_LIBS)
# Compile ASan sources into an object library.
if(APPLE)
foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
add_compiler_rt_darwin_object_library(RTAsan ${os}
ARCH ${ASAN_SUPPORTED_ARCH}
- SOURCES ${ASAN_SOURCES}
+ SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
endforeach()
-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})
+ add_compiler_rt_object_library(RTAsan_cxx ${arch}
+ SOURCES ${ASAN_CXX_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_compiler_rt_object_library(RTAsan_preinit ${arch}
+ SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ if (COMPILER_RT_BUILD_SHARED_ASAN)
+ add_compiler_rt_object_library(RTAsan_dynamic ${arch}
+ SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+ endif()
endforeach()
endif()
# Build ASan runtimes shipped with Clang.
-set(ASAN_RUNTIME_LIBRARIES)
+add_custom_target(asan)
if(APPLE)
foreach (os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
- # Dynamic lookup is needed because shadow scale and offset are
- # provided by the instrumented modules.
- set(ASAN_RUNTIME_LDFLAGS
- "-undefined dynamic_lookup")
add_compiler_rt_darwin_dynamic_runtime(clang_rt.asan_${os}_dynamic ${os}
ARCH ${ASAN_SUPPORTED_ARCH}
SOURCES $<TARGET_OBJECTS:RTAsan.${os}>
@@ -92,63 +98,89 @@ if(APPLE)
$<TARGET_OBJECTS:RTSanitizerCommon.${os}>
$<TARGET_OBJECTS:RTLSanCommon.${os}>
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS}
- LINKFLAGS ${ASAN_RUNTIME_LDFLAGS})
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_${os}_dynamic)
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan_${os}_dynamic)
endforeach()
-
-elseif(ANDROID)
- add_library(clang_rt.asan-arm-android SHARED
- $<TARGET_OBJECTS:RTAsan.arm.android>
- $<TARGET_OBJECTS:RTInterception.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
- COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
- target_link_libraries(clang_rt.asan-arm-android dl)
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-arm-android)
else()
# Build separate libraries for each target.
foreach(arch ${ASAN_SUPPORTED_ARCH})
- set(ASAN_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTAsan.${arch}>
+ set(ASAN_COMMON_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
- if (NOT WIN32)
+ if(NOT WIN32)
# We can't build Leak Sanitizer on Windows yet.
- list(APPEND ASAN_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+ list(APPEND ASAN_COMMON_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
endif()
- add_compiler_rt_static_runtime(clang_rt.asan-${arch} ${arch}
- SOURCES ${ASAN_RUNTIME_OBJECTS}
+ add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ ${ASAN_COMMON_RUNTIME_OBJECTS}
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan-${arch})
+
+ add_compiler_rt_runtime(clang_rt.asan_cxx-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch})
- if (UNIX AND NOT ${arch} STREQUAL "i386")
+ add_dependencies(asan clang_rt.asan_cxx-${arch})
+
+ if (COMPILER_RT_BUILD_SHARED_ASAN)
+ add_compiler_rt_runtime(clang_rt.asan-preinit-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan-preinit-${arch})
+
+ if (WIN32)
+ set(SHARED_ASAN_NAME clang_rt.asan_dynamic-${arch}${COMPILER_RT_OS_SUFFIX})
+ else()
+ set(SHARED_ASAN_NAME clang_rt.asan-${arch}${COMPILER_RT_OS_SUFFIX})
+ endif()
+
+ add_compiler_rt_runtime(clang_rt.asan-dynamic-${arch} ${arch} SHARED
+ OUTPUT_NAME ${SHARED_ASAN_NAME}
+ SOURCES $<TARGET_OBJECTS:RTAsan_dynamic.${arch}>
+ ${ASAN_COMMON_RUNTIME_OBJECTS}
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+ target_link_libraries(clang_rt.asan-dynamic-${arch} ${ASAN_DYNAMIC_LIBS})
+ add_dependencies(asan clang_rt.asan-dynamic-${arch})
+ endif()
+
+ if (UNIX AND NOT ${arch} STREQUAL "i386" AND NOT ${arch} STREQUAL "i686")
+ add_sanitizer_rt_symbols(clang_rt.asan_cxx-${arch})
+ add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra)
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch}-symbols)
+ add_dependencies(asan clang_rt.asan-${arch}-symbols)
endif()
if (WIN32)
- add_compiler_rt_static_runtime(clang_rt.asan_dll_thunk-${arch} ${arch}
- SOURCES asan_dll_thunk.cc
- CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
- DEFS ${ASAN_COMMON_DEFINITIONS})
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_dll_thunk-${arch})
+ add_compiler_rt_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} STATIC
+ SOURCES asan_win_dll_thunk.cc
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan_dll_thunk-${arch})
+ add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk-${arch} ${arch}
+ STATIC
+ SOURCES asan_win_dynamic_runtime_thunk.cc
+ CFLAGS ${ASAN_CFLAGS} -DASAN_DYNAMIC_RUNTIME_THUNK -Zl
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan_dynamic_runtime_thunk-${arch})
endif()
endforeach()
endif()
add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt)
+add_dependencies(asan asan_blacklist)
+add_dependencies(compiler-rt asan)
-# All ASan runtime dependencies.
-add_custom_target(asan_runtime_libraries
- DEPENDS asan_blacklist ${ASAN_RUNTIME_LIBRARIES})
+add_subdirectory(scripts)
-if(LLVM_INCLUDE_TESTS)
+if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
-
-add_subdirectory(lit_tests)
diff --git a/lib/asan/Makefile.mk b/lib/asan/Makefile.mk
index 97da64bec573..0dafefc2fd8c 100644
--- a/lib/asan/Makefile.mk
+++ b/lib/asan/Makefile.mk
@@ -10,8 +10,12 @@
ModuleName := asan
SubDirs :=
-Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
-ObjNames := $(Sources:%.cc=%.o)
+CCSources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+CXXOnlySources := asan_new_delete.cc
+COnlySources := $(filter-out $(CXXOnlySources),$(CCSources))
+SSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(CCSources) $(SSources)
+ObjNames := $(CCSources:%.cc=%.o) $(SSources:%.S=%.o)
Implementation := Generic
@@ -21,4 +25,5 @@ Dependencies += $(wildcard $(Dir)/../interception/*.h)
Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
# Define a convenience variable for all the asan functions.
-AsanFunctions := $(Sources:%.cc=%)
+AsanFunctions := $(COnlySources:%.cc=%) $(SSources:%.S=%)
+AsanCXXFunctions := $(CXXOnlySources:%.cc=%)
diff --git a/lib/asan/README.txt b/lib/asan/README.txt
index e4f4961c5d4f..b9c43acd5fe4 100644
--- a/lib/asan/README.txt
+++ b/lib/asan/README.txt
@@ -1,16 +1,15 @@
AddressSanitizer RT
================================
-This directory contains sources of the AddressSanitizer (asan) run-time library.
+This directory contains sources of the AddressSanitizer (asan) runtime library.
We are in the process of integrating AddressSanitizer with LLVM, stay tuned.
-Directory structre:
+Directory structure:
README.txt : This file.
Makefile.mk : File for make-based build.
CMakeLists.txt : File for cmake-based build.
-asan_*.{cc,h} : Sources of the asan run-time lirbary.
+asan_*.{cc,h} : Sources of the asan runtime library.
scripts/* : Helper scripts.
tests/* : ASan unit tests.
-lit_tests/* : ASan output tests.
Also ASan runtime needs the following libraries:
lib/interception/ : Machinery used to intercept function calls.
diff --git a/lib/asan/asan_activation.cc b/lib/asan/asan_activation.cc
new file mode 100644
index 000000000000..eb4a6db0b85e
--- /dev/null
+++ b/lib/asan/asan_activation.cc
@@ -0,0 +1,88 @@
+//===-- asan_activation.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.
+//
+// ASan activation/deactivation logic.
+//===----------------------------------------------------------------------===//
+
+#include "asan_activation.h"
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __asan {
+
+static struct AsanDeactivatedFlags {
+ int quarantine_size;
+ int max_redzone;
+ int malloc_context_size;
+ bool poison_heap;
+ bool alloc_dealloc_mismatch;
+ bool allocator_may_return_null;
+} asan_deactivated_flags;
+
+static bool asan_is_deactivated;
+
+void AsanStartDeactivated() {
+ VReport(1, "Deactivating ASan\n");
+ // Save flag values.
+ asan_deactivated_flags.quarantine_size = flags()->quarantine_size;
+ asan_deactivated_flags.max_redzone = flags()->max_redzone;
+ asan_deactivated_flags.poison_heap = flags()->poison_heap;
+ asan_deactivated_flags.malloc_context_size =
+ common_flags()->malloc_context_size;
+ asan_deactivated_flags.alloc_dealloc_mismatch =
+ flags()->alloc_dealloc_mismatch;
+ asan_deactivated_flags.allocator_may_return_null =
+ common_flags()->allocator_may_return_null;
+
+ flags()->quarantine_size = 0;
+ flags()->max_redzone = 16;
+ flags()->poison_heap = false;
+ common_flags()->malloc_context_size = 0;
+ flags()->alloc_dealloc_mismatch = false;
+ common_flags()->allocator_may_return_null = true;
+
+ asan_is_deactivated = true;
+}
+
+void AsanActivate() {
+ if (!asan_is_deactivated) return;
+ VReport(1, "Activating ASan\n");
+
+ // Restore flag values.
+ // FIXME: this is not atomic, and there may be other threads alive.
+ flags()->quarantine_size = asan_deactivated_flags.quarantine_size;
+ flags()->max_redzone = asan_deactivated_flags.max_redzone;
+ flags()->poison_heap = asan_deactivated_flags.poison_heap;
+ common_flags()->malloc_context_size =
+ asan_deactivated_flags.malloc_context_size;
+ flags()->alloc_dealloc_mismatch =
+ asan_deactivated_flags.alloc_dealloc_mismatch;
+ common_flags()->allocator_may_return_null =
+ asan_deactivated_flags.allocator_may_return_null;
+
+ ParseExtraActivationFlags();
+
+ ReInitializeAllocator();
+
+ asan_is_deactivated = false;
+ VReport(
+ 1,
+ "quarantine_size %d, max_redzone %d, poison_heap %d, "
+ "malloc_context_size %d, alloc_dealloc_mismatch %d, "
+ "allocator_may_return_null %d\n",
+ flags()->quarantine_size, flags()->max_redzone, flags()->poison_heap,
+ common_flags()->malloc_context_size, flags()->alloc_dealloc_mismatch,
+ common_flags()->allocator_may_return_null);
+}
+
+} // namespace __asan
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc b/lib/asan/asan_activation.h
index 6ef565ce47b3..dafb840a6042 100644
--- a/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc
+++ b/lib/asan/asan_activation.h
@@ -1,4 +1,4 @@
-//===----------- shared-lib-test-so.cc --------------------------*- C++ -*-===//
+//===-- asan_activation.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -9,18 +9,15 @@
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
+// ASan activation/deactivation logic.
//===----------------------------------------------------------------------===//
-#include <stdio.h>
-int pad[10];
-int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#ifndef ASAN_ACTIVATION_H
+#define ASAN_ACTIVATION_H
-extern "C"
-void inc(int index) {
- GLOB[index]++;
-}
+namespace __asan {
+void AsanStartDeactivated();
+void AsanActivate();
+} // namespace __asan
-extern "C"
-void inc2(int *a, int index) {
- a[index]++;
-}
+#endif // ASAN_ACTIVATION_H
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index c5fcbbb5d64b..6d3a99282a4a 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -17,6 +17,7 @@
#include "asan_internal.h"
#include "asan_interceptors.h"
+#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_list.h"
namespace __asan {
@@ -31,6 +32,7 @@ static const uptr kNumberOfSizeClasses = 255;
struct AsanChunk;
void InitializeAllocator();
+void ReInitializeAllocator();
class AsanChunkView {
public:
@@ -42,8 +44,9 @@ class AsanChunkView {
uptr UsedSize(); // Size requested by the user.
uptr AllocTid();
uptr FreeTid();
- void GetAllocStack(StackTrace *stack);
- void GetFreeStack(StackTrace *stack);
+ bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
+ StackTrace GetAllocStack();
+ StackTrace GetFreeStack();
bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
if (addr >= Beg() && (addr + access_size) <= End()) {
*offset = addr - Beg();
@@ -90,31 +93,66 @@ class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
uptr size_;
};
-struct AsanThreadLocalMallocStorage {
- explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
- { }
- AsanThreadLocalMallocStorage() {
- CHECK(REAL(memset));
- REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
- }
+struct AsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const;
+ void OnUnmap(uptr p, uptr size) const;
+};
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+# if defined(__powerpc64__)
+const uptr kAllocatorSpace = 0xa0000000000ULL;
+const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
+# else
+const uptr kAllocatorSpace = 0x600000000000ULL;
+const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+# endif
+typedef DefaultSizeClassMap SizeClassMap;
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
+ SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
+#else // Fallback to SizeClassAllocator32.
+static const uptr kRegionSizeLog = 20;
+static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+# if SANITIZER_WORDSIZE == 32
+typedef FlatByteMap<kNumRegions> ByteMap;
+# elif SANITIZER_WORDSIZE == 64
+typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+# endif
+typedef CompactSizeClassMap SizeClassMap;
+typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16,
+ SizeClassMap, kRegionSizeLog,
+ ByteMap,
+ AsanMapUnmapCallback> PrimaryAllocator;
+#endif // SANITIZER_CAN_USE_ALLOCATOR64
+
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+struct AsanThreadLocalMallocStorage {
uptr quarantine_cache[16];
- uptr allocator2_cache[96 * (512 * 8 + 16)]; // Opaque.
+ AllocatorCache allocator2_cache;
void CommitBack();
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ AsanThreadLocalMallocStorage() {}
};
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
AllocType alloc_type);
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type);
-void *asan_malloc(uptr size, StackTrace *stack);
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack);
-void *asan_realloc(void *p, uptr size, StackTrace *stack);
-void *asan_valloc(uptr size, StackTrace *stack);
-void *asan_pvalloc(uptr size, StackTrace *stack);
+void *asan_malloc(uptr size, BufferedStackTrace *stack);
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
+void *asan_valloc(uptr size, BufferedStackTrace *stack);
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
- StackTrace *stack);
+ BufferedStackTrace *stack);
uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
uptr asan_mz_size(const void *ptr);
diff --git a/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc
index 7a29975d711e..52bdcf607f57 100644
--- a/lib/asan/asan_allocator2.cc
+++ b/lib/asan/asan_allocator2.cc
@@ -19,8 +19,9 @@
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
+#include "asan_stack.h"
#include "asan_thread.h"
-#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_list.h"
@@ -30,65 +31,30 @@
namespace __asan {
-struct AsanMapUnmapCallback {
- void OnMap(uptr p, uptr size) const {
- PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
- // Statistics.
- AsanStats &thread_stats = GetCurrentThreadStats();
- thread_stats.mmaps++;
- thread_stats.mmaped += size;
- }
- void OnUnmap(uptr p, uptr size) const {
- PoisonShadow(p, size, 0);
- // We are about to unmap a chunk of user memory.
- // Mark the corresponding shadow memory as not needed.
- // Since asan's mapping is compacting, the shadow chunk may be
- // not page-aligned, so we only flush the page-aligned portion.
- uptr page_size = GetPageSizeCached();
- uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
- uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
- FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
- // Statistics.
- AsanStats &thread_stats = GetCurrentThreadStats();
- thread_stats.munmaps++;
- thread_stats.munmaped += size;
- }
-};
-
-#if SANITIZER_WORDSIZE == 64
-#if defined(__powerpc64__)
-const uptr kAllocatorSpace = 0xa0000000000ULL;
-const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
-#else
-const uptr kAllocatorSpace = 0x600000000000ULL;
-const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
-#endif
-typedef DefaultSizeClassMap SizeClassMap;
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
- SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
-#elif SANITIZER_WORDSIZE == 32
-static const u64 kAddressSpaceSize = 1ULL << 32;
-typedef CompactSizeClassMap SizeClassMap;
-static const uptr kRegionSizeLog = 20;
-static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
-typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
- SizeClassMap, kRegionSizeLog,
- FlatByteMap<kFlatByteMapSize>,
- AsanMapUnmapCallback> PrimaryAllocator;
-#endif
-
-typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
-typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
- SecondaryAllocator> Allocator;
+void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const {
+ PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.mmaps++;
+ thread_stats.mmaped += size;
+}
+void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const {
+ PoisonShadow(p, size, 0);
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ FlushUnneededASanShadowMemory(p, size);
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.munmaps++;
+ thread_stats.munmaped += size;
+}
// We can not use THREADLOCAL because it is not supported on some of the
// platforms we care about (OSX 10.6, Android).
// static THREADLOCAL AllocatorCache cache;
AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
CHECK(ms);
- CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator2_cache));
- return reinterpret_cast<AllocatorCache *>(ms->allocator2_cache);
+ return &ms->allocator2_cache;
}
static Allocator allocator;
@@ -134,7 +100,8 @@ static uptr ComputeRZLog(uptr user_requested_size) {
user_requested_size <= (1 << 14) - 256 ? 4 :
user_requested_size <= (1 << 15) - 512 ? 5 :
user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
- return Max(rz_log, RZSize2Log(flags()->redzone));
+ return Min(Max(rz_log, RZSize2Log(flags()->redzone)),
+ RZSize2Log(flags()->max_redzone));
}
// The memory chunk allocated from the underlying allocator looks like this:
@@ -201,23 +168,6 @@ struct AsanChunk: ChunkBase {
}
return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
}
- // If we don't use stack depot, we store the alloc/free stack traces
- // in the chunk itself.
- u32 *AllocStackBeg() {
- return (u32*)(Beg() - RZLog2Size(rz_log));
- }
- uptr AllocStackSize() {
- CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize);
- return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32);
- }
- u32 *FreeStackBeg() {
- return (u32*)(Beg() + kChunkHeader2Size);
- }
- uptr FreeStackSize() {
- if (user_requested_size < kChunkHeader2Size) return 0;
- uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
- return (available - kChunkHeader2Size) / sizeof(u32);
- }
bool AddrIsInside(uptr addr, bool locked_version = false) {
return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
}
@@ -232,20 +182,19 @@ uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
-static void GetStackTraceFromId(u32 id, StackTrace *stack) {
+static StackTrace GetStackTraceFromId(u32 id) {
CHECK(id);
- uptr size = 0;
- const uptr *trace = StackDepotGet(id, &size);
- CHECK(trace);
- stack->CopyFrom(trace, size);
+ StackTrace res = StackDepotGet(id);
+ CHECK(res.trace);
+ return res;
}
-void AsanChunkView::GetAllocStack(StackTrace *stack) {
- GetStackTraceFromId(chunk_->alloc_context_id, stack);
+StackTrace AsanChunkView::GetAllocStack() {
+ return GetStackTraceFromId(chunk_->alloc_context_id);
}
-void AsanChunkView::GetFreeStack(StackTrace *stack) {
- GetStackTraceFromId(chunk_->free_context_id, stack);
+StackTrace AsanChunkView::GetFreeStack() {
+ return GetStackTraceFromId(chunk_->free_context_id);
}
struct QuarantineCallback;
@@ -309,10 +258,14 @@ void InitializeAllocator() {
quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
}
-static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
+void ReInitializeAllocator() {
+ quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
+}
+
+static void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
AllocType alloc_type, bool can_fill) {
- if (!asan_inited)
- __asan_init();
+ if (UNLIKELY(!asan_inited))
+ AsanInitFromRtl();
Flags &fl = *flags();
CHECK(stack);
const uptr min_alignment = SHADOW_GRANULARITY;
@@ -357,6 +310,16 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
AllocatorCache *cache = &fallback_allocator_cache;
allocated = allocator.Allocate(cache, needed_size, 8, false);
}
+
+ if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && flags()->poison_heap) {
+ // Heap poisoning is enabled, but the allocator provides an unpoisoned
+ // chunk. This is possible if flags()->poison_heap was disabled for some
+ // time, for example, due to flags()->start_disabled.
+ // Anyway, poison the block before using it for anything else.
+ uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated);
+ PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic);
+ }
+
uptr alloc_beg = reinterpret_cast<uptr>(allocated);
uptr alloc_end = alloc_beg + needed_size;
uptr beg_plus_redzone = alloc_beg + rz_size;
@@ -391,7 +354,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
meta[1] = chunk_beg;
}
- m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
+ m->alloc_context_id = StackDepotPut(*stack);
uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
// Unpoison the bulk of the memory region.
@@ -427,15 +390,16 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
return res;
}
-static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) {
+static void ReportInvalidFree(void *ptr, u8 chunk_state,
+ BufferedStackTrace *stack) {
if (chunk_state == CHUNK_QUARANTINE)
ReportDoubleFree((uptr)ptr, stack);
else
ReportFreeNotMalloced((uptr)ptr, stack);
}
-static void AtomicallySetQuarantineFlag(AsanChunk *m,
- void *ptr, StackTrace *stack) {
+static void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
+ BufferedStackTrace *stack) {
u8 old_chunk_state = CHUNK_ALLOCATED;
// Flip the chunk_state atomically to avoid race on double-free.
if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
@@ -446,8 +410,8 @@ static void AtomicallySetQuarantineFlag(AsanChunk *m,
// Expects the chunk to already be marked as quarantined by using
// AtomicallySetQuarantineFlag.
-static void QuarantineChunk(AsanChunk *m, void *ptr,
- StackTrace *stack, AllocType alloc_type) {
+static void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
+ AllocType alloc_type) {
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
@@ -459,7 +423,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
CHECK_EQ(m->free_tid, kInvalidTid);
AsanThread *t = GetCurrentThread();
m->free_tid = t ? t->tid() : 0;
- m->free_context_id = StackDepotPut(stack->trace, stack->size);
+ m->free_context_id = StackDepotPut(*stack);
// Poison the region.
PoisonShadow(m->Beg(),
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
@@ -483,19 +447,25 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
}
}
-static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
+static void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
uptr p = reinterpret_cast<uptr>(ptr);
if (p == 0) return;
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+ if (delete_size && flags()->new_delete_type_mismatch &&
+ delete_size != m->UsedSize()) {
+ ReportNewDeleteSizeMismatch(p, delete_size, stack);
+ }
ASAN_FREE_HOOK(ptr);
// Must mark the chunk as quarantined before any changes to its metadata.
AtomicallySetQuarantineFlag(m, ptr, stack);
QuarantineChunk(m, ptr, stack, alloc_type);
}
-static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
+static void *Reallocate(void *old_ptr, uptr new_size,
+ BufferedStackTrace *stack) {
CHECK(old_ptr && new_size);
uptr p = reinterpret_cast<uptr>(old_ptr);
uptr chunk_beg = p - kChunkHeaderSize;
@@ -515,7 +485,7 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
// If realloc() races with free(), we may start copying freed memory.
// However, we will report racy double-free later anyway.
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
- Deallocate(old_ptr, stack, FROM_MALLOC);
+ Deallocate(old_ptr, 0, stack, FROM_MALLOC);
}
return new_ptr;
}
@@ -608,20 +578,25 @@ void PrintInternalAllocatorStats() {
allocator.PrintStats();
}
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
AllocType alloc_type) {
return Allocate(size, alignment, stack, alloc_type, true);
}
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
- Deallocate(ptr, stack, alloc_type);
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
+ Deallocate(ptr, 0, stack, alloc_type);
}
-void *asan_malloc(uptr size, StackTrace *stack) {
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ Deallocate(ptr, size, stack, alloc_type);
+}
+
+void *asan_malloc(uptr size, BufferedStackTrace *stack) {
return Allocate(size, 8, stack, FROM_MALLOC, true);
}
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
if (CallocShouldReturnNullDueToOverflow(size, nmemb))
return AllocatorReturnNull();
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
@@ -632,21 +607,21 @@ void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
return ptr;
}
-void *asan_realloc(void *p, uptr size, StackTrace *stack) {
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
if (p == 0)
return Allocate(size, 8, stack, FROM_MALLOC, true);
if (size == 0) {
- Deallocate(p, stack, FROM_MALLOC);
+ Deallocate(p, 0, stack, FROM_MALLOC);
return 0;
}
return Reallocate(p, size, stack);
}
-void *asan_valloc(uptr size, StackTrace *stack) {
+void *asan_valloc(uptr size, BufferedStackTrace *stack) {
return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
}
-void *asan_pvalloc(uptr size, StackTrace *stack) {
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
uptr PageSize = GetPageSizeCached();
size = RoundUpTo(size, PageSize);
if (size == 0) {
@@ -657,7 +632,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack) {
}
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
- StackTrace *stack) {
+ BufferedStackTrace *stack) {
void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
CHECK(IsAligned((uptr)ptr, alignment));
*memptr = ptr;
@@ -710,8 +685,12 @@ uptr PointsIntoChunk(void* p) {
__asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
if (!m) return 0;
uptr chunk = m->Beg();
- if ((m->chunk_state == __asan::CHUNK_ALLOCATED) &&
- m->AddrIsInside(addr, /*locked_version=*/true))
+ if (m->chunk_state != __asan::CHUNK_ALLOCATED)
+ return 0;
+ if (m->AddrIsInside(addr, /*locked_version=*/true))
+ return chunk;
+ if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true),
+ addr))
return chunk;
return 0;
}
@@ -776,23 +755,23 @@ using namespace __asan; // NOLINT
// ASan allocator doesn't reserve extra bytes, so normally we would
// just return "size". We don't want to expose our redzone sizes, etc here.
-uptr __asan_get_estimated_allocated_size(uptr size) {
+uptr __sanitizer_get_estimated_allocated_size(uptr size) {
return size;
}
-bool __asan_get_ownership(const void *p) {
+int __sanitizer_get_ownership(const void *p) {
uptr ptr = reinterpret_cast<uptr>(p);
return (AllocationSize(ptr) > 0);
}
-uptr __asan_get_allocated_size(const void *p) {
+uptr __sanitizer_get_allocated_size(const void *p) {
if (p == 0) return 0;
uptr ptr = reinterpret_cast<uptr>(p);
uptr allocated_size = AllocationSize(ptr);
// Die if p is not malloced or if it is already freed.
if (allocated_size == 0) {
GET_STACK_TRACE_FATAL_HERE;
- ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
+ ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack);
}
return allocated_size;
}
@@ -801,12 +780,12 @@ uptr __asan_get_allocated_size(const void *p) {
// Provide default (no-op) implementation of malloc hooks.
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __asan_malloc_hook(void *ptr, uptr size) {
+void __sanitizer_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __asan_free_hook(void *ptr) {
+void __sanitizer_free_hook(void *ptr) {
(void)ptr;
}
} // extern "C"
diff --git a/lib/asan/asan_blacklist.txt b/lib/asan/asan_blacklist.txt
index 63b3c315b26b..c25921fd5fe7 100644
--- a/lib/asan/asan_blacklist.txt
+++ b/lib/asan/asan_blacklist.txt
@@ -8,3 +8,6 @@
# global:*global_with_bad_access_or_initialization*
# global:*global_with_initialization_issues*=init
# type:*Namespace::ClassName*=init
+
+# Stack buffer overflow in VC/INCLUDE/xlocnum, see http://goo.gl/L4qqUG
+fun:*_Find_elem@*@std*
diff --git a/lib/asan/asan_debugging.cc b/lib/asan/asan_debugging.cc
new file mode 100644
index 000000000000..2b66dd5265fc
--- /dev/null
+++ b/lib/asan/asan_debugging.cc
@@ -0,0 +1,141 @@
+//===-- asan_debugging.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.
+//
+// This file contains various functions that are generally useful to call when
+// using a debugger (LLDB, GDB).
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
+ descr->name[0] = 0;
+ descr->region_address = 0;
+ descr->region_size = 0;
+ descr->region_kind = "stack";
+
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access))
+ return;
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ return;
+ }
+
+ for (uptr i = 0; i < vars.size(); i++) {
+ if (access.offset <= vars[i].beg + vars[i].size) {
+ internal_strncat(descr->name, vars[i].name_pos,
+ Min(descr->name_size, vars[i].name_len));
+ descr->region_address = addr - (access.offset - vars[i].beg);
+ descr->region_size = vars[i].size;
+ return;
+ }
+ }
+}
+
+void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+
+ descr->name[0] = 0;
+ descr->region_address = 0;
+ descr->region_size = 0;
+
+ if (!chunk.IsValid()) {
+ descr->region_kind = "heap-invalid";
+ return;
+ }
+
+ descr->region_address = chunk.Beg();
+ descr->region_size = chunk.UsedSize();
+ descr->region_kind = "heap";
+}
+
+void AsanLocateAddress(uptr addr, AddressDescription *descr) {
+ if (DescribeAddressIfShadow(addr, descr, /* print */ false)) {
+ return;
+ }
+ if (GetInfoForAddressIfGlobal(addr, descr)) {
+ return;
+ }
+ asanThreadRegistry().Lock();
+ AsanThread *thread = FindThreadByStackAddress(addr);
+ asanThreadRegistry().Unlock();
+ if (thread) {
+ GetInfoForStackVar(addr, descr, thread);
+ return;
+ }
+ GetInfoForHeapAddress(addr, descr);
+}
+
+uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
+ bool alloc_stack) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+ if (!chunk.IsValid()) return 0;
+
+ StackTrace stack(nullptr, 0);
+ if (alloc_stack) {
+ if (chunk.AllocTid() == kInvalidTid) return 0;
+ stack = chunk.GetAllocStack();
+ if (thread_id) *thread_id = chunk.AllocTid();
+ } else {
+ if (chunk.FreeTid() == kInvalidTid) return 0;
+ stack = chunk.GetFreeStack();
+ if (thread_id) *thread_id = chunk.FreeTid();
+ }
+
+ if (trace && size) {
+ size = Min(size, Min(stack.size, kStackTraceMax));
+ for (uptr i = 0; i < size; i++)
+ trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
+
+ return size;
+ }
+
+ return 0;
+}
+
+} // namespace __asan
+
+using namespace __asan;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address, uptr *region_size) {
+ AddressDescription descr = { name, name_size, 0, 0, 0 };
+ AsanLocateAddress(addr, &descr);
+ if (region_address) *region_address = descr.region_address;
+ if (region_size) *region_size = descr.region_size;
+ return descr.region_kind;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+ return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+ return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
+ if (shadow_scale)
+ *shadow_scale = SHADOW_SCALE;
+ if (shadow_offset)
+ *shadow_offset = SHADOW_OFFSET;
+}
diff --git a/lib/asan/asan_dll_thunk.cc b/lib/asan/asan_dll_thunk.cc
deleted file mode 100644
index cedd60d342f6..000000000000
--- a/lib/asan/asan_dll_thunk.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-//===-- asan_dll_thunk.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.
-//
-// This file defines a family of thunks that should be statically linked into
-// the DLLs that have ASan instrumentation in order to delegate the calls to the
-// shared runtime that lives in the main binary.
-// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
-// details.
-//===----------------------------------------------------------------------===//
-
-// Only compile this code when buidling asan_dll_thunk.lib
-// Using #ifdef rather than relying on Makefiles etc.
-// simplifies the build procedure.
-#ifdef ASAN_DLL_THUNK
-
-// ----------------- Helper functions and macros --------------------- {{{1
-extern "C" {
-void *__stdcall GetModuleHandleA(const char *module_name);
-void *__stdcall GetProcAddress(void *module, const char *proc_name);
-void abort();
-}
-
-static void *getRealProcAddressOrDie(const char *name) {
- void *ret = GetProcAddress(GetModuleHandleA(0), name);
- if (!ret)
- abort();
- return ret;
-}
-
-#define WRAP_V_V(name) \
- extern "C" void name() { \
- typedef void (*fntype)(); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(); \
- }
-
-#define WRAP_V_W(name) \
- extern "C" void name(void *arg) { \
- typedef void (*fntype)(void *arg); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg); \
- }
-
-#define WRAP_V_WW(name) \
- extern "C" void name(void *arg1, void *arg2) { \
- typedef void (*fntype)(void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg1, arg2); \
- }
-
-#define WRAP_V_WWW(name) \
- extern "C" void name(void *arg1, void *arg2, void *arg3) { \
- typedef void *(*fntype)(void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg1, arg2, arg3); \
- }
-
-#define WRAP_W_V(name) \
- extern "C" void *name() { \
- typedef void *(*fntype)(); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(); \
- }
-
-#define WRAP_W_W(name) \
- extern "C" void *name(void *arg) { \
- typedef void *(*fntype)(void *arg); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg); \
- }
-
-#define WRAP_W_WW(name) \
- extern "C" void *name(void *arg1, void *arg2) { \
- typedef void *(*fntype)(void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2); \
- }
-
-#define WRAP_W_WWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
- typedef void *(*fntype)(void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3); \
- }
-
-#define WRAP_W_WWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
- typedef void *(*fntype)(void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4); \
- }
-
-#define WRAP_W_WWWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
- void *arg5) { \
- typedef void *(*fntype)(void *, void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4, arg5); \
- }
-
-#define WRAP_W_WWWWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
- void *arg5, void *arg6) { \
- typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
- }
-// }}}
-
-// ----------------- ASan own interface functions --------------------
-WRAP_W_V(__asan_should_detect_stack_use_after_return)
-
-extern "C" {
- int __asan_option_detect_stack_use_after_return;
-
- // Manually wrap __asan_init as we need to initialize
- // __asan_option_detect_stack_use_after_return afterwards.
- void __asan_init_v3() {
- typedef void (*fntype)();
- static fntype fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
- fn();
- __asan_option_detect_stack_use_after_return =
- (__asan_should_detect_stack_use_after_return() != 0);
- }
-}
-
-WRAP_V_W(__asan_report_store1)
-WRAP_V_W(__asan_report_store2)
-WRAP_V_W(__asan_report_store4)
-WRAP_V_W(__asan_report_store8)
-WRAP_V_W(__asan_report_store16)
-WRAP_V_WW(__asan_report_store_n)
-
-WRAP_V_W(__asan_report_load1)
-WRAP_V_W(__asan_report_load2)
-WRAP_V_W(__asan_report_load4)
-WRAP_V_W(__asan_report_load8)
-WRAP_V_W(__asan_report_load16)
-WRAP_V_WW(__asan_report_load_n)
-
-WRAP_V_WW(__asan_register_globals)
-WRAP_V_WW(__asan_unregister_globals)
-
-WRAP_W_WW(__asan_stack_malloc_0)
-WRAP_W_WW(__asan_stack_malloc_1)
-WRAP_W_WW(__asan_stack_malloc_2)
-WRAP_W_WW(__asan_stack_malloc_3)
-WRAP_W_WW(__asan_stack_malloc_4)
-WRAP_W_WW(__asan_stack_malloc_5)
-WRAP_W_WW(__asan_stack_malloc_6)
-WRAP_W_WW(__asan_stack_malloc_7)
-WRAP_W_WW(__asan_stack_malloc_8)
-WRAP_W_WW(__asan_stack_malloc_9)
-WRAP_W_WW(__asan_stack_malloc_10)
-
-WRAP_V_WWW(__asan_stack_free_0)
-WRAP_V_WWW(__asan_stack_free_1)
-WRAP_V_WWW(__asan_stack_free_2)
-WRAP_V_WWW(__asan_stack_free_4)
-WRAP_V_WWW(__asan_stack_free_5)
-WRAP_V_WWW(__asan_stack_free_6)
-WRAP_V_WWW(__asan_stack_free_7)
-WRAP_V_WWW(__asan_stack_free_8)
-WRAP_V_WWW(__asan_stack_free_9)
-WRAP_V_WWW(__asan_stack_free_10)
-
-// TODO(timurrrr): Add more interface functions on the as-needed basis.
-
-// ----------------- Memory allocation functions ---------------------
-WRAP_V_W(free)
-WRAP_V_WW(_free_dbg)
-
-WRAP_W_W(malloc)
-WRAP_W_WWWW(_malloc_dbg)
-
-WRAP_W_WW(calloc)
-WRAP_W_WWWWW(_calloc_dbg)
-WRAP_W_WWW(_calloc_impl)
-
-WRAP_W_WW(realloc)
-WRAP_W_WWW(_realloc_dbg)
-WRAP_W_WWW(_recalloc)
-
-WRAP_W_W(_msize)
-
-// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
-
-#endif // ASAN_DLL_THUNK
diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc
index d3e55bff1e6e..c95bc11f6cd3 100644
--- a/lib/asan/asan_fake_stack.cc
+++ b/lib/asan/asan_fake_stack.cc
@@ -27,8 +27,10 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3.
u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
if (class_id <= 6) {
- for (uptr i = 0; i < (1U << class_id); i++)
+ for (uptr i = 0; i < (1U << class_id); i++) {
shadow[i] = magic;
+ SanitizerBreakOptimization(0); // Make sure this does not become memset.
+ }
} else {
// The size class is too big, it's cheaper to poison only size bytes.
PoisonShadow(ptr, size, static_cast<u8>(magic));
@@ -42,21 +44,32 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
stack_size_log = kMinStackSizeLog;
if (stack_size_log > kMaxStackSizeLog)
stack_size_log = kMaxStackSizeLog;
+ uptr size = RequiredSize(stack_size_log);
FakeStack *res = reinterpret_cast<FakeStack *>(
- MmapOrDie(RequiredSize(stack_size_log), "FakeStack"));
+ flags()->uar_noreserve ? MmapNoReserveOrDie(size, "FakeStack")
+ : MmapOrDie(size, "FakeStack"));
res->stack_size_log_ = stack_size_log;
- if (common_flags()->verbosity) {
- u8 *p = reinterpret_cast<u8 *>(res);
- Report("T%d: FakeStack created: %p -- %p stack_size_log: %zd \n",
- GetCurrentTidOrInvalid(), p,
- p + FakeStack::RequiredSize(stack_size_log), stack_size_log);
- }
+ u8 *p = reinterpret_cast<u8 *>(res);
+ VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; "
+ "mmapped %zdK, noreserve=%d \n",
+ GetCurrentTidOrInvalid(), p,
+ p + FakeStack::RequiredSize(stack_size_log), stack_size_log,
+ size >> 10, flags()->uar_noreserve);
return res;
}
-void FakeStack::Destroy() {
+void FakeStack::Destroy(int tid) {
PoisonAll(0);
- UnmapOrDie(this, RequiredSize(stack_size_log_));
+ if (common_flags()->verbosity >= 2) {
+ InternalScopedString str(kNumberOfSizeClasses * 50);
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
+ str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
+ NumberOfFrames(stack_size_log(), class_id));
+ Report("T%d: FakeStack destroyed: %s\n", tid, str.data());
+ }
+ uptr size = RequiredSize(stack_size_log_);
+ FlushUnneededASanShadowMemory(reinterpret_cast<uptr>(this), size);
+ UnmapOrDie(this, size);
}
void FakeStack::PoisonAll(u8 magic) {
@@ -93,7 +106,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
return 0; // We are out of fake stack.
}
-uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
+uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
uptr stack_size_log = this->stack_size_log();
uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
@@ -103,7 +116,10 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
CHECK_LE(base, ptr);
CHECK_LT(ptr, base + (1UL << stack_size_log));
uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
- return base + pos * BytesInSizeClass(class_id);
+ uptr res = base + pos * BytesInSizeClass(class_id);
+ *frame_end = res + BytesInSizeClass(class_id);
+ *frame_beg = res + sizeof(FakeFrame);
+ return res;
}
void FakeStack::HandleNoReturn() {
@@ -197,14 +213,15 @@ ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
+using namespace __asan;
#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \
__asan_stack_malloc_##class_id(uptr size, uptr real_stack) { \
- return __asan::OnMalloc(class_id, size, real_stack); \
+ return OnMalloc(class_id, size, real_stack); \
} \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \
uptr ptr, uptr size, uptr real_stack) { \
- __asan::OnFree(ptr, class_id, size, real_stack); \
+ OnFree(ptr, class_id, size, real_stack); \
}
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
@@ -218,3 +235,23 @@ DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
+ void **end) {
+ FakeStack *fs = reinterpret_cast<FakeStack*>(fake_stack);
+ if (!fs) return 0;
+ uptr frame_beg, frame_end;
+ FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack(
+ reinterpret_cast<uptr>(addr), &frame_beg, &frame_end));
+ if (!frame) return 0;
+ if (frame->magic != kCurrentStackFrameMagic)
+ return 0;
+ if (beg) *beg = reinterpret_cast<void*>(frame_beg);
+ if (end) *end = reinterpret_cast<void*>(frame_end);
+ return reinterpret_cast<void*>(frame->real_stack);
+}
+} // extern "C"
diff --git a/lib/asan/asan_fake_stack.h b/lib/asan/asan_fake_stack.h
index f17ee0268917..3b1d9eb3b57e 100644
--- a/lib/asan/asan_fake_stack.h
+++ b/lib/asan/asan_fake_stack.h
@@ -65,7 +65,7 @@ class FakeStack {
// CTOR: create the FakeStack as a single mmap-ed object.
static FakeStack *Create(uptr stack_size_log);
- void Destroy();
+ void Destroy(int tid);
// stack_size_log is at least 15 (stack_size >= 32K).
static uptr SizeRequiredForFlags(uptr stack_size_log) {
@@ -129,7 +129,11 @@ class FakeStack {
void PoisonAll(u8 magic);
// Return the beginning of the FakeFrame or 0 if the address is not ours.
- uptr AddrIsInFakeStack(uptr addr);
+ uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end);
+ USED uptr AddrIsInFakeStack(uptr addr) {
+ uptr t1, t2;
+ return AddrIsInFakeStack(addr, &t1, &t2);
+ }
// Number of bytes in a fake frame of this size class.
static uptr BytesInSizeClass(uptr class_id) {
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index 89662f28b29c..3df4dd3050bc 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -28,88 +28,44 @@
namespace __asan {
struct Flags {
- // Size (in bytes) of quarantine used to detect use-after-free errors.
- // Lower value may reduce memory usage but increase the chance of
- // false negatives.
+ // Flag descriptions are in asan_rtl.cc.
int quarantine_size;
- // Size (in bytes) of redzones around heap objects.
- // Requirement: redzone >= 32, is a power of two.
int redzone;
- // If set, prints some debugging information and does additional checks.
+ int max_redzone;
bool debug;
- // Controls the way to handle globals (0 - don't detect buffer overflow
- // on globals, 1 - detect buffer overflow, 2 - print data about registered
- // globals).
int report_globals;
- // If set, attempts to catch initialization order issues.
bool check_initialization_order;
- // If set, uses custom wrappers and replacements for libc string functions
- // to find more errors.
bool replace_str;
- // If set, uses custom wrappers for memset/memcpy/memmove intinsics.
bool replace_intrin;
- // Used on Mac only.
bool mac_ignore_invalid_free;
- // Enables stack-use-after-return checking at run-time.
bool detect_stack_use_after_return;
- // The minimal fake stack size log.
- int uar_stack_size_log;
- // ASan allocator flag. max_malloc_fill_size is the maximal amount of bytes
- // that will be filled with malloc_fill_byte on malloc.
+ int min_uar_stack_size_log;
+ int max_uar_stack_size_log;
+ bool uar_noreserve;
int max_malloc_fill_size, malloc_fill_byte;
- // Override exit status if something was reported.
int exitcode;
- // If set, user may manually mark memory regions as poisoned or unpoisoned.
bool allow_user_poisoning;
- // Number of seconds to sleep between printing an error report and
- // terminating application. Useful for debug purposes (when one needs
- // to attach gdb, for example).
int sleep_before_dying;
- // If set, registers ASan custom segv handler.
- bool handle_segv;
- // If set, allows user register segv handler even if ASan registers one.
- bool allow_user_segv_handler;
- // If set, uses alternate stack for signal handling.
- bool use_sigaltstack;
- // Allow the users to work around the bug in Nvidia drivers prior to 295.*.
bool check_malloc_usable_size;
- // If set, explicitly unmaps (huge) shadow at exit.
bool unmap_shadow_on_exit;
- // If set, calls abort() instead of _exit() after printing an error report.
bool abort_on_error;
- // Print various statistics after printing an error message or if atexit=1.
bool print_stats;
- // Print the legend for the shadow bytes.
bool print_legend;
- // If set, prints ASan exit stats even after program terminates successfully.
bool atexit;
- // If set, coverage information will be dumped at shutdown time if the
- // appropriate instrumentation was enabled.
- bool coverage;
- // By default, disable core dumper on 64-bit - it makes little sense
- // to dump 16T+ core.
- bool disable_core;
- // Allow the tool to re-exec the program. This may interfere badly with the
- // debugger.
bool allow_reexec;
- // If set, prints not only thread creation stacks for threads in error report,
- // but also thread creation stacks for threads that created those threads,
- // etc. up to main thread.
bool print_full_thread_history;
- // Poison (or not) the heap memory on [de]allocation. Zero value is useful
- // for benchmarking the allocator or instrumentator.
bool poison_heap;
- // If true, poison partially addressable 8-byte aligned words (default=true).
- // This flag affects heap and global buffers, but not stack buffers.
bool poison_partial;
- // Report errors on malloc/delete, new/free, new/delete[], etc.
+ bool poison_array_cookie;
bool alloc_dealloc_mismatch;
- // If true, assume that memcmp(p1, p2, n) always reads n bytes before
- // comparing p1 and p2.
+ bool new_delete_type_mismatch;
bool strict_memcmp;
- // If true, assume that dynamic initializers can never access globals from
- // other modules, even if the latter are already initialized.
bool strict_init_order;
+ bool start_deactivated;
+ int detect_invalid_pointer_pairs;
+ bool detect_container_overflow;
+ int detect_odr_violation;
+ bool dump_instruction_bytes;
};
extern Flags asan_flags_dont_use_directly;
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index 81699676b574..be111d4fb4cf 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -22,6 +22,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
namespace __asan {
@@ -45,6 +46,14 @@ typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
// Lazy-initialized and never deleted.
static VectorOfGlobals *dynamic_init_globals;
+// We want to remember where a certain range of globals was registered.
+struct GlobalRegistrationSite {
+ u32 stack_id;
+ Global *g_first, *g_last;
+};
+typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
+static GlobalRegistrationSiteVector *global_registration_site_vector;
+
ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
FastPoisonShadow(g->beg, g->size_with_redzone, value);
}
@@ -62,25 +71,74 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) {
}
}
+const uptr kMinimalDistanceFromAnotherGlobal = 64;
+
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
+ if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
+ if (addr >= g.beg + g.size_with_redzone) return false;
+ return true;
+}
+
static void ReportGlobal(const Global &g, const char *prefix) {
- Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
- prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
+ Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
+ prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
g.module_name, g.has_dynamic_init);
+ if (g.location) {
+ Report(" location (%p): name=%s[%p], %d %d\n", g.location,
+ g.location->filename, g.location->filename, g.location->line_no,
+ g.location->column_no);
+ }
}
-bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print,
+ Global *output_global) {
if (!flags()->report_globals) return false;
BlockingMutexLock lock(&mu_for_globals);
bool res = false;
for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
const Global &g = *l->g;
- if (flags()->report_globals >= 2)
- ReportGlobal(g, "Search");
- res |= DescribeAddressRelativeToGlobal(addr, size, g);
+ if (print) {
+ if (flags()->report_globals >= 2)
+ ReportGlobal(g, "Search");
+ res |= DescribeAddressRelativeToGlobal(addr, size, g);
+ } else {
+ if (IsAddressNearGlobal(addr, g)) {
+ CHECK(output_global);
+ *output_global = g;
+ return true;
+ }
+ }
}
return res;
}
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+ return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true,
+ /* output_global */ nullptr);
+}
+
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
+ Global g = {};
+ if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) {
+ internal_strncpy(descr->name, g.name, descr->name_size);
+ descr->region_address = g.beg;
+ descr->region_size = g.size;
+ descr->region_kind = "global";
+ return true;
+ }
+ return false;
+}
+
+u32 FindRegistrationSite(const Global *g) {
+ CHECK(global_registration_site_vector);
+ for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
+ GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
+ if (g >= grs.g_first && g <= grs.g_last)
+ return grs.stack_id;
+ }
+ return 0;
+}
+
// Register a global variable.
// This function may be called more than once for every global
// so we store the globals in a map.
@@ -92,6 +150,20 @@ static void RegisterGlobal(const Global *g) {
CHECK(AddrIsInMem(g->beg));
CHECK(AddrIsAlignedByGranularity(g->beg));
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+ if (flags()->detect_odr_violation) {
+ // Try detecting ODR (One Definition Rule) violation, i.e. the situation
+ // where two globals with the same name are defined in different modules.
+ if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
+ // This check may not be enough: if the first global is much larger
+ // the entire redzone of the second global may be within the first global.
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ if (g->beg == l->g->beg &&
+ (flags()->detect_odr_violation >= 2 || g->size != l->g->size))
+ ReportODRViolation(g, FindRegistrationSite(g),
+ l->g, FindRegistrationSite(l->g));
+ }
+ }
+ }
if (flags()->poison_heap)
PoisonRedZones(*g);
ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
@@ -144,7 +216,18 @@ using namespace __asan; // NOLINT
// Register an array of globals.
void __asan_register_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return;
+ GET_STACK_TRACE_FATAL_HERE;
+ u32 stack_id = StackDepotPut(stack);
BlockingMutexLock lock(&mu_for_globals);
+ if (!global_registration_site_vector)
+ global_registration_site_vector =
+ new(allocator_for_globals) GlobalRegistrationSiteVector(128);
+ GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
+ global_registration_site_vector->push_back(site);
+ if (flags()->report_globals >= 2) {
+ PRINT_CURRENT_STACK();
+ Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
+ }
for (uptr i = 0; i < n; i++) {
RegisterGlobal(&globals[i]);
}
diff --git a/lib/asan/asan_init_version.h b/lib/asan/asan_init_version.h
new file mode 100644
index 000000000000..77aea81bd298
--- /dev/null
+++ b/lib/asan/asan_init_version.h
@@ -0,0 +1,32 @@
+//===-- asan_init_version.h -------------------------------------*- 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.
+//
+// This header defines a versioned __asan_init function to be called at the
+// startup of the instrumented program.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INIT_VERSION_H
+#define ASAN_INIT_VERSION_H
+
+extern "C" {
+ // Every time the ASan ABI changes we also change the version number in the
+ // __asan_init function name. Objects built with incompatible ASan ABI
+ // versions will not link with run-time.
+ // Changes between ABI versions:
+ // v1=>v2: added 'module_name' to __asan_global
+ // v2=>v3: stack frame description (created by the compiler)
+ // contains the function PC as the 3-rd field (see
+ // DescribeAddressIfStack).
+ // v3=>v4: added '__asan_global_source_location' to __asan_global.
+ #define __asan_init __asan_init_v4
+ #define __asan_init_name "__asan_init_v4"
+}
+
+#endif // ASAN_INIT_VERSION_H
diff --git a/lib/asan/asan_intercepted_functions.h b/lib/asan/asan_intercepted_functions.h
deleted file mode 100644
index de42cd6d5ca6..000000000000
--- a/lib/asan/asan_intercepted_functions.h
+++ /dev/null
@@ -1,79 +0,0 @@
-//===-- asan_intercepted_functions.h ----------------------------*- 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.
-//
-// ASan-private header containing prototypes for wrapper functions and wrappers
-//===----------------------------------------------------------------------===//
-#ifndef ASAN_INTERCEPTED_FUNCTIONS_H
-#define ASAN_INTERCEPTED_FUNCTIONS_H
-
-#include "sanitizer_common/sanitizer_platform_interceptors.h"
-
-// Use macro to describe if specific function should be
-// intercepted on a given platform.
-#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
-# define ASAN_INTERCEPT__LONGJMP 1
-# define ASAN_INTERCEPT_STRDUP 1
-# define ASAN_INTERCEPT_INDEX 1
-# define ASAN_INTERCEPT_PTHREAD_CREATE 1
-# define ASAN_INTERCEPT_MLOCKX 1
-#else
-# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
-# define ASAN_INTERCEPT__LONGJMP 0
-# define ASAN_INTERCEPT_STRDUP 0
-# define ASAN_INTERCEPT_INDEX 0
-# define ASAN_INTERCEPT_PTHREAD_CREATE 0
-# define ASAN_INTERCEPT_MLOCKX 0
-#endif
-
-#if SANITIZER_LINUX
-# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
-#else
-# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
-#endif
-
-#if !SANITIZER_MAC
-# define ASAN_INTERCEPT_STRNLEN 1
-#else
-# define ASAN_INTERCEPT_STRNLEN 0
-#endif
-
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-# define ASAN_INTERCEPT_SWAPCONTEXT 1
-#else
-# define ASAN_INTERCEPT_SWAPCONTEXT 0
-#endif
-
-#if !SANITIZER_ANDROID && !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
-#else
-# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
-#endif
-
-#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_SIGLONGJMP 1
-#else
-# define ASAN_INTERCEPT_SIGLONGJMP 0
-#endif
-
-#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT___CXA_THROW 1
-#else
-# define ASAN_INTERCEPT___CXA_THROW 0
-#endif
-
-#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT___CXA_ATEXIT 1
-#else
-# define ASAN_INTERCEPT___CXA_ATEXIT 0
-#endif
-
-#endif // ASAN_INTERCEPTED_FUNCTIONS_H
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index a25827b6b9ae..910cd3addcb0 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -14,14 +14,13 @@
#include "asan_interceptors.h"
#include "asan_allocator.h"
-#include "asan_intercepted_functions.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
-#include "interception/interception.h"
+#include "asan_suppressions.h"
#include "sanitizer_common/sanitizer_libc.h"
namespace __asan {
@@ -36,24 +35,45 @@ static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
return false;
}
+struct AsanInterceptorContext {
+ const char *interceptor_name;
+};
+
// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
// and ASAN_WRITE_RANGE as macro instead of function so
// that no extra frames are created, and stack trace contains
// relevant information only.
// We check all shadow bytes.
-#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
+#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
uptr __offset = (uptr)(offset); \
uptr __size = (uptr)(size); \
uptr __bad = 0; \
+ if (__offset > __offset + __size) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
+ } \
if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
- GET_CURRENT_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, __bad, isWrite, __size); \
+ AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
+ bool suppressed = false; \
+ if (_ctx) { \
+ suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
+ if (!suppressed && HaveStackTraceBasedSuppressions()) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ suppressed = IsStackTraceSuppressed(&stack); \
+ } \
+ } \
+ if (!suppressed) { \
+ GET_CURRENT_PC_BP_SP; \
+ __asan_report_error(pc, bp, sp, __bad, isWrite, __size); \
+ } \
} \
} while (0)
-#define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false)
-#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true)
+#define ASAN_READ_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, false)
+#define ASAN_WRITE_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, true)
// Behavior of functions like "memcpy" or "strcpy" is undefined
// if memory intervals overlap. We report error in this case.
@@ -72,13 +92,6 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
} \
} while (0)
-#define ENSURE_ASAN_INITED() do { \
- CHECK(!asan_init_is_running); \
- if (!asan_inited) { \
- __asan_init(); \
- } \
-} while (0)
-
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
#if ASAN_INTERCEPT_STRNLEN
if (REAL(strnlen) != 0) {
@@ -108,31 +121,34 @@ DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
#if !SANITIZER_MAC
-#define ASAN_INTERCEPT_FUNC(name) \
- do { \
- if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \
- common_flags()->verbosity > 0) \
- Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
+#define ASAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
+ VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \
} while (0)
#else
// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
#define ASAN_INTERCEPT_FUNC(name)
#endif // SANITIZER_MAC
+#define ASAN_INTERCEPTOR_ENTER(ctx, func) \
+ AsanInterceptorContext _ctx = {#func}; \
+ ctx = (void *)&_ctx; \
+ (void) ctx; \
+
#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
-#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
- do { \
- } while (false)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
- ASAN_WRITE_RANGE(ptr, size)
-#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) ASAN_READ_RANGE(ptr, size)
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
- do { \
- if (asan_init_is_running) return REAL(func)(__VA_ARGS__); \
- ctx = 0; \
- (void) ctx; \
- if (SANITIZER_MAC && !asan_inited) return REAL(func)(__VA_ARGS__); \
- ENSURE_ASAN_INITED(); \
+ ASAN_WRITE_RANGE(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ ASAN_READ_RANGE(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ do { \
+ if (asan_init_is_running) \
+ return REAL(func)(__VA_ARGS__); \
+ ASAN_INTERCEPTOR_ENTER(ctx, func); \
+ if (SANITIZER_MAC && UNLIKELY(!asan_inited)) \
+ return REAL(func)(__VA_ARGS__); \
+ ENSURE_ASAN_INITED(); \
} while (false)
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
do { \
@@ -153,10 +169,15 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} while (false)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res) CovUpdateMapping()
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CovUpdateMapping()
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
#include "sanitizer_common/sanitizer_common_interceptors.inc"
-#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
-#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s)
+// Syscall interceptors don't have contexts, we don't support suppressions
+// for them.
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
do { \
(void)(p); \
@@ -169,47 +190,90 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} while (false)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
+struct ThreadStartParam {
+ atomic_uintptr_t t;
+ atomic_uintptr_t is_registered;
+};
+
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
- AsanThread *t = (AsanThread*)arg;
+ ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
+ AsanThread *t = nullptr;
+ while ((t = reinterpret_cast<AsanThread *>(
+ atomic_load(&param->t, memory_order_acquire))) == 0)
+ internal_sched_yield();
SetCurrentThread(t);
- return t->ThreadStart(GetTid());
+ return t->ThreadStart(GetTid(), &param->is_registered);
}
#if ASAN_INTERCEPT_PTHREAD_CREATE
INTERCEPTOR(int, pthread_create, void *thread,
void *attr, void *(*start_routine)(void*), void *arg) {
EnsureMainThreadIDIsCorrect();
- // Strict init-order checking in thread-hostile.
+ // Strict init-order checking is thread-hostile.
if (flags()->strict_init_order)
StopInitOrderChecking();
GET_STACK_TRACE_THREAD;
int detached = 0;
if (attr != 0)
REAL(pthread_attr_getdetachstate)(attr, &detached);
-
- u32 current_tid = GetCurrentTidOrInvalid();
- AsanThread *t = AsanThread::Create(start_routine, arg);
- CreateThreadContextArgs args = { t, &stack };
- asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
- return REAL(pthread_create)(thread, attr, asan_thread_start, t);
+ ThreadStartParam param;
+ atomic_store(&param.t, 0, memory_order_relaxed);
+ atomic_store(&param.is_registered, 0, memory_order_relaxed);
+ int result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
+ if (result == 0) {
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+ atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
+ // Wait until the AsanThread object is initialized and the ThreadRegistry
+ // entry is in "started" state. One reason for this is that after this
+ // interceptor exits, the child thread's stack may be the only thing holding
+ // the |arg| pointer. This may cause LSan to report a leak if leak checking
+ // happens at a point when the interceptor has already exited, but the stack
+ // range for the child thread is not yet known.
+ while (atomic_load(&param.is_registered, memory_order_acquire) == 0)
+ internal_sched_yield();
+ }
+ return result;
}
#endif // ASAN_INTERCEPT_PTHREAD_CREATE
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
+
+#if SANITIZER_ANDROID
+INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
+ if (!AsanInterceptsSignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
+ return REAL(bsd_signal)(signum, handler);
+ }
+ return 0;
+}
+#else
INTERCEPTOR(void*, signal, int signum, void *handler) {
- if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
+ if (!AsanInterceptsSignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
return REAL(signal)(signum, handler);
}
return 0;
}
+#endif
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
struct sigaction *oldact) {
- if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
+ if (!AsanInterceptsSignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
return REAL(sigaction)(signum, act, oldact);
}
return 0;
}
+
+namespace __sanitizer {
+int real_sigaction(int signum, const void *act, void *oldact) {
+ return REAL(sigaction)(signum, (const struct sigaction *)act,
+ (struct sigaction *)oldact);
+}
+} // namespace __sanitizer
+
#elif SANITIZER_POSIX
// We need to have defined REAL(sigaction) on posix systems.
DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
@@ -279,52 +343,45 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
}
#endif
-// intercept mlock and friends.
-// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
-// All functions return 0 (success).
-static void MlockIsUnsupported() {
- static bool printed = false;
- if (printed) return;
- printed = true;
- if (common_flags()->verbosity > 0) {
- Printf("INFO: AddressSanitizer ignores "
- "mlock/mlockall/munlock/munlockall\n");
- }
-}
-
-INTERCEPTOR(int, mlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
-}
-
-INTERCEPTOR(int, munlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
+#if SANITIZER_WINDOWS
+INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(RaiseException));
+ __asan_handle_no_return();
+ REAL(RaiseException)(a, b, c, d);
}
-INTERCEPTOR(int, mlockall, int flags) {
- MlockIsUnsupported();
- return 0;
+INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(_except_handler3));
+ __asan_handle_no_return();
+ return REAL(_except_handler3)(a, b, c, d);
}
-INTERCEPTOR(int, munlockall, void) {
- MlockIsUnsupported();
- return 0;
+#if ASAN_DYNAMIC
+// This handler is named differently in -MT and -MD CRTs.
+#define _except_handler4 _except_handler4_common
+#endif
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(_except_handler4));
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
}
+#endif
static inline int CharCmp(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
}
INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
- if (!asan_inited) return internal_memcmp(a1, a2, size);
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memcmp);
+ if (UNLIKELY(!asan_inited)) return internal_memcmp(a1, a2, size);
ENSURE_ASAN_INITED();
if (flags()->replace_intrin) {
if (flags()->strict_memcmp) {
// Check the entire regions even if the first bytes of the buffers are
// different.
- ASAN_READ_RANGE(a1, size);
- ASAN_READ_RANGE(a2, size);
+ ASAN_READ_RANGE(ctx, a1, size);
+ ASAN_READ_RANGE(ctx, a2, size);
// Fallthrough to REAL(memcmp) below.
} else {
unsigned char c1 = 0, c2 = 0;
@@ -336,51 +393,81 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
c2 = s2[i];
if (c1 != c2) break;
}
- ASAN_READ_RANGE(s1, Min(i + 1, size));
- ASAN_READ_RANGE(s2, Min(i + 1, size));
+ ASAN_READ_RANGE(ctx, s1, Min(i + 1, size));
+ ASAN_READ_RANGE(ctx, s2, Min(i + 1, size));
return CharCmp(c1, c2);
}
}
return REAL(memcmp(a1, a2, size));
}
-#define MEMMOVE_BODY { \
- if (!asan_inited) return internal_memmove(to, from, size); \
- if (asan_init_is_running) { \
- return REAL(memmove)(to, from, size); \
- } \
- ENSURE_ASAN_INITED(); \
- if (flags()->replace_intrin) { \
- ASAN_READ_RANGE(from, size); \
- ASAN_WRITE_RANGE(to, size); \
- } \
- return internal_memmove(to, from, size); \
+// memcpy is called during __asan_init() from the internals of printf(...).
+// We do not treat memcpy with to==from as a bug.
+// See http://llvm.org/bugs/show_bug.cgi?id=11763.
+#define ASAN_MEMCPY_IMPL(ctx, to, from, size) do { \
+ if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
+ if (asan_init_is_running) { \
+ return REAL(memcpy)(to, from, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ if (to != from) { \
+ CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
+ } \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return REAL(memcpy)(to, from, size); \
+ } while (0)
+
+
+void *__asan_memcpy(void *to, const void *from, uptr size) {
+ ASAN_MEMCPY_IMPL(nullptr, to, from, size);
+}
+
+// memset is called inside Printf.
+#define ASAN_MEMSET_IMPL(ctx, block, c, size) do { \
+ if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
+ if (asan_init_is_running) { \
+ return REAL(memset)(block, c, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_WRITE_RANGE(ctx, block, size); \
+ } \
+ return REAL(memset)(block, c, size); \
+ } while (0)
+
+void *__asan_memset(void *block, int c, uptr size) {
+ ASAN_MEMSET_IMPL(nullptr, block, c, size);
+}
+
+#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) do { \
+ if (UNLIKELY(!asan_inited)) \
+ return internal_memmove(to, from, size); \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return internal_memmove(to, from, size); \
+ } while (0)
+
+void *__asan_memmove(void *to, const void *from, uptr size) {
+ ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
}
-INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) MEMMOVE_BODY
+INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memmove);
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size);
+}
INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memcpy);
#if !SANITIZER_MAC
- if (!asan_inited) return internal_memcpy(to, from, size);
- // memcpy is called during __asan_init() from the internals
- // of printf(...).
- if (asan_init_is_running) {
- return REAL(memcpy)(to, from, size);
- }
- ENSURE_ASAN_INITED();
- if (flags()->replace_intrin) {
- if (to != from) {
- // We do not treat memcpy with to==from as a bug.
- // See http://llvm.org/bugs/show_bug.cgi?id=11763.
- CHECK_RANGES_OVERLAP("memcpy", to, size, from, size);
- }
- ASAN_READ_RANGE(from, size);
- ASAN_WRITE_RANGE(to, size);
- }
- // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8, so
- // calling REAL(memcpy) here leads to infinite recursion.
- // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
- return internal_memcpy(to, from, size);
+ ASAN_MEMCPY_IMPL(ctx, to, from, size);
#else
// At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced
// with WRAP(memcpy). As a result, false positives are reported for memmove()
@@ -388,25 +475,20 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
// ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with
// internal_memcpy(), which may lead to crashes, see
// http://llvm.org/bugs/show_bug.cgi?id=16362.
- MEMMOVE_BODY
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size);
#endif // !SANITIZER_MAC
}
INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
- if (!asan_inited) return internal_memset(block, c, size);
- // memset is called inside Printf.
- if (asan_init_is_running) {
- return REAL(memset)(block, c, size);
- }
- ENSURE_ASAN_INITED();
- if (flags()->replace_intrin) {
- ASAN_WRITE_RANGE(block, size);
- }
- return REAL(memset)(block, c, size);
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memset);
+ ASAN_MEMSET_IMPL(ctx, block, c, size);
}
INTERCEPTOR(char*, strchr, const char *str, int c) {
- if (!asan_inited) return internal_strchr(str, c);
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strchr);
+ if (UNLIKELY(!asan_inited)) return internal_strchr(str, c);
// strchr is called inside create_purgeable_zone() when MallocGuardEdges=1 is
// used.
if (asan_init_is_running) {
@@ -416,7 +498,7 @@ INTERCEPTOR(char*, strchr, const char *str, int c) {
char *result = REAL(strchr)(str, c);
if (flags()->replace_str) {
uptr bytes_read = (result ? result - str : REAL(strlen)(str)) + 1;
- ASAN_READ_RANGE(str, bytes_read);
+ ASAN_READ_RANGE(ctx, str, bytes_read);
}
return result;
}
@@ -438,13 +520,15 @@ DEFINE_REAL(char*, index, const char *string, int c)
// For both strcat() and strncat() we need to check the validity of |to|
// argument irrespective of the |from| length.
INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT
ENSURE_ASAN_INITED();
if (flags()->replace_str) {
uptr from_length = REAL(strlen)(from);
- ASAN_READ_RANGE(from, from_length + 1);
+ ASAN_READ_RANGE(ctx, from, from_length + 1);
uptr to_length = REAL(strlen)(to);
- ASAN_READ_RANGE(to, to_length);
- ASAN_WRITE_RANGE(to + to_length, from_length + 1);
+ ASAN_READ_RANGE(ctx, to, to_length);
+ ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
// If the copying actually happens, the |from| string should not overlap
// with the resulting string starting at |to|, which has a length of
// to_length + from_length + 1.
@@ -457,14 +541,16 @@ INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
}
INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strncat);
ENSURE_ASAN_INITED();
if (flags()->replace_str) {
uptr from_length = MaybeRealStrnlen(from, size);
uptr copy_length = Min(size, from_length + 1);
- ASAN_READ_RANGE(from, copy_length);
+ ASAN_READ_RANGE(ctx, from, copy_length);
uptr to_length = REAL(strlen)(to);
- ASAN_READ_RANGE(to, to_length);
- ASAN_WRITE_RANGE(to + to_length, from_length + 1);
+ ASAN_READ_RANGE(ctx, to, to_length);
+ ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
if (from_length > 0) {
CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
from, copy_length);
@@ -474,8 +560,10 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
}
INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT
#if SANITIZER_MAC
- if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT
+ if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT
#endif
// strcpy is called from malloc_default_purgeable_zone()
// in __asan::ReplaceSystemAlloc() on Mac.
@@ -486,19 +574,21 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
if (flags()->replace_str) {
uptr from_size = REAL(strlen)(from) + 1;
CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
- ASAN_READ_RANGE(from, from_size);
- ASAN_WRITE_RANGE(to, from_size);
+ ASAN_READ_RANGE(ctx, from, from_size);
+ ASAN_WRITE_RANGE(ctx, to, from_size);
}
return REAL(strcpy)(to, from); // NOLINT
}
#if ASAN_INTERCEPT_STRDUP
INTERCEPTOR(char*, strdup, const char *s) {
- if (!asan_inited) return internal_strdup(s);
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strdup);
+ if (UNLIKELY(!asan_inited)) return internal_strdup(s);
ENSURE_ASAN_INITED();
uptr length = REAL(strlen)(s);
if (flags()->replace_str) {
- ASAN_READ_RANGE(s, length + 1);
+ ASAN_READ_RANGE(ctx, s, length + 1);
}
GET_STACK_TRACE_MALLOC;
void *new_mem = asan_malloc(length + 1, &stack);
@@ -507,47 +597,55 @@ INTERCEPTOR(char*, strdup, const char *s) {
}
#endif
-INTERCEPTOR(uptr, strlen, const char *s) {
- if (!asan_inited) return internal_strlen(s);
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strlen);
+ if (UNLIKELY(!asan_inited)) return internal_strlen(s);
// strlen is called from malloc_default_purgeable_zone()
// in __asan::ReplaceSystemAlloc() on Mac.
if (asan_init_is_running) {
return REAL(strlen)(s);
}
ENSURE_ASAN_INITED();
- uptr length = REAL(strlen)(s);
+ SIZE_T length = REAL(strlen)(s);
if (flags()->replace_str) {
- ASAN_READ_RANGE(s, length + 1);
+ ASAN_READ_RANGE(ctx, s, length + 1);
}
return length;
}
-INTERCEPTOR(uptr, wcslen, const wchar_t *s) {
- uptr length = REAL(wcslen)(s);
+INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
+ SIZE_T length = REAL(wcslen)(s);
if (!asan_init_is_running) {
ENSURE_ASAN_INITED();
- ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t));
+ ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
}
return length;
}
INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
ENSURE_ASAN_INITED();
if (flags()->replace_str) {
uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
- ASAN_READ_RANGE(from, from_size);
- ASAN_WRITE_RANGE(to, size);
+ ASAN_READ_RANGE(ctx, from, from_size);
+ ASAN_WRITE_RANGE(ctx, to, size);
}
return REAL(strncpy)(to, from, size);
}
#if ASAN_INTERCEPT_STRNLEN
INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strnlen);
ENSURE_ASAN_INITED();
uptr length = REAL(strnlen)(s, maxlen);
if (flags()->replace_str) {
- ASAN_READ_RANGE(s, Min(length + 1, maxlen));
+ ASAN_READ_RANGE(ctx, s, Min(length + 1, maxlen));
}
return length;
}
@@ -565,13 +663,15 @@ static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
// We get this symbol by skipping leading blanks and optional +/- sign.
while (IsSpace(*nptr)) nptr++;
if (*nptr == '+' || *nptr == '-') nptr++;
- *endptr = (char*)nptr;
+ *endptr = const_cast<char *>(nptr);
}
CHECK(*endptr >= nptr);
}
INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
char **endptr, int base) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strtol);
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
return REAL(strtol)(nptr, endptr, base);
@@ -583,14 +683,16 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
}
if (IsValidStrtolBase(base)) {
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
}
return result;
}
INTERCEPTOR(int, atoi, const char *nptr) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atoi);
#if SANITIZER_MAC
- if (!asan_inited) return REAL(atoi)(nptr);
+ if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr);
#endif
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
@@ -603,13 +705,15 @@ INTERCEPTOR(int, atoi, const char *nptr) {
// different from int). So, we just imitate this behavior.
int result = REAL(strtol)(nptr, &real_endptr, 10);
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atol);
#if SANITIZER_MAC
- if (!asan_inited) return REAL(atol)(nptr);
+ if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr);
#endif
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
@@ -618,13 +722,15 @@ INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
char *real_endptr;
long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
char **endptr, int base) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strtoll);
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
return REAL(strtoll)(nptr, endptr, base);
@@ -639,12 +745,14 @@ INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
// if base is valid.
if (IsValidStrtolBase(base)) {
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
}
return result;
}
INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atoll);
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
return REAL(atoll)(nptr);
@@ -652,7 +760,7 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
char *real_endptr;
long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
@@ -666,7 +774,7 @@ static void AtCxaAtexit(void *unused) {
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
#if SANITIZER_MAC
- if (!asan_inited) return REAL(__cxa_atexit)(func, arg, dso_handle);
+ if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
#endif
ENSURE_ASAN_INITED();
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
@@ -675,27 +783,50 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
+#if ASAN_INTERCEPT_FORK
+INTERCEPTOR(int, fork, void) {
+ ENSURE_ASAN_INITED();
+ if (common_flags()->coverage) CovBeforeFork();
+ int pid = REAL(fork)();
+ if (common_flags()->coverage) CovAfterFork(pid);
+ return pid;
+}
+#endif // ASAN_INTERCEPT_FORK
+
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
DWORD (__stdcall *start_routine)(void*), void* arg,
DWORD thr_flags, void* tid) {
- // Strict init-order checking in thread-hostile.
+ // Strict init-order checking is thread-hostile.
if (flags()->strict_init_order)
StopInitOrderChecking();
GET_STACK_TRACE_THREAD;
- u32 current_tid = GetCurrentTidOrInvalid();
- AsanThread *t = AsanThread::Create(start_routine, arg);
- CreateThreadContextArgs args = { t, &stack };
bool detached = false; // FIXME: how can we determine it on Windows?
- asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
- return REAL(CreateThread)(security, stack_size,
- asan_thread_start, t, thr_flags, tid);
+ ThreadStartParam param;
+ atomic_store(&param.t, 0, memory_order_relaxed);
+ atomic_store(&param.is_registered, 0, memory_order_relaxed);
+ DWORD result = REAL(CreateThread)(security, stack_size, asan_thread_start,
+ &param, thr_flags, tid);
+ if (result) {
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+ atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
+ // The pthread_create interceptor waits here, so we do the same for
+ // consistency.
+ while (atomic_load(&param.is_registered, memory_order_acquire) == 0)
+ internal_sched_yield();
+ }
+ return result;
}
namespace __asan {
void InitializeWindowsInterceptors() {
ASAN_INTERCEPT_FUNC(CreateThread);
+ ASAN_INTERCEPT_FUNC(RaiseException);
+ ASAN_INTERCEPT_FUNC(_except_handler3);
+ ASAN_INTERCEPT_FUNC(_except_handler4);
}
} // namespace __asan
@@ -707,7 +838,7 @@ void InitializeAsanInterceptors() {
static bool was_called_once;
CHECK(was_called_once == false);
was_called_once = true;
- SANITIZER_COMMON_INTERCEPTORS_INIT;
+ InitializeCommonInterceptors();
// Intercept mem* functions.
ASAN_INTERCEPT_FUNC(memcmp);
@@ -743,20 +874,16 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(strtoll);
#endif
-#if ASAN_INTERCEPT_MLOCKX
- // Intercept mlock/munlock.
- ASAN_INTERCEPT_FUNC(mlock);
- ASAN_INTERCEPT_FUNC(munlock);
- ASAN_INTERCEPT_FUNC(mlockall);
- ASAN_INTERCEPT_FUNC(munlockall);
-#endif
-
// Intecept signal- and jump-related functions.
ASAN_INTERCEPT_FUNC(longjmp);
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
ASAN_INTERCEPT_FUNC(sigaction);
+#if SANITIZER_ANDROID
+ ASAN_INTERCEPT_FUNC(bsd_signal);
+#else
ASAN_INTERCEPT_FUNC(signal);
#endif
+#endif
#if ASAN_INTERCEPT_SWAPCONTEXT
ASAN_INTERCEPT_FUNC(swapcontext);
#endif
@@ -769,7 +896,7 @@ void InitializeAsanInterceptors() {
// Intercept exception handling functions.
#if ASAN_INTERCEPT___CXA_THROW
- INTERCEPT_FUNCTION(__cxa_throw);
+ ASAN_INTERCEPT_FUNC(__cxa_throw);
#endif
// Intercept threading-related functions
@@ -782,14 +909,16 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(__cxa_atexit);
#endif
+#if ASAN_INTERCEPT_FORK
+ ASAN_INTERCEPT_FUNC(fork);
+#endif
+
// Some Windows-specific interceptors.
#if SANITIZER_WINDOWS
InitializeWindowsInterceptors();
#endif
- if (common_flags()->verbosity > 0) {
- Report("AddressSanitizer: libc interceptors initialized\n");
- }
+ VReport(1, "AddressSanitizer: libc interceptors initialized\n");
}
} // namespace __asan
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index 91830aa145a9..ee3b82aa7ef9 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -16,12 +16,75 @@
#include "asan_internal.h"
#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+
+// Use macro to describe if specific function should be
+// intercepted on a given platform.
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
+# define ASAN_INTERCEPT__LONGJMP 1
+# define ASAN_INTERCEPT_STRDUP 1
+# define ASAN_INTERCEPT_INDEX 1
+# define ASAN_INTERCEPT_PTHREAD_CREATE 1
+# define ASAN_INTERCEPT_FORK 1
+#else
+# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
+# define ASAN_INTERCEPT__LONGJMP 0
+# define ASAN_INTERCEPT_STRDUP 0
+# define ASAN_INTERCEPT_INDEX 0
+# define ASAN_INTERCEPT_PTHREAD_CREATE 0
+# define ASAN_INTERCEPT_FORK 0
+#endif
+
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
+#else
+# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
+#endif
+
+#if !SANITIZER_MAC
+# define ASAN_INTERCEPT_STRNLEN 1
+#else
+# define ASAN_INTERCEPT_STRNLEN 0
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+# define ASAN_INTERCEPT_SWAPCONTEXT 1
+#else
+# define ASAN_INTERCEPT_SWAPCONTEXT 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
+#else
+# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_SIGLONGJMP 1
+#else
+# define ASAN_INTERCEPT_SIGLONGJMP 0
+#endif
+
+// Android bug: https://code.google.com/p/android/issues/detail?id=61799
+#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
+ !(SANITIZER_ANDROID && defined(__i386))
+# define ASAN_INTERCEPT___CXA_THROW 1
+#else
+# define ASAN_INTERCEPT___CXA_THROW 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT___CXA_ATEXIT 1
+#else
+# define ASAN_INTERCEPT___CXA_ATEXIT 0
+#endif
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
DECLARE_REAL(char*, strchr, const char *str, int c)
-DECLARE_REAL(uptr, strlen, const char *s)
+DECLARE_REAL(SIZE_T, strlen, const char *s)
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
@@ -33,6 +96,13 @@ namespace __asan {
void InitializeAsanInterceptors();
+#define ENSURE_ASAN_INITED() do { \
+ CHECK(!asan_init_is_running); \
+ if (UNLIKELY(!asan_inited)) { \
+ AsanInitFromRtl(); \
+ } \
+} while (0)
+
} // namespace __asan
#endif // ASAN_INTERCEPTORS_H
diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h
index 5c1d025296fb..edaf44d7893a 100644
--- a/lib/asan/asan_interface_internal.h
+++ b/lib/asan/asan_interface_internal.h
@@ -17,21 +17,24 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "asan_init_version.h"
+
using __sanitizer::uptr;
extern "C" {
// This function should be called at the very beginning of the process,
// before any instrumented code is executed and before any call to malloc.
- // Everytime the asan ABI changes we also change the version number in this
- // name. Objects build with incompatible asan ABI version
- // will not link with run-time.
- // Changes between ABI versions:
- // v1=>v2: added 'module_name' to __asan_global
- // v2=>v3: stack frame description (created by the compiler)
- // contains the function PC as the 3-rd field (see
- // DescribeAddressIfStack).
- SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3();
- #define __asan_init __asan_init_v3
+ // Please note that __asan_init is a macro that is replaced with
+ // __asan_init_vXXX at compile-time.
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_init();
+
+ // This structure is used to describe the source location of a place where
+ // global was defined.
+ struct __asan_global_source_location {
+ const char *filename;
+ int line_no;
+ int column_no;
+ };
// This structure describes an instrumented global variable.
struct __asan_global {
@@ -42,6 +45,8 @@ extern "C" {
const char *module_name; // Module name as a C string. This pointer is a
// unique identifier of a module.
uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
+ __asan_global_source_location *location; // Source location of a global,
+ // or NULL if it is unknown.
};
// These two functions should be called by the instrumented code.
@@ -77,7 +82,7 @@ extern "C" {
void __asan_unpoison_memory_region(void const volatile *addr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
- bool __asan_address_is_poisoned(void const volatile *addr);
+ int __asan_address_is_poisoned(void const volatile *addr);
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_region_is_poisoned(uptr beg, uptr size);
@@ -86,8 +91,41 @@ extern "C" {
void __asan_describe_address(uptr addr);
SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_report_present();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_pc();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_bp();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_sp();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_address();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_get_report_access_type();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_access_size();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char * __asan_get_report_description();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char * __asan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address, uptr *region_size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
+ u32 *thread_id);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
+ u32 *thread_id);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
void __asan_report_error(uptr pc, uptr bp, uptr sp,
- uptr addr, bool is_write, uptr access_size);
+ uptr addr, int is_write, uptr access_size);
SANITIZER_INTERFACE_ATTRIBUTE
int __asan_set_error_exit_code(int exit_code);
@@ -99,32 +137,46 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __asan_on_error();
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
- int out_size);
-
- SANITIZER_INTERFACE_ATTRIBUTE
- uptr __asan_get_estimated_allocated_size(uptr size);
-
- SANITIZER_INTERFACE_ATTRIBUTE bool __asan_get_ownership(const void *p);
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_allocated_size(const void *p);
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_current_allocated_bytes();
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_heap_size();
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_bytes();
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_unmapped_bytes();
SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ const char* __asan_default_options();
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size);
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ void __asan_free_hook(void *ptr);
-
// Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return
SANITIZER_INTERFACE_ATTRIBUTE
extern int __asan_option_detect_stack_use_after_return;
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ extern uptr *__asan_test_only_reported_buggy_pointer;
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memcpy(void *dst, const void *src, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memset(void *s, int c, uptr n);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memmove(void* dest, const void* src, uptr n);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_cxx_array_cookie(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_load_cxx_array_cookie(uptr *p);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_intra_object_redzone(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_intra_object_redzone(uptr p, uptr size);
} // extern "C"
#endif // ASAN_INTERFACE_INTERNAL_H
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 70e55ea0afef..65d4a47d3d9e 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -30,26 +30,11 @@
// Build-time configuration options.
-// If set, asan will install its own SEGV signal handler.
-#ifndef ASAN_NEEDS_SEGV
-# if SANITIZER_ANDROID == 1
-# define ASAN_NEEDS_SEGV 0
-# else
-# define ASAN_NEEDS_SEGV 1
-# endif
-#endif
-
// If set, asan will intercept C++ exception api call(s).
#ifndef ASAN_HAS_EXCEPTIONS
# define ASAN_HAS_EXCEPTIONS 1
#endif
-// If set, asan uses the values of SHADOW_SCALE and SHADOW_OFFSET
-// provided by the instrumented objects. Otherwise constants are used.
-#ifndef ASAN_FLEXIBLE_MAPPING_AND_OFFSET
-# define ASAN_FLEXIBLE_MAPPING_AND_OFFSET 0
-#endif
-
// If set, values like allocator chunk size, as well as defaults for some flags
// will be changed towards less memory overhead.
#ifndef ASAN_LOW_MEMORY
@@ -60,36 +45,56 @@
# endif
#endif
-#ifndef ASAN_USE_PREINIT_ARRAY
-# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
+#ifndef ASAN_DYNAMIC
+# ifdef PIC
+# define ASAN_DYNAMIC 1
+# else
+# define ASAN_DYNAMIC 0
+# endif
#endif
// All internal functions in asan reside inside the __asan namespace
// to avoid namespace collisions with the user programs.
-// Seperate namespace also makes it simpler to distinguish the asan run-time
+// Separate namespace also makes it simpler to distinguish the asan run-time
// functions from the instrumented user code in a profile.
namespace __asan {
class AsanThread;
using __sanitizer::StackTrace;
+struct SignalContext {
+ void *context;
+ uptr addr;
+ uptr pc;
+ uptr sp;
+ uptr bp;
+
+ SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) :
+ context(context), addr(addr), pc(pc), sp(sp), bp(bp) {
+ }
+
+ // Creates signal context in a platform-specific manner.
+ static SignalContext Create(void *siginfo, void *context);
+};
+
+void AsanInitFromRtl();
+
// asan_rtl.cc
void NORETURN ShowStatsAndAbort();
-void ReplaceOperatorsNewAndDelete();
// asan_malloc_linux.cc / asan_malloc_mac.cc
void ReplaceSystemMalloc();
// asan_linux.cc / asan_mac.cc / asan_win.cc
void *AsanDoesNotSupportStaticLinkage();
+void AsanCheckDynamicRTPrereqs();
+void AsanCheckIncompatibleRT();
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
+void AsanOnSIGSEGV(int, void *siginfo, void *context);
void MaybeReexec();
bool AsanInterceptsSignal(int signum);
-void SetAlternateSignalStack();
-void UnsetAlternateSignalStack();
-void InstallSignalHandlers();
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
void AsanPlatformThreadInit();
void StopInitOrderChecking();
@@ -102,7 +107,11 @@ void PlatformTSDDtor(void *tsd);
void AppendToErrorMessageBuffer(const char *buffer);
-// Platfrom-specific options.
+void ParseExtraActivationFlags();
+
+void *AsanDlSymNext(const char *sym);
+
+// Platform-specific options.
#if SANITIZER_MAC
bool PlatformHasDifferentMemcpyAndMemmove();
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
@@ -114,9 +123,9 @@ bool PlatformHasDifferentMemcpyAndMemmove();
// Add convenient macro for interface functions that may be represented as
// weak hooks.
#define ASAN_MALLOC_HOOK(ptr, size) \
- if (&__asan_malloc_hook) __asan_malloc_hook(ptr, size)
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
#define ASAN_FREE_HOOK(ptr) \
- if (&__asan_free_hook) __asan_free_hook(ptr)
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
#define ASAN_ON_ERROR() \
if (&__asan_on_error) __asan_on_error()
@@ -136,9 +145,14 @@ const int kAsanStackPartialRedzoneMagic = 0xf4;
const int kAsanStackAfterReturnMagic = 0xf5;
const int kAsanInitializationOrderMagic = 0xf6;
const int kAsanUserPoisonedMemoryMagic = 0xf7;
+const int kAsanContiguousContainerOOBMagic = 0xfc;
const int kAsanStackUseAfterScopeMagic = 0xf8;
const int kAsanGlobalRedzoneMagic = 0xf9;
const int kAsanInternalHeapMagic = 0xfe;
+const int kAsanArrayCookieMagic = 0xac;
+const int kAsanIntraObjectRedzone = 0xbb;
+const int kAsanAllocaLeftMagic = 0xca;
+const int kAsanAllocaRightMagic = 0xcb;
static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
static const uptr kRetiredStackFrameMagic = 0x45E0360E;
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 39eec3bfd301..fdd009c960d8 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -13,11 +13,13 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_freebsd.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
@@ -26,18 +28,43 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
+#include <dlfcn.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <unwind.h>
-#if !SANITIZER_ANDROID
-// FIXME: where to get ucontext on Android?
-#include <sys/ucontext.h>
+#if SANITIZER_FREEBSD
+#include <sys/link_elf.h>
#endif
+#if SANITIZER_ANDROID || SANITIZER_FREEBSD
+#include <ucontext.h>
extern "C" void* _DYNAMIC;
+#else
+#include <sys/ucontext.h>
+#include <link.h>
+#endif
+
+// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
+// 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
+ __FreeBSD_version <= 902001 // v9.2
+#define ucontext_t xucontext_t
+#endif
+
+typedef enum {
+ ASAN_RT_VERSION_UNDEFINED = 0,
+ ASAN_RT_VERSION_DYNAMIC,
+ ASAN_RT_VERSION_STATIC,
+} asan_rt_version_t;
+
+// FIXME: perhaps also store abi version here?
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+asan_rt_version_t __asan_rt_version;
+}
namespace __asan {
@@ -50,38 +77,126 @@ void *AsanDoesNotSupportStaticLinkage() {
return &_DYNAMIC; // defined in link.h
}
-void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#if SANITIZER_ANDROID
- *pc = *sp = *bp = 0;
-#elif defined(__arm__)
+// FIXME: should we do anything for Android?
+void AsanCheckDynamicRTPrereqs() {}
+void AsanCheckIncompatibleRT() {}
+#else
+static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ // Continue until the first dynamic library is found
+ if (!info->dlpi_name || info->dlpi_name[0] == 0)
+ return 0;
+
+ // Ignore vDSO
+ if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
+ return 0;
+
+ *(const char **)data = info->dlpi_name;
+ return 1;
+}
+
+static bool IsDynamicRTName(const char *libname) {
+ return internal_strstr(libname, "libclang_rt.asan") ||
+ internal_strstr(libname, "libasan.so");
+}
+
+static void ReportIncompatibleRT() {
+ Report("Your application is linked against incompatible ASan runtimes.\n");
+ Die();
+}
+
+void AsanCheckDynamicRTPrereqs() {
+ // Ensure that dynamic RT is the first DSO in the list
+ const char *first_dso_name = 0;
+ dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
+ if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
+ Report("ASan runtime does not come first in initial library list; "
+ "you should either link runtime to your application or "
+ "manually preload it with LD_PRELOAD.\n");
+ Die();
+ }
+}
+
+void AsanCheckIncompatibleRT() {
+ if (ASAN_DYNAMIC) {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
+ ReportIncompatibleRT();
+ }
+ } else {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ // Ensure that dynamic runtime is not present. We should detect it
+ // as early as possible, otherwise ASan interceptors could bind to
+ // the functions in dynamic ASan runtime instead of the functions in
+ // system libraries, causing crashes later in ASan initialization.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ char filename[128];
+ while (proc_maps.Next(0, 0, 0, filename, sizeof(filename), 0)) {
+ if (IsDynamicRTName(filename)) {
+ Report("Your application is linked against "
+ "incompatible ASan runtimes.\n");
+ Die();
+ }
+ }
+ __asan_rt_version = ASAN_RT_VERSION_STATIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
+ ReportIncompatibleRT();
+ }
+ }
+}
+#endif // SANITIZER_ANDROID
+
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
+#if defined(__arm__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.arm_pc;
*bp = ucontext->uc_mcontext.arm_fp;
*sp = ucontext->uc_mcontext.arm_sp;
-# elif defined(__hppa__)
+#elif defined(__aarch64__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.pc;
+ *bp = ucontext->uc_mcontext.regs[29];
+ *sp = ucontext->uc_mcontext.sp;
+#elif defined(__hppa__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.sc_iaoq[0];
/* GCC uses %r3 whenever a frame pointer is needed. */
*bp = ucontext->uc_mcontext.sc_gr[3];
*sp = ucontext->uc_mcontext.sc_gr[30];
-# elif defined(__x86_64__)
+#elif defined(__x86_64__)
+# if SANITIZER_FREEBSD
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.mc_rip;
+ *bp = ucontext->uc_mcontext.mc_rbp;
+ *sp = ucontext->uc_mcontext.mc_rsp;
+# else
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
*bp = ucontext->uc_mcontext.gregs[REG_RBP];
*sp = ucontext->uc_mcontext.gregs[REG_RSP];
-# elif defined(__i386__)
+# endif
+#elif defined(__i386__)
+# if SANITIZER_FREEBSD
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.mc_eip;
+ *bp = ucontext->uc_mcontext.mc_ebp;
+ *sp = ucontext->uc_mcontext.mc_esp;
+# else
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
*bp = ucontext->uc_mcontext.gregs[REG_EBP];
*sp = ucontext->uc_mcontext.gregs[REG_ESP];
-# elif defined(__powerpc__) || defined(__powerpc64__)
+# endif
+#elif defined(__powerpc__) || defined(__powerpc64__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.regs->nip;
*sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
// The powerpc{,64}-linux ABIs do not specify r31 as the frame
// pointer, but GCC always uses r31 when we need a frame pointer.
*bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
-# elif defined(__sparc__)
+#elif defined(__sparc__)
ucontext_t *ucontext = (ucontext_t*)context;
uptr *stk_ptr;
# if defined (__arch64__)
@@ -95,7 +210,7 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
stk_ptr = (uptr *) *sp;
*bp = stk_ptr[15];
# endif
-# elif defined(__mips__)
+#elif defined(__mips__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[31];
*bp = ucontext->uc_mcontext.gregs[30];
@@ -106,7 +221,7 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
}
bool AsanInterceptsSignal(int signum) {
- return signum == SIGSEGV && flags()->handle_segv;
+ return signum == SIGSEGV && common_flags()->handle_segv;
}
void AsanPlatformThreadInit() {
@@ -125,6 +240,10 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
}
#endif
+void *AsanDlSymNext(const char *sym) {
+ return dlsym(RTLD_NEXT, sym);
+}
+
} // namespace __asan
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index e27d70adb81e..ae0fa15b6523 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -17,12 +17,12 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
-#include "asan_mac.h"
#include "asan_mapping.h"
#include "asan_stack.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mac.h"
#include <crt_externs.h> // for _NSGetArgv
#include <dlfcn.h> // for dladdr()
@@ -53,43 +53,6 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
# endif // SANITIZER_WORDSIZE
}
-MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
-
-MacosVersion GetMacosVersionInternal() {
- int mib[2] = { CTL_KERN, KERN_OSRELEASE };
- char version[100];
- uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
- for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
- // Get the version length.
- CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
- CHECK_LT(len, maxlen);
- CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
- switch (version[0]) {
- case '9': return MACOS_VERSION_LEOPARD;
- case '1': {
- switch (version[1]) {
- case '0': return MACOS_VERSION_SNOW_LEOPARD;
- case '1': return MACOS_VERSION_LION;
- case '2': return MACOS_VERSION_MOUNTAIN_LION;
- case '3': return MACOS_VERSION_MAVERICKS;
- default: return MACOS_VERSION_UNKNOWN;
- }
- }
- default: return MACOS_VERSION_UNKNOWN;
- }
-}
-
-MacosVersion GetMacosVersion() {
- atomic_uint32_t *cache =
- reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
- MacosVersion result =
- static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
- if (result == MACOS_VERSION_UNINITIALIZED) {
- result = GetMacosVersionInternal();
- atomic_store(cache, result, memory_order_release);
- }
- return result;
-}
bool PlatformHasDifferentMemcpyAndMemmove() {
// On OS X 10.7 memcpy() and memmove() are both resolved
@@ -151,7 +114,7 @@ void MaybeReexec() {
internal_strlen(dyld_insert_libraries) : 0;
uptr fname_len = internal_strlen(info.dli_fname);
if (!dyld_insert_libraries ||
- !REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
+ !REAL(strstr)(dyld_insert_libraries, StripModuleName(info.dli_fname))) {
// DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
// library.
char program_name[1024];
@@ -174,12 +137,10 @@ void MaybeReexec() {
// Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
}
- if (common_flags()->verbosity >= 1) {
- Report("exec()-ing the program with\n");
- Report("%s=%s\n", kDyldInsertLibraries, new_env);
- Report("to enable ASan wrappers.\n");
- Report("Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
- }
+ VReport(1, "exec()-ing the program with\n");
+ VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
+ VReport(1, "to enable ASan wrappers.\n");
+ VReport(1, "Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
execv(program_name, *_NSGetArgv());
} else {
// DYLD_INSERT_LIBRARIES is set and contains the runtime library.
@@ -238,8 +199,15 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckDynamicRTPrereqs() {}
+
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckIncompatibleRT() {}
+
bool AsanInterceptsSignal(int signum) {
- return (signum == SIGSEGV || signum == SIGBUS) && flags()->handle_segv;
+ return (signum == SIGSEGV || signum == SIGBUS) &&
+ common_flags()->handle_segv;
}
void AsanPlatformThreadInit() {
@@ -296,9 +264,8 @@ ALWAYS_INLINE
void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
AsanThread *t = GetCurrentThread();
if (!t) {
- t = AsanThread::Create(0, 0);
- CreateThreadContextArgs args = { t, stack };
- asanThreadRegistry().CreateThread(*(uptr*)t, true, parent_tid, &args);
+ t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
+ parent_tid, stack, /* detached */ true);
t->Init();
asanThreadRegistry().StartThread(t->tid(), 0, 0);
SetCurrentThread(t);
@@ -311,11 +278,10 @@ extern "C"
void asan_dispatch_call_block_and_release(void *block) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *context = (asan_block_context_t*)block;
- if (common_flags()->verbosity >= 2) {
- Report("asan_dispatch_call_block_and_release(): "
- "context: %p, pthread_self: %p\n",
- block, pthread_self());
- }
+ VReport(2,
+ "asan_dispatch_call_block_and_release(): "
+ "context: %p, pthread_self: %p\n",
+ block, pthread_self());
asan_register_worker_thread(context->parent_tid, &stack);
// Call the original dispatcher for the block.
context->func(context->block);
@@ -330,7 +296,7 @@ using namespace __asan; // NOLINT
// The caller retains control of the allocated context.
extern "C"
asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
- StackTrace *stack) {
+ BufferedStackTrace *stack) {
asan_block_context_t *asan_ctxt =
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
asan_ctxt->block = ctxt;
@@ -349,10 +315,10 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
if (common_flags()->verbosity >= 2) { \
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
asan_ctxt, pthread_self()); \
- PRINT_CURRENT_STACK(); \
- } \
- return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
- asan_dispatch_call_block_and_release); \
+ PRINT_CURRENT_STACK(); \
+ } \
+ return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
+ asan_dispatch_call_block_and_release); \
}
INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
@@ -388,7 +354,6 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
#if !defined(MISSING_BLOCKS_SUPPORT)
extern "C" {
-// FIXME: consolidate these declarations with asan_intercepted_functions.h.
void dispatch_async(dispatch_queue_t dq, void(^work)(void));
void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
void(^work)(void));
@@ -408,32 +373,44 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
work(); \
}
+// Forces the compiler to generate a frame pointer in the function.
+#define ENABLE_FRAME_POINTER \
+ do { \
+ volatile uptr enable_fp; \
+ enable_fp = GET_CURRENT_FRAME(); \
+ } while (0)
+
INTERCEPTOR(void, dispatch_async,
dispatch_queue_t dq, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_async)(dq, asan_block);
}
INTERCEPTOR(void, dispatch_group_async,
dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_group_async)(dg, dq, asan_block);
}
INTERCEPTOR(void, dispatch_after,
dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_after)(when, queue, asan_block);
}
INTERCEPTOR(void, dispatch_source_set_cancel_handler,
dispatch_source_t ds, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
}
INTERCEPTOR(void, dispatch_source_set_event_handler,
dispatch_source_t ds, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_source_set_event_handler)(ds, asan_block);
}
diff --git a/lib/asan/asan_mac.h b/lib/asan/asan_mac.h
deleted file mode 100644
index 827b8b001699..000000000000
--- a/lib/asan/asan_mac.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//===-- asan_mac.h ----------------------------------------------*- 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.
-//
-// Mac-specific ASan definitions.
-//===----------------------------------------------------------------------===//
-#ifndef ASAN_MAC_H
-#define ASAN_MAC_H
-
-// CF_RC_BITS, the layout of CFRuntimeBase and __CFStrIsConstant are internal
-// and subject to change in further CoreFoundation versions. Apple does not
-// guarantee any binary compatibility from release to release.
-
-// See http://opensource.apple.com/source/CF/CF-635.15/CFInternal.h
-#if defined(__BIG_ENDIAN__)
-#define CF_RC_BITS 0
-#endif
-
-#if defined(__LITTLE_ENDIAN__)
-#define CF_RC_BITS 3
-#endif
-
-// See http://opensource.apple.com/source/CF/CF-635.15/CFRuntime.h
-typedef struct __CFRuntimeBase {
- uptr _cfisa;
- u8 _cfinfo[4];
-#if __LP64__
- u32 _rc;
-#endif
-} CFRuntimeBase;
-
-enum MacosVersion {
- MACOS_VERSION_UNINITIALIZED = 0,
- MACOS_VERSION_UNKNOWN,
- MACOS_VERSION_LEOPARD,
- MACOS_VERSION_SNOW_LEOPARD,
- MACOS_VERSION_LION,
- MACOS_VERSION_MOUNTAIN_LION,
- MACOS_VERSION_MAVERICKS
-};
-
-// Used by asan_malloc_mac.cc and asan_mac.cc
-extern "C" void __CFInitialize();
-
-namespace __asan {
-
-MacosVersion GetMacosVersion();
-void MaybeReplaceCFAllocator();
-
-} // namespace __asan
-
-#endif // ASAN_MAC_H
diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index 24b7f6977927..46a6a9db4a81 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/lib/asan/asan_malloc_linux.cc
@@ -15,48 +15,14 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_stack.h"
-#if SANITIZER_ANDROID
-DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
-DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void*, realloc, void *ptr, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void*, memalign, uptr boundary, uptr size)
-
-struct MallocDebug {
- void* (*malloc)(uptr bytes);
- void (*free)(void* mem);
- void* (*calloc)(uptr n_elements, uptr elem_size);
- void* (*realloc)(void* oldMem, uptr bytes);
- void* (*memalign)(uptr alignment, uptr bytes);
-};
-
-const MallocDebug asan_malloc_dispatch ALIGNED(32) = {
- WRAP(malloc), WRAP(free), WRAP(calloc), WRAP(realloc), WRAP(memalign)
-};
-
-extern "C" const MallocDebug* __libc_malloc_dispatch;
-
-namespace __asan {
-void ReplaceSystemMalloc() {
- __libc_malloc_dispatch = &asan_malloc_dispatch;
-}
-} // namespace __asan
-
-#else // ANDROID
-
-namespace __asan {
-void ReplaceSystemMalloc() {
-}
-} // namespace __asan
-#endif // ANDROID
-
// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan; // NOLINT
@@ -76,7 +42,7 @@ INTERCEPTOR(void*, malloc, uptr size) {
}
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
- if (!asan_inited) {
+ if (UNLIKELY(!asan_inited)) {
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
const uptr kCallocPoolSize = 1024;
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
@@ -101,8 +67,17 @@ INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
}
-INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s)
- ALIAS("memalign");
+INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(boundary, size, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
+ DTLS_on_libc_memalign(res, size * boundary);
+ return res;
+}
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
GET_CURRENT_PC_BP_SP;
@@ -148,4 +123,64 @@ INTERCEPTOR(void, malloc_stats, void) {
__asan_print_accumulated_stats();
}
-#endif // SANITIZER_LINUX
+#if SANITIZER_ANDROID
+// Format of __libc_malloc_dispatch has changed in Android L.
+// While we are moving towards a solution that does not depend on bionic
+// internals, here is something to support both K* and L releases.
+struct MallocDebugK {
+ void *(*malloc)(uptr bytes);
+ void (*free)(void *mem);
+ void *(*calloc)(uptr n_elements, uptr elem_size);
+ void *(*realloc)(void *oldMem, uptr bytes);
+ void *(*memalign)(uptr alignment, uptr bytes);
+ uptr (*malloc_usable_size)(void *mem);
+};
+
+struct MallocDebugL {
+ void *(*calloc)(uptr n_elements, uptr elem_size);
+ void (*free)(void *mem);
+ fake_mallinfo (*mallinfo)(void);
+ void *(*malloc)(uptr bytes);
+ uptr (*malloc_usable_size)(void *mem);
+ void *(*memalign)(uptr alignment, uptr bytes);
+ int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
+ void* (*pvalloc)(uptr size);
+ void *(*realloc)(void *oldMem, uptr bytes);
+ void* (*valloc)(uptr size);
+};
+
+ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
+ WRAP(malloc), WRAP(free), WRAP(calloc),
+ WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
+
+ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
+ WRAP(calloc), WRAP(free), WRAP(mallinfo),
+ WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),
+ WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),
+ WRAP(valloc)};
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+ void **__libc_malloc_dispatch_p =
+ (void **)AsanDlSymNext("__libc_malloc_dispatch");
+ if (__libc_malloc_dispatch_p) {
+ // Decide on K vs L dispatch format by the presence of
+ // __libc_malloc_default_dispatch export in libc.
+ void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
+ if (default_dispatch_p)
+ *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
+ else
+ *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
+ }
+}
+} // namespace __asan
+
+#else // SANITIZER_ANDROID
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+}
+} // namespace __asan
+#endif // SANITIZER_ANDROID
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index f9f08f0201c2..79b6dfae10f6 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -24,10 +24,10 @@
#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_internal.h"
-#include "asan_mac.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
+#include "sanitizer_common/sanitizer_mac.h"
// Similar code is used in Google Perftools,
// http://code.google.com/p/google-perftools.
@@ -41,7 +41,7 @@ static malloc_zone_t asan_zone;
INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
vm_size_t start_size, unsigned zone_flags) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
uptr page_size = GetPageSizeCached();
uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
@@ -60,39 +60,39 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
}
INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
return &asan_zone;
}
INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
// FIXME: ASan should support purgeable allocations.
// https://code.google.com/p/address-sanitizer/issues/detail?id=139
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
return &asan_zone;
}
INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
// for now.
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
}
INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
// for now.
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
// Must return 0 if the contents were not purged since the last call to
// malloc_make_purgeable().
return 0;
}
INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
// Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
size_t buflen = 6 + (name ? internal_strlen(name) : 0);
- InternalScopedBuffer<char> new_name(buflen);
+ InternalScopedString new_name(buflen);
if (name && zone->introspect == asan_zone.introspect) {
- internal_snprintf(new_name.data(), buflen, "asan-%s", name);
+ new_name.append("asan-%s", name);
name = new_name.data();
}
@@ -102,44 +102,44 @@ INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
}
INTERCEPTOR(void *, malloc, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
void *res = asan_malloc(size, &stack);
return res;
}
INTERCEPTOR(void, free, void *ptr) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
if (!ptr) return;
GET_STACK_TRACE_FREE;
asan_free(ptr, &stack, FROM_MALLOC);
}
INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
INTERCEPTOR(void *, valloc, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
}
INTERCEPTOR(size_t, malloc_good_size, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
return asan_zone.introspect->good_size(&asan_zone, size);
}
INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
CHECK(memptr);
GET_STACK_TRACE_MALLOC;
void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
@@ -159,7 +159,7 @@ size_t mz_size(malloc_zone_t* zone, const void* ptr) {
}
void *mz_malloc(malloc_zone_t *zone, size_t size) {
- if (!asan_inited) {
+ if (UNLIKELY(!asan_inited)) {
CHECK(system_malloc_zone);
return malloc_zone_malloc(system_malloc_zone, size);
}
@@ -168,7 +168,7 @@ void *mz_malloc(malloc_zone_t *zone, size_t size) {
}
void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
- if (!asan_inited) {
+ if (UNLIKELY(!asan_inited)) {
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
const size_t kCallocPoolSize = 1024;
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
@@ -184,7 +184,7 @@ void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
}
void *mz_valloc(malloc_zone_t *zone, size_t size) {
- if (!asan_inited) {
+ if (UNLIKELY(!asan_inited)) {
CHECK(system_malloc_zone);
return malloc_zone_valloc(system_malloc_zone, size);
}
@@ -242,7 +242,7 @@ void mz_destroy(malloc_zone_t* zone) {
#if defined(MAC_OS_X_VERSION_10_6) && \
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
- if (!asan_inited) {
+ if (UNLIKELY(!asan_inited)) {
CHECK(system_malloc_zone);
return malloc_zone_memalign(system_malloc_zone, align, size);
}
diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc
index 73e4c825092c..c99e31234951 100644
--- a/lib/asan/asan_malloc_win.cc
+++ b/lib/asan/asan_malloc_win.cc
@@ -23,71 +23,77 @@
#include <stddef.h>
-// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan; // NOLINT
-// FIXME: Simply defining functions with the same signature in *.obj
-// files overrides the standard functions in *.lib
-// This works well for simple helloworld-like tests but might need to be
-// revisited in the future.
+// MT: Simply defining functions with the same signature in *.obj
+// files overrides the standard functions in the CRT.
+// MD: Memory allocation functions are defined in the CRT .dll,
+// so we have to intercept them before they are called for the first time.
+
+#if ASAN_DYNAMIC
+# define ALLOCATION_FUNCTION_ATTRIBUTE
+#else
+# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+#endif
extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void free(void *ptr) {
GET_STACK_TRACE_FREE;
return asan_free(ptr, &stack, FROM_MALLOC);
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void _free_dbg(void* ptr, int) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void _free_dbg(void *ptr, int) {
free(ptr);
}
+ALLOCATION_FUNCTION_ATTRIBUTE
void cfree(void *ptr) {
- CHECK(!"cfree() should not be used on Windows?");
+ CHECK(!"cfree() should not be used on Windows");
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *malloc(size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _malloc_dbg(size_t size, int , const char*, int) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_malloc_dbg(size_t size, int, const char *, int) {
return malloc(size);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *calloc(size_t nmemb, size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
- return calloc(n, size);
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
+ return calloc(nmemb, size);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
return calloc(nmemb, size);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *realloc(void *ptr, size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *_realloc_dbg(void *ptr, size_t size, int) {
CHECK(!"_realloc_dbg should not exist!");
return 0;
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _recalloc(void* p, size_t n, size_t elem_size) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_recalloc(void *p, size_t n, size_t elem_size) {
if (!p)
return calloc(n, elem_size);
const size_t size = n * elem_size;
@@ -96,13 +102,28 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
return realloc(p, size);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
size_t _msize(void *ptr) {
GET_CURRENT_PC_BP_SP;
(void)sp;
return asan_malloc_usable_size(ptr, pc, bp);
}
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_expand(void *memblock, size_t size) {
+ // _expand is used in realloc-like functions to resize the buffer if possible.
+ // We don't want memory to stand still while resizing buffers, so return 0.
+ return 0;
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_expand_dbg(void *memblock, size_t size) {
+ return _expand(memblock, size);
+}
+
+// TODO(timurrrr): Might want to add support for _aligned_* allocation
+// functions to detect a bit more bugs. Those functions seem to wrap malloc().
+
int _CrtDbgReport(int, const char*, int,
const char*, const char*, ...) {
ShowStatsAndAbort();
@@ -118,37 +139,38 @@ int _CrtSetReportMode(int, int) {
}
} // extern "C"
-using __interception::GetRealFunctionAddress;
-
-// We don't want to include "windows.h" in this file to avoid extra attributes
-// set on malloc/free etc (e.g. dllimport), so declare a few things manually:
-extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
- DWORD prot, DWORD *old_prot);
-const int PAGE_EXECUTE_READWRITE = 0x40;
-
namespace __asan {
void ReplaceSystemMalloc() {
-#if defined(_DLL)
-# ifdef _WIN64
-# error ReplaceSystemMalloc was not tested on x64
-# endif
- char *crt_malloc;
- if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
- // Replace malloc in the CRT dll with a jump to our malloc.
- DWORD old_prot, unused;
- CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
- REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16); // just in case.
-
- ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
- crt_malloc[0] = 0xE9; // jmp, should be followed by an offset.
- REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
-
- CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
-
- // FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
- }
-
- // FIXME: investigate whether anything else is needed.
+#if defined(ASAN_DYNAMIC)
+ // We don't check the result because CRT might not be used in the process.
+ __interception::OverrideFunction("free", (uptr)free);
+ __interception::OverrideFunction("malloc", (uptr)malloc);
+ __interception::OverrideFunction("_malloc_crt", (uptr)malloc);
+ __interception::OverrideFunction("calloc", (uptr)calloc);
+ __interception::OverrideFunction("_calloc_crt", (uptr)calloc);
+ __interception::OverrideFunction("realloc", (uptr)realloc);
+ __interception::OverrideFunction("_realloc_crt", (uptr)realloc);
+ __interception::OverrideFunction("_recalloc", (uptr)_recalloc);
+ __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
+ __interception::OverrideFunction("_msize", (uptr)_msize);
+ __interception::OverrideFunction("_expand", (uptr)_expand);
+
+ // Override different versions of 'operator new' and 'operator delete'.
+ // No need to override the nothrow versions as they just wrap the throw
+ // versions.
+ // FIXME: Unfortunately, MSVC miscompiles the statements that take the
+ // addresses of the array versions of these operators,
+ // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
+ // We might want to try to work around this by [inline] assembly or compiling
+ // parts of the RTL with Clang.
+ void *(*op_new)(size_t sz) = operator new;
+ void (*op_delete)(void *p) = operator delete;
+ void *(*op_array_new)(size_t sz) = operator new[];
+ void (*op_array_delete)(void *p) = operator delete[];
+ __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
+ __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
+ __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
+ __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
#endif
}
} // namespace __asan
diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h
index 1fecaeb35e1e..2746754152b6 100644
--- a/lib/asan/asan_mapping.h
+++ b/lib/asan/asan_mapping.h
@@ -43,54 +43,87 @@
// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
//
-// Default Linux/i386 mapping:
+// Default Linux/i386 mapping on x86_64 machine:
// || `[0x40000000, 0xffffffff]` || HighMem ||
// || `[0x28000000, 0x3fffffff]` || HighShadow ||
// || `[0x24000000, 0x27ffffff]` || ShadowGap ||
// || `[0x20000000, 0x23ffffff]` || LowShadow ||
// || `[0x00000000, 0x1fffffff]` || LowMem ||
//
+// Default Linux/i386 mapping on i386 machine
+// (addresses starting with 0xc0000000 are reserved
+// for kernel and thus not sanitized):
+// || `[0x38000000, 0xbfffffff]` || HighMem ||
+// || `[0x27000000, 0x37ffffff]` || HighShadow ||
+// || `[0x24000000, 0x26ffffff]` || ShadowGap ||
+// || `[0x20000000, 0x23ffffff]` || LowShadow ||
+// || `[0x00000000, 0x1fffffff]` || LowMem ||
+//
// Default Linux/MIPS mapping:
-// || `[0x2aaa8000, 0xffffffff]` || HighMem ||
-// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow ||
-// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap ||
-// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow ||
-// || `[0x00000000, 0x0aaa7fff]` || LowMem ||
+// || `[0x2aaa0000, 0xffffffff]` || HighMem ||
+// || `[0x0fff4000, 0x2aa9ffff]` || HighShadow ||
+// || `[0x0bff4000, 0x0fff3fff]` || ShadowGap ||
+// || `[0x0aaa0000, 0x0bff3fff]` || LowShadow ||
+// || `[0x00000000, 0x0aa9ffff]` || LowMem ||
+//
+// Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
+// || `[0x500000000000, 0x7fffffffffff]` || HighMem ||
+// || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow ||
+// || `[0x480000000000, 0x49ffffffffff]` || ShadowGap ||
+// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
+// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
+//
+// Shadow mapping on FreeBSD/i386 with SHADOW_OFFSET == 0x40000000:
+// || `[0x60000000, 0xffffffff]` || HighMem ||
+// || `[0x4c000000, 0x5fffffff]` || HighShadow ||
+// || `[0x48000000, 0x4bffffff]` || ShadowGap ||
+// || `[0x40000000, 0x47ffffff]` || LowShadow ||
+// || `[0x00000000, 0x3fffffff]` || LowMem ||
static const u64 kDefaultShadowScale = 3;
-static const u64 kDefaultShadowOffset32 = 1ULL << 29;
+static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
+static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
static const u64 kDefaultShadowOffset64 = 1ULL << 44;
static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
+static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
+static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
+static const u64 kMIPS64_ShadowOffset64 = 1ULL << 36;
static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
-static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000;
+static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
+static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
-#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
-extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale;
-extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
-# define SHADOW_SCALE (__asan_mapping_scale)
-# define SHADOW_OFFSET (__asan_mapping_offset)
+#define SHADOW_SCALE kDefaultShadowScale
+#if SANITIZER_ANDROID
+# define SHADOW_OFFSET (0)
#else
-# define SHADOW_SCALE kDefaultShadowScale
-# if SANITIZER_ANDROID
-# define SHADOW_OFFSET (0)
-# else
-# if SANITIZER_WORDSIZE == 32
-# if defined(__mips__)
-# define SHADOW_OFFSET kMIPS32_ShadowOffset32
-# else
-# define SHADOW_OFFSET kDefaultShadowOffset32
-# endif
+# if SANITIZER_WORDSIZE == 32
+# if defined(__mips__)
+# define SHADOW_OFFSET kMIPS32_ShadowOffset32
+# elif SANITIZER_FREEBSD
+# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
# else
-# if defined(__powerpc64__)
+# if SANITIZER_IOS
+# define SHADOW_OFFSET kIosShadowOffset32
+# else
+# define SHADOW_OFFSET kDefaultShadowOffset32
+# endif
+# endif
+# else
+# if defined(__aarch64__)
+# define SHADOW_OFFSET kAArch64_ShadowOffset64
+# elif defined(__powerpc64__)
# define SHADOW_OFFSET kPPC64_ShadowOffset64
-# elif SANITIZER_MAC
-# define SHADOW_OFFSET kDefaultShadowOffset64
-# else
-# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
-# endif
+# elif SANITIZER_FREEBSD
+# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
+# elif SANITIZER_MAC
+# define SHADOW_OFFSET kDefaultShadowOffset64
+# elif defined(__mips64)
+# define SHADOW_OFFSET kMIPS64_ShadowOffset64
+# else
+# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
# endif
# endif
-#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
+#endif
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc
index d5eb6eca9321..e48bdaf03dd3 100644
--- a/lib/asan/asan_new_delete.cc
+++ b/lib/asan/asan_new_delete.cc
@@ -16,20 +16,21 @@
#include "asan_internal.h"
#include "asan_stack.h"
+#include "interception/interception.h"
+
#include <stddef.h>
-namespace __asan {
-// This function is a no-op. We need it to make sure that object file
-// with our replacements will actually be loaded from static ASan
-// run-time library at link-time.
-void ReplaceOperatorsNewAndDelete() { }
-}
+// C++ operators can't have visibility attributes on Windows.
+#if SANITIZER_WINDOWS
+# define CXX_OPERATOR_ATTRIBUTE
+#else
+# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
+#endif
using namespace __asan; // NOLINT
-// On Android new() goes through malloc interceptors.
-// See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !SANITIZER_ANDROID
+// This code has issues on OSX.
+// See https://code.google.com/p/address-sanitizer/issues/detail?id=131.
// Fake std::nothrow_t to avoid including <new>.
namespace std {
@@ -48,14 +49,23 @@ struct nothrow_t {};
// To make sure that C++ allocation/deallocation operators are overridden on
// OS X we need to intercept them using their mangled names.
#if !SANITIZER_MAC
-INTERCEPTOR_ATTRIBUTE
+// FreeBSD prior v9.2 have wrong definition of 'size_t'.
+// http://svnweb.freebsd.org/base?view=revision&revision=232261
+#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
+#include <sys/param.h>
+#if __FreeBSD_version <= 902001 // v9.2
+#define size_t unsigned
+#endif // __FreeBSD_version
+#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
+
+CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
-INTERCEPTOR_ATTRIBUTE
+CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
-INTERCEPTOR_ATTRIBUTE
+CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW); }
-INTERCEPTOR_ATTRIBUTE
+CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
@@ -79,16 +89,32 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
asan_free(ptr, &stack, type);
#if !SANITIZER_MAC
-INTERCEPTOR_ATTRIBUTE
-void operator delete(void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW); }
-INTERCEPTOR_ATTRIBUTE
-void operator delete[](void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW_BR); }
-INTERCEPTOR_ATTRIBUTE
-void operator delete(void *ptr, std::nothrow_t const&)
-{ OPERATOR_DELETE_BODY(FROM_NEW); }
-INTERCEPTOR_ATTRIBUTE
-void operator delete[](void *ptr, std::nothrow_t const&)
-{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr) throw() {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr) throw() {
+ OPERATOR_DELETE_BODY(FROM_NEW_BR);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(FROM_NEW_BR);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, size_t size) throw() {
+ GET_STACK_TRACE_FREE;
+ asan_sized_free(ptr, size, &stack, FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, size_t size) throw() {
+ GET_STACK_TRACE_FREE;
+ asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
+}
#else // SANITIZER_MAC
INTERCEPTOR(void, _ZdlPv, void *ptr) {
@@ -104,5 +130,3 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY(FROM_NEW_BR);
}
#endif
-
-#endif
diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc
index 280aaeb909a3..1c6e92f69c65 100644
--- a/lib/asan/asan_poisoning.cc
+++ b/lib/asan/asan_poisoning.cc
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_flags.h"
@@ -50,6 +52,36 @@ struct ShadowSegmentEndpoint {
}
};
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+ // Since asan's mapping is compacting, the shadow chunk may be
+ // not page-aligned, so we only flush the page-aligned portion.
+ uptr page_size = GetPageSizeCached();
+ uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
+ uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
+ FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
+}
+
+void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
+ uptr end = ptr + size;
+ if (common_flags()->verbosity) {
+ Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n",
+ poison ? "" : "un", ptr, end, size);
+ if (common_flags()->verbosity >= 2)
+ PRINT_CURRENT_STACK();
+ }
+ CHECK(size);
+ CHECK_LE(size, 4096);
+ CHECK(IsAligned(end, SHADOW_GRANULARITY));
+ if (!IsAligned(ptr, SHADOW_GRANULARITY)) {
+ *(u8 *)MemToShadow(ptr) =
+ poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0;
+ ptr |= SHADOW_GRANULARITY - 1;
+ ptr++;
+ }
+ for (; ptr < end; ptr += SHADOW_GRANULARITY)
+ *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0;
+}
+
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
@@ -69,10 +101,8 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) {
if (!flags()->allow_user_poisoning || size == 0) return;
uptr beg_addr = (uptr)addr;
uptr end_addr = beg_addr + size;
- if (common_flags()->verbosity >= 1) {
- Printf("Trying to poison memory region [%p, %p)\n",
- (void*)beg_addr, (void*)end_addr);
- }
+ VPrintf(1, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr,
+ (void *)end_addr);
ShadowSegmentEndpoint beg(beg_addr);
ShadowSegmentEndpoint end(end_addr);
if (beg.chunk == end.chunk) {
@@ -111,10 +141,8 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
if (!flags()->allow_user_poisoning || size == 0) return;
uptr beg_addr = (uptr)addr;
uptr end_addr = beg_addr + size;
- if (common_flags()->verbosity >= 1) {
- Printf("Trying to unpoison memory region [%p, %p)\n",
- (void*)beg_addr, (void*)end_addr);
- }
+ VPrintf(1, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr,
+ (void *)end_addr);
ShadowSegmentEndpoint beg(beg_addr);
ShadowSegmentEndpoint end(end_addr);
if (beg.chunk == end.chunk) {
@@ -139,7 +167,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
}
}
-bool __asan_address_is_poisoned(void const volatile *addr) {
+int __asan_address_is_poisoned(void const volatile *addr) {
return __asan::AddressIsPoisoned((uptr)addr);
}
@@ -148,6 +176,7 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
uptr end = beg + size;
if (!AddrIsInMem(beg)) return beg;
if (!AddrIsInMem(end)) return end;
+ CHECK_LT(beg, end);
uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY);
uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY);
uptr shadow_beg = MemToShadow(aligned_b);
@@ -219,6 +248,36 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
*p = x;
}
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_cxx_array_cookie(uptr p) {
+ if (SANITIZER_WORDSIZE != 64) return;
+ if (!flags()->poison_array_cookie) return;
+ uptr s = MEM_TO_SHADOW(p);
+ *reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_load_cxx_array_cookie(uptr *p) {
+ if (SANITIZER_WORDSIZE != 64) return *p;
+ if (!flags()->poison_array_cookie) return *p;
+ uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p));
+ u8 sval = *reinterpret_cast<u8*>(s);
+ if (sval == kAsanArrayCookieMagic) return *p;
+ // If sval is not kAsanArrayCookieMagic it can only be freed memory,
+ // which means that we are going to get double-free. So, return 0 to avoid
+ // infinite loop of destructors. We don't want to report a double-free here
+ // though, so print a warning just in case.
+ // CHECK_EQ(sval, kAsanHeapFreeMagic);
+ if (sval == kAsanHeapFreeMagic) {
+ Report("AddressSanitizer: loaded array cookie from free-d memory; "
+ "expect a double-free report\n");
+ return 0;
+ }
+ // The cookie may remain unpoisoned if e.g. it comes from a custom
+ // operator new defined inside a class.
+ return *p;
+}
+
// This is a simplified version of __asan_(un)poison_memory_region, which
// assumes that left border of region to be poisoned is properly aligned.
static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
@@ -245,55 +304,113 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
}
void __asan_poison_stack_memory(uptr addr, uptr size) {
- if (common_flags()->verbosity > 0)
- Report("poisoning: %p %zx\n", (void*)addr, size);
+ VReport(1, "poisoning: %p %zx\n", (void *)addr, size);
PoisonAlignedStackMemory(addr, size, true);
}
void __asan_unpoison_stack_memory(uptr addr, uptr size) {
- if (common_flags()->verbosity > 0)
- Report("unpoisoning: %p %zx\n", (void*)addr, size);
+ VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size);
PoisonAlignedStackMemory(addr, size, false);
}
-void __sanitizer_annotate_contiguous_container(void *beg_p, void *end_p,
- void *old_mid_p,
- void *new_mid_p) {
+void __sanitizer_annotate_contiguous_container(const void *beg_p,
+ const void *end_p,
+ const void *old_mid_p,
+ const void *new_mid_p) {
+ if (!flags()->detect_container_overflow) return;
+ VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
+ new_mid_p);
uptr beg = reinterpret_cast<uptr>(beg_p);
- uptr end= reinterpret_cast<uptr>(end_p);
+ uptr end = reinterpret_cast<uptr>(end_p);
uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
uptr granularity = SHADOW_GRANULARITY;
- CHECK(beg <= end && beg <= old_mid && beg <= new_mid && old_mid <= end &&
- new_mid <= end && IsAligned(beg, granularity));
+ if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end &&
+ IsAligned(beg, granularity))) {
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid,
+ &stack);
+ }
CHECK_LE(end - beg,
FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
- uptr b = new_mid;
- uptr b1 = RoundDownTo(b, granularity);
- uptr b2 = RoundUpTo(b, granularity);
- uptr d = old_mid;
- uptr d1 = RoundDownTo(d, granularity);
- uptr d2 = RoundUpTo(d, granularity);
+ uptr d1 = RoundDownTo(old_mid, granularity);
+ // uptr d2 = RoundUpTo(old_mid, granularity);
// Currently we should be in this state:
// [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
// Make a quick sanity check that we are indeed in this state.
- if (d1 != d2)
- CHECK_EQ(*(u8*)MemToShadow(d1), d - d1);
+ //
+ // FIXME: Two of these three checks are disabled until we fix
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=258.
+ // if (d1 != d2)
+ // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
if (a + granularity <= d1)
CHECK_EQ(*(u8*)MemToShadow(a), 0);
- if (d2 + granularity <= c && c <= end)
- CHECK_EQ(*(u8 *)MemToShadow(c - granularity), kAsanUserPoisonedMemoryMagic);
+ // if (d2 + granularity <= c && c <= end)
+ // CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
+ // kAsanContiguousContainerOOBMagic);
+ uptr b1 = RoundDownTo(new_mid, granularity);
+ uptr b2 = RoundUpTo(new_mid, granularity);
// New state:
// [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
- // FIXME: we may want to have a separate poison magic value.
PoisonShadow(a, b1 - a, 0);
- PoisonShadow(b2, c - b2, kAsanUserPoisonedMemoryMagic);
+ PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
if (b1 != b2) {
CHECK_EQ(b2 - b1, granularity);
- *(u8*)MemToShadow(b1) = static_cast<u8>(b - b1);
+ *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
}
}
+
+int __sanitizer_verify_contiguous_container(const void *beg_p,
+ const void *mid_p,
+ const void *end_p) {
+ if (!flags()->detect_container_overflow) return 1;
+ uptr beg = reinterpret_cast<uptr>(beg_p);
+ uptr end = reinterpret_cast<uptr>(end_p);
+ uptr mid = reinterpret_cast<uptr>(mid_p);
+ CHECK_LE(beg, mid);
+ CHECK_LE(mid, end);
+ // Check some bytes starting from beg, some bytes around mid, and some bytes
+ // ending with end.
+ uptr kMaxRangeToCheck = 32;
+ uptr r1_beg = beg;
+ uptr r1_end = Min(end + kMaxRangeToCheck, mid);
+ uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
+ uptr r2_end = Min(end, mid + kMaxRangeToCheck);
+ uptr r3_beg = Max(end - kMaxRangeToCheck, mid);
+ uptr r3_end = end;
+ for (uptr i = r1_beg; i < r1_end; i++)
+ if (AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = r2_beg; i < mid; i++)
+ if (AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = mid; i < r2_end; i++)
+ if (!AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = r3_beg; i < r3_end; i++)
+ if (!AddressIsPoisoned(i))
+ return 0;
+ return 1;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
+ AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) {
+ AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false);
+}
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+bool WordIsPoisoned(uptr addr) {
+ return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0);
+}
+}
+
diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h
index fbac21196b8f..feda1a984544 100644
--- a/lib/asan/asan_poisoning.h
+++ b/lib/asan/asan_poisoning.h
@@ -15,6 +15,7 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
+#include "sanitizer_common/sanitizer_flags.h"
namespace __asan {
@@ -37,7 +38,32 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
uptr shadow_end = MEM_TO_SHADOW(
aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
- REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+ // FIXME: Page states are different on Windows, so using the same interface
+ // for mapping shadow and zeroing out pages doesn't "just work", so we should
+ // probably provide higher-level interface for these operations.
+ // For now, just memset on Windows.
+ if (value ||
+ SANITIZER_WINDOWS == 1 ||
+ shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+ REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+ } else {
+ uptr page_size = GetPageSizeCached();
+ uptr page_beg = RoundUpTo(shadow_beg, page_size);
+ uptr page_end = RoundDownTo(shadow_end, page_size);
+
+ if (page_beg >= page_end) {
+ REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+ } else {
+ if (page_beg != shadow_beg) {
+ REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+ }
+ if (page_end != shadow_end) {
+ REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+ }
+ void *res = MmapFixedNoReserve(page_beg, page_end - page_beg);
+ CHECK_EQ(page_beg, res);
+ }
+ }
}
ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
@@ -57,4 +83,8 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
}
}
+// Calls __sanitizer::FlushUnneededShadowMemory() on
+// [MemToShadow(p), MemToShadow(p+size)] with proper rounding.
+void FlushUnneededASanShadowMemory(uptr p, uptr size);
+
} // namespace __asan
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index bcc6b381a785..ad31458df28d 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_POSIX
#include "asan_internal.h"
#include "asan_interceptors.h"
@@ -30,70 +30,59 @@
#include <sys/resource.h>
#include <unistd.h>
-static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
-
namespace __asan {
-static void MaybeInstallSigaction(int signum,
- void (*handler)(int, siginfo_t *, void *)) {
- if (!AsanInterceptsSignal(signum))
- return;
- struct sigaction sigact;
- REAL(memset)(&sigact, 0, sizeof(sigact));
- sigact.sa_sigaction = handler;
- sigact.sa_flags = SA_SIGINFO;
- if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
- CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
- if (common_flags()->verbosity >= 1) {
- Report("Installed the sigaction for signal %d\n", signum);
- }
-}
-
-static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
- uptr addr = (uptr)siginfo->si_addr;
- // Write the first message using the bullet-proof write.
- if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+ uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
uptr pc, sp, bp;
GetPcSpBp(context, &pc, &sp, &bp);
- ReportSIGSEGV(pc, sp, bp, addr);
+ return SignalContext(context, addr, pc, sp, bp);
}
-void SetAlternateSignalStack() {
- stack_t altstack, oldstack;
- CHECK_EQ(0, sigaltstack(0, &oldstack));
- // If the alternate stack is already in place, do nothing.
- if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
- // TODO(glider): the mapped stack should have the MAP_STACK flag in the
- // future. It is not required by man 2 sigaltstack now (they're using
- // malloc()).
- void* base = MmapOrDie(kAltStackSize, __FUNCTION__);
- altstack.ss_sp = base;
- altstack.ss_flags = 0;
- altstack.ss_size = kAltStackSize;
- CHECK_EQ(0, sigaltstack(&altstack, 0));
- if (common_flags()->verbosity > 0) {
- Report("Alternative stack for T%d set: [%p,%p)\n",
- GetCurrentTidOrInvalid(),
- altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
+void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+ ScopedDeadlySignal signal_scope(GetCurrentThread());
+ int code = (int)((siginfo_t*)siginfo)->si_code;
+ // Write the first message using the bullet-proof write.
+ if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
+ SignalContext sig = SignalContext::Create(siginfo, context);
+
+ // Access at a reasonable offset above SP, or slightly below it (to account
+ // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
+ // probably a stack overflow.
+ bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
+
+#if __powerpc__
+ // Large stack frames can be allocated with e.g.
+ // lis r0,-10000
+ // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
+ // If the store faults then sp will not have been updated, so test above
+ // will not work, becase the fault address will be more than just "slightly"
+ // below sp.
+ if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
+ u32 inst = *(unsigned *)sig.pc;
+ u32 ra = (inst >> 16) & 0x1F;
+ u32 opcd = inst >> 26;
+ u32 xo = (inst >> 1) & 0x3FF;
+ // Check for store-with-update to sp. The instructions we accept are:
+ // stbu rs,d(ra) stbux rs,ra,rb
+ // sthu rs,d(ra) sthux rs,ra,rb
+ // stwu rs,d(ra) stwux rs,ra,rb
+ // stdu rs,ds(ra) stdux rs,ra,rb
+ // where ra is r1 (the stack pointer).
+ if (ra == 1 &&
+ (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
+ (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
+ IsStackAccess = true;
}
-}
-
-void UnsetAlternateSignalStack() {
- stack_t altstack, oldstack;
- altstack.ss_sp = 0;
- altstack.ss_flags = SS_DISABLE;
- altstack.ss_size = 0;
- CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
- UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
-}
-
-void InstallSignalHandlers() {
- // Set the alternate signal stack for the main thread.
- // This will cause SetAlternateSignalStack to be called twice, but the stack
- // will be actually set only once.
- if (flags()->use_sigaltstack) SetAlternateSignalStack();
- MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
- MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
+#endif // __powerpc__
+
+ // We also check si_code to filter out SEGV caused by something else other
+ // then hitting the guard page or unmapped memory, like, for example,
+ // unaligned memory access.
+ if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
+ ReportStackOverflow(sig);
+ else
+ ReportSIGSEGV("SEGV", sig);
}
// ---------------------- TSD ---------------- {{{1
@@ -127,4 +116,4 @@ void PlatformTSDDtor(void *tsd) {
}
} // namespace __asan
-#endif // SANITIZER_LINUX || SANITIZER_MAC
+#endif // SANITIZER_POSIX
diff --git a/lib/asan/asan_preinit.cc b/lib/asan/asan_preinit.cc
index 586f551c23c3..a3986d24f9c3 100644
--- a/lib/asan/asan_preinit.cc
+++ b/lib/asan/asan_preinit.cc
@@ -10,22 +10,16 @@
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Call __asan_init at the very early stage of process startup.
-// On Linux we use .preinit_array section (unless PIC macro is defined).
//===----------------------------------------------------------------------===//
#include "asan_internal.h"
-#if ASAN_USE_PREINIT_ARRAY && !defined(PIC)
- // On Linux, we force __asan_init to be called before anyone else
- // by placing it into .preinit_array section.
- // FIXME: do we have anything like this on Mac?
+using namespace __asan;
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
// The symbol is called __local_asan_preinit, because it's not intended to be
// exported.
+ // This code linked into the main executable when -fsanitize=address is in
+ // the link flags. It can only use exported interface functions.
__attribute__((section(".preinit_array"), used))
void (*__local_asan_preinit)(void) = __asan_init;
-#elif SANITIZER_WINDOWS && defined(_DLL)
- // On Windows, when using dynamic CRT (/MD), we can put a pointer
- // to __asan_init into the global list of C initializers.
- // See crt0dat.c in the CRT sources for the details.
- #pragma section(".CRT$XIB", long, read) // NOLINT
- __declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init;
#endif
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index ed4e433c7a54..0fb50276186b 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -31,6 +31,19 @@ static char *error_message_buffer = 0;
static uptr error_message_buffer_pos = 0;
static uptr error_message_buffer_size = 0;
+struct ReportData {
+ uptr pc;
+ uptr sp;
+ uptr bp;
+ uptr addr;
+ bool is_write;
+ uptr access_size;
+ const char *description;
+};
+
+static bool report_happened = false;
+static ReportData report_data = {};
+
void AppendToErrorMessageBuffer(const char *buffer) {
if (error_message_buffer) {
uptr length = internal_strlen(buffer);
@@ -45,11 +58,9 @@ void AppendToErrorMessageBuffer(const char *buffer) {
}
// ---------------------- Decorator ------------------------------ {{{1
-class Decorator: private __sanitizer::AnsiColorDecorator {
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
- Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
- const char *Warning() { return Red(); }
- const char *EndWarning() { return Default(); }
+ Decorator() : SanitizerCommonDecorator() { }
const char *Access() { return Blue(); }
const char *EndAccess() { return Default(); }
const char *Location() { return Green(); }
@@ -61,6 +72,7 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
switch (byte) {
case kAsanHeapLeftRedzoneMagic:
case kAsanHeapRightRedzoneMagic:
+ case kAsanArrayCookieMagic:
return Red();
case kAsanHeapFreeMagic:
return Magenta();
@@ -74,6 +86,9 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
case kAsanInitializationOrderMagic:
return Cyan();
case kAsanUserPoisonedMemoryMagic:
+ case kAsanContiguousContainerOOBMagic:
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
return Blue();
case kAsanStackUseAfterScopeMagic:
return Magenta();
@@ -81,75 +96,119 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
return Red();
case kAsanInternalHeapMagic:
return Yellow();
+ case kAsanIntraObjectRedzone:
+ return Yellow();
default:
return Default();
}
}
const char *EndShadowByte() { return Default(); }
+ const char *MemoryByte() { return Magenta(); }
+ const char *EndMemoryByte() { return Default(); }
};
// ---------------------- Helper functions ----------------------- {{{1
-static void PrintShadowByte(const char *before, u8 byte,
- const char *after = "\n") {
+static void PrintMemoryByte(InternalScopedString *str, const char *before,
+ u8 byte, bool in_shadow, const char *after = "\n") {
Decorator d;
- Printf("%s%s%x%x%s%s", before,
- d.ShadowByte(byte), byte >> 4, byte & 15, d.EndShadowByte(), after);
+ str->append("%s%s%x%x%s%s", before,
+ in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
+ byte >> 4, byte & 15,
+ in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
+}
+
+static void PrintShadowByte(InternalScopedString *str, const char *before,
+ u8 byte, const char *after = "\n") {
+ PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
}
-static void PrintShadowBytes(const char *before, u8 *bytes,
- u8 *guilty, uptr n) {
+static void PrintShadowBytes(InternalScopedString *str, const char *before,
+ u8 *bytes, u8 *guilty, uptr n) {
Decorator d;
- if (before)
- Printf("%s%p:", before, bytes);
+ if (before) str->append("%s%p:", before, bytes);
for (uptr i = 0; i < n; i++) {
u8 *p = bytes + i;
- const char *before = p == guilty ? "[" :
- (p - 1 == guilty && i != 0) ? "" : " ";
+ const char *before =
+ p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " ";
const char *after = p == guilty ? "]" : "";
- PrintShadowByte(before, *p, after);
+ PrintShadowByte(str, before, *p, after);
}
- Printf("\n");
-}
-
-static void PrintLegend() {
- Printf("Shadow byte legend (one shadow byte represents %d "
- "application bytes):\n", (int)SHADOW_GRANULARITY);
- PrintShadowByte(" Addressable: ", 0);
- Printf(" Partially addressable: ");
- for (u8 i = 1; i < SHADOW_GRANULARITY; i++)
- PrintShadowByte("", i, " ");
- Printf("\n");
- PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
- PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic);
- PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic);
- PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic);
- PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic);
- PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic);
- PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic);
- PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic);
- PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic);
- PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic);
- PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic);
- PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic);
- PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
+ str->append("\n");
}
-static void PrintShadowMemoryForAddress(uptr addr) {
- if (!AddrIsInMem(addr))
+static void PrintLegend(InternalScopedString *str) {
+ str->append(
+ "Shadow byte legend (one shadow byte represents %d "
+ "application bytes):\n",
+ (int)SHADOW_GRANULARITY);
+ PrintShadowByte(str, " Addressable: ", 0);
+ str->append(" Partially addressable: ");
+ for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " ");
+ str->append("\n");
+ PrintShadowByte(str, " Heap left redzone: ",
+ kAsanHeapLeftRedzoneMagic);
+ PrintShadowByte(str, " Heap right redzone: ",
+ kAsanHeapRightRedzoneMagic);
+ PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic);
+ PrintShadowByte(str, " Stack left redzone: ",
+ kAsanStackLeftRedzoneMagic);
+ PrintShadowByte(str, " Stack mid redzone: ",
+ kAsanStackMidRedzoneMagic);
+ PrintShadowByte(str, " Stack right redzone: ",
+ kAsanStackRightRedzoneMagic);
+ PrintShadowByte(str, " Stack partial redzone: ",
+ kAsanStackPartialRedzoneMagic);
+ PrintShadowByte(str, " Stack after return: ",
+ kAsanStackAfterReturnMagic);
+ PrintShadowByte(str, " Stack use after scope: ",
+ kAsanStackUseAfterScopeMagic);
+ PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic);
+ PrintShadowByte(str, " Global init order: ",
+ kAsanInitializationOrderMagic);
+ PrintShadowByte(str, " Poisoned by user: ",
+ kAsanUserPoisonedMemoryMagic);
+ PrintShadowByte(str, " Container overflow: ",
+ kAsanContiguousContainerOOBMagic);
+ PrintShadowByte(str, " Array cookie: ",
+ kAsanArrayCookieMagic);
+ PrintShadowByte(str, " Intra object redzone: ",
+ kAsanIntraObjectRedzone);
+ PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic);
+ PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic);
+ PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic);
+}
+
+void MaybeDumpInstructionBytes(uptr pc) {
+ if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
return;
+ InternalScopedString str(1024);
+ str.append("First 16 instruction bytes at pc: ");
+ if (IsAccessibleMemoryRange(pc, 16)) {
+ for (int i = 0; i < 16; ++i) {
+ PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " ");
+ }
+ str.append("\n");
+ } else {
+ str.append("unaccessible\n");
+ }
+ Report("%s", str.data());
+}
+
+static void PrintShadowMemoryForAddress(uptr addr) {
+ if (!AddrIsInMem(addr)) return;
uptr shadow_addr = MemToShadow(addr);
const uptr n_bytes_per_row = 16;
uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
- Printf("Shadow bytes around the buggy address:\n");
+ InternalScopedString str(4096 * 8);
+ str.append("Shadow bytes around the buggy address:\n");
for (int i = -5; i <= 5; i++) {
const char *prefix = (i == 0) ? "=>" : " ";
- PrintShadowBytes(prefix,
- (u8*)(aligned_shadow + i * n_bytes_per_row),
- (u8*)shadow_addr, n_bytes_per_row);
+ PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
+ (u8 *)shadow_addr, n_bytes_per_row);
}
- if (flags()->print_legend)
- PrintLegend();
+ if (flags()->print_legend) PrintLegend(&str);
+ Printf("%s", str.data());
}
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
@@ -181,62 +240,89 @@ static bool IsASCII(unsigned char c) {
static const char *MaybeDemangleGlobalName(const char *name) {
// We can spoil names of globals with C linkage, so use an heuristic
// approach to check if the name should be demangled.
- return (name[0] == '_' && name[1] == 'Z')
- ? Symbolizer::Get()->Demangle(name)
- : name;
+ bool should_demangle = false;
+ if (name[0] == '_' && name[1] == 'Z')
+ should_demangle = true;
+ else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
+ should_demangle = true;
+
+ return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
}
// Check if the global is a zero-terminated ASCII string. If so, print it.
-static void PrintGlobalNameIfASCII(const __asan_global &g) {
+static void PrintGlobalNameIfASCII(InternalScopedString *str,
+ const __asan_global &g) {
for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
unsigned char c = *(unsigned char*)p;
if (c == '\0' || !IsASCII(c)) return;
}
if (*(char*)(g.beg + g.size - 1) != '\0') return;
- Printf(" '%s' is ascii string '%s'\n",
- MaybeDemangleGlobalName(g.name), (char*)g.beg);
+ str->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name),
+ (char *)g.beg);
+}
+
+static const char *GlobalFilename(const __asan_global &g) {
+ const char *res = g.module_name;
+ // Prefer the filename from source location, if is available.
+ if (g.location)
+ res = g.location->filename;
+ CHECK(res);
+ return res;
+}
+
+static void PrintGlobalLocation(InternalScopedString *str,
+ const __asan_global &g) {
+ str->append("%s", GlobalFilename(g));
+ if (!g.location)
+ return;
+ if (g.location->line_no)
+ str->append(":%d", g.location->line_no);
+ if (g.location->column_no)
+ str->append(":%d", g.location->column_no);
}
bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
const __asan_global &g) {
- static const uptr kMinimalDistanceFromAnotherGlobal = 64;
- if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
- if (addr >= g.beg + g.size_with_redzone) return false;
+ if (!IsAddressNearGlobal(addr, g)) return false;
+ InternalScopedString str(4096);
Decorator d;
- Printf("%s", d.Location());
+ str.append("%s", d.Location());
if (addr < g.beg) {
- Printf("%p is located %zd bytes to the left", (void*)addr, g.beg - addr);
+ str.append("%p is located %zd bytes to the left", (void *)addr,
+ g.beg - addr);
} else if (addr + size > g.beg + g.size) {
if (addr < g.beg + g.size)
addr = g.beg + g.size;
- Printf("%p is located %zd bytes to the right", (void*)addr,
- addr - (g.beg + g.size));
+ str.append("%p is located %zd bytes to the right", (void *)addr,
+ addr - (g.beg + g.size));
} else {
// Can it happen?
- Printf("%p is located %zd bytes inside", (void*)addr, addr - g.beg);
+ str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg);
}
- Printf(" of global variable '%s' from '%s' (0x%zx) of size %zu\n",
- MaybeDemangleGlobalName(g.name), g.module_name, g.beg, g.size);
- Printf("%s", d.EndLocation());
- PrintGlobalNameIfASCII(g);
+ str.append(" of global variable '%s' defined in '",
+ MaybeDemangleGlobalName(g.name));
+ PrintGlobalLocation(&str, g);
+ str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
+ str.append("%s", d.EndLocation());
+ PrintGlobalNameIfASCII(&str, g);
+ Printf("%s", str.data());
return true;
}
-bool DescribeAddressIfShadow(uptr addr) {
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) {
if (AddrIsInMem(addr))
return false;
- static const char kAddrInShadowReport[] =
- "Address %p is located in the %s.\n";
- if (AddrIsInShadowGap(addr)) {
- Printf(kAddrInShadowReport, addr, "shadow gap area");
- return true;
- }
- if (AddrIsInHighShadow(addr)) {
- Printf(kAddrInShadowReport, addr, "high shadow area");
- return true;
- }
- if (AddrIsInLowShadow(addr)) {
- Printf(kAddrInShadowReport, addr, "low shadow area");
+ const char *area_type = nullptr;
+ if (AddrIsInShadowGap(addr)) area_type = "shadow gap";
+ else if (AddrIsInHighShadow(addr)) area_type = "high shadow";
+ else if (AddrIsInLowShadow(addr)) area_type = "low shadow";
+ if (area_type != nullptr) {
+ if (print) {
+ Printf("Address %p is located in the %s area.\n", addr, area_type);
+ } else {
+ CHECK(descr);
+ descr->region_kind = area_type;
+ }
return true;
}
CHECK(0 && "Address is not in memory and not in shadow?");
@@ -263,16 +349,15 @@ const char *ThreadNameWithParenthesis(u32 tid, char buff[],
return ThreadNameWithParenthesis(t, buff, buff_len);
}
-void PrintAccessAndVarIntersection(const char *var_name,
- uptr var_beg, uptr var_size,
- uptr addr, uptr access_size,
- uptr prev_var_end, uptr next_var_beg) {
- uptr var_end = var_beg + var_size;
+static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
+ uptr access_size, uptr prev_var_end,
+ uptr next_var_beg) {
+ uptr var_end = var.beg + var.size;
uptr addr_end = addr + access_size;
const char *pos_descr = 0;
- // If the variable [var_beg, var_end) is the nearest variable to the
+ // If the variable [var.beg, var_end) is the nearest variable to the
// current memory access, indicate it in the log.
- if (addr >= var_beg) {
+ if (addr >= var.beg) {
if (addr_end <= var_end)
pos_descr = "is inside"; // May happen if this is a use-after-return.
else if (addr < var_end)
@@ -281,59 +366,77 @@ void PrintAccessAndVarIntersection(const char *var_name,
next_var_beg - addr_end >= addr - var_end)
pos_descr = "overflows";
} else {
- if (addr_end > var_beg)
+ if (addr_end > var.beg)
pos_descr = "partially underflows";
else if (addr >= prev_var_end &&
- addr - prev_var_end >= var_beg - addr_end)
+ addr - prev_var_end >= var.beg - addr_end)
pos_descr = "underflows";
}
- Printf(" [%zd, %zd) '%s'", var_beg, var_beg + var_size, var_name);
+ InternalScopedString str(1024);
+ str.append(" [%zd, %zd)", var.beg, var_end);
+ // Render variable name.
+ str.append(" '");
+ for (uptr i = 0; i < var.name_len; ++i) {
+ str.append("%c", var.name_pos[i]);
+ }
+ str.append("'");
if (pos_descr) {
Decorator d;
// FIXME: we may want to also print the size of the access here,
// but in case of accesses generated by memset it may be confusing.
- Printf("%s <== Memory access at offset %zd %s this variable%s\n",
- d.Location(), addr, pos_descr, d.EndLocation());
+ str.append("%s <== Memory access at offset %zd %s this variable%s\n",
+ d.Location(), addr, pos_descr, d.EndLocation());
} else {
- Printf("\n");
+ str.append("\n");
}
+ Printf("%s", str.data());
}
-struct StackVarDescr {
- uptr beg;
- uptr size;
- const char *name_pos;
- uptr name_len;
-};
+bool ParseFrameDescription(const char *frame_descr,
+ InternalMmapVector<StackVarDescr> *vars) {
+ CHECK(frame_descr);
+ char *p;
+ // This string is created by the compiler and has the following form:
+ // "n alloc_1 alloc_2 ... alloc_n"
+ // where alloc_i looks like "offset size len ObjectName".
+ uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
+ if (n_objects == 0)
+ return false;
+
+ for (uptr i = 0; i < n_objects; i++) {
+ uptr beg = (uptr)internal_simple_strtoll(p, &p, 10);
+ uptr size = (uptr)internal_simple_strtoll(p, &p, 10);
+ uptr len = (uptr)internal_simple_strtoll(p, &p, 10);
+ if (beg == 0 || size == 0 || *p != ' ') {
+ return false;
+ }
+ p++;
+ StackVarDescr var = {beg, size, p, len};
+ vars->push_back(var);
+ p += len;
+ }
+
+ return true;
+}
bool DescribeAddressIfStack(uptr addr, uptr access_size) {
AsanThread *t = FindThreadByStackAddress(addr);
if (!t) return false;
- const uptr kBufSize = 4095;
- char buf[kBufSize];
- uptr offset = 0;
- uptr frame_pc = 0;
- char tname[128];
- const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
-#ifdef __powerpc64__
- // On PowerPC64, the address of a function actually points to a
- // three-doubleword data structure with the first field containing
- // the address of the function's code.
- frame_pc = *reinterpret_cast<uptr *>(frame_pc);
-#endif
-
- // This string is created by the compiler and has the following form:
- // "n alloc_1 alloc_2 ... alloc_n"
- // where alloc_i looks like "offset size len ObjectName ".
- CHECK(frame_descr);
Decorator d;
+ char tname[128];
Printf("%s", d.Location());
- Printf("Address %p is located in stack of thread T%d%s "
- "at offset %zu in frame\n",
- addr, t->tid(),
- ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)),
- offset);
+ Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
+ ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
+
+ // Try to fetch precise stack frame for this access.
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access)) {
+ Printf("%s\n", d.EndLocation());
+ return true;
+ }
+ Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
+
// Now we print the frame where the alloca has happened.
// We print this frame as a stack trace with one element.
// The symbolizer may print more than one frame if inlining was involved.
@@ -341,50 +444,42 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
// previously. That's unfortunate, but I have no better solution,
// especially given that the alloca may be from entirely different place
// (e.g. use-after-scope, or different thread's stack).
- StackTrace alloca_stack;
- alloca_stack.trace[0] = frame_pc + 16;
- alloca_stack.size = 1;
+#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+ // On PowerPC64 ELFv1, the address of a function actually points to a
+ // three-doubleword data structure with the first field containing
+ // the address of the function's code.
+ access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
+#endif
+ access.frame_pc += 16;
Printf("%s", d.EndLocation());
- PrintStack(&alloca_stack);
+ StackTrace alloca_stack(&access.frame_pc, 1);
+ alloca_stack.Print();
+
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ Printf("AddressSanitizer can't parse the stack frame "
+ "descriptor: |%s|\n", access.frame_descr);
+ // 'addr' is a stack address, so return true even if we can't parse frame
+ return true;
+ }
+ uptr n_objects = vars.size();
// Report the number of stack objects.
- char *p;
- uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
- CHECK_GT(n_objects, 0);
Printf(" This frame has %zu object(s):\n", n_objects);
// Report all objects in this frame.
- InternalScopedBuffer<StackVarDescr> vars(n_objects);
for (uptr i = 0; i < n_objects; i++) {
- uptr beg, size;
- uptr len;
- beg = (uptr)internal_simple_strtoll(p, &p, 10);
- size = (uptr)internal_simple_strtoll(p, &p, 10);
- len = (uptr)internal_simple_strtoll(p, &p, 10);
- if (beg == 0 || size == 0 || *p != ' ') {
- Printf("AddressSanitizer can't parse the stack frame "
- "descriptor: |%s|\n", frame_descr);
- break;
- }
- p++;
- vars[i].beg = beg;
- vars[i].size = size;
- vars[i].name_pos = p;
- vars[i].name_len = len;
- p += len;
- }
- for (uptr i = 0; i < n_objects; i++) {
- buf[0] = 0;
- internal_strncat(buf, vars[i].name_pos,
- static_cast<uptr>(Min(kBufSize, vars[i].name_len)));
uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
- PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size,
- offset, access_size,
+ PrintAccessAndVarIntersection(vars[i], access.offset, access_size,
prev_var_end, next_var_beg);
}
Printf("HINT: this may be a false positive if your program uses "
- "some custom stack unwind mechanism or swapcontext\n"
- " (longjmp and C++ exceptions *are* supported)\n");
+ "some custom stack unwind mechanism or swapcontext\n");
+ if (SANITIZER_WINDOWS)
+ Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n");
+ else
+ Printf(" (longjmp and C++ exceptions *are* supported)\n");
+
DescribeThread(t);
return true;
}
@@ -393,24 +488,26 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
uptr access_size) {
sptr offset;
Decorator d;
- Printf("%s", d.Location());
+ InternalScopedString str(4096);
+ str.append("%s", d.Location());
if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
- Printf("%p is located %zd bytes to the left of", (void*)addr, offset);
+ str.append("%p is located %zd bytes to the left of", (void *)addr, offset);
} else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
if (offset < 0) {
addr -= offset;
offset = 0;
}
- Printf("%p is located %zd bytes to the right of", (void*)addr, offset);
+ str.append("%p is located %zd bytes to the right of", (void *)addr, offset);
} else if (chunk.AddrIsInside(addr, access_size, &offset)) {
- Printf("%p is located %zd bytes inside of", (void*)addr, offset);
+ str.append("%p is located %zd bytes inside of", (void*)addr, offset);
} else {
- Printf("%p is located somewhere around (this is AddressSanitizer bug!)",
- (void*)addr);
+ str.append("%p is located somewhere around (this is AddressSanitizer bug!)",
+ (void *)addr);
}
- Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
- (void*)(chunk.Beg()), (void*)(chunk.End()));
- Printf("%s", d.EndLocation());
+ str.append(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
+ (void *)(chunk.Beg()), (void *)(chunk.End()));
+ str.append("%s", d.EndLocation());
+ Printf("%s", str.data());
}
void DescribeHeapAddress(uptr addr, uptr access_size) {
@@ -425,8 +522,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
asanThreadRegistry().CheckLocked();
AsanThreadContext *alloc_thread =
GetThreadContextByTidLocked(chunk.AllocTid());
- StackTrace alloc_stack;
- chunk.GetAllocStack(&alloc_stack);
+ StackTrace alloc_stack = chunk.GetAllocStack();
char tname[128];
Decorator d;
AsanThreadContext *free_thread = 0;
@@ -436,9 +532,8 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
free_thread->tid,
ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
d.EndAllocation());
- StackTrace free_stack;
- chunk.GetFreeStack(&free_stack);
- PrintStack(&free_stack);
+ StackTrace free_stack = chunk.GetFreeStack();
+ free_stack.Print();
Printf("%spreviously allocated by thread T%d%s here:%s\n",
d.Allocation(), alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
@@ -449,7 +544,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
d.EndAllocation());
}
- PrintStack(&alloc_stack);
+ alloc_stack.Print();
DescribeThread(GetCurrentThread());
if (free_thread)
DescribeThread(free_thread);
@@ -480,15 +575,14 @@ void DescribeThread(AsanThreadContext *context) {
}
context->announced = true;
char tname[128];
- Printf("Thread T%d%s", context->tid,
- ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
- Printf(" created by T%d%s here:\n",
- context->parent_tid,
- ThreadNameWithParenthesis(context->parent_tid,
- tname, sizeof(tname)));
- uptr stack_size;
- const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size);
- PrintStack(stack_trace, stack_size);
+ InternalScopedString str(1024);
+ str.append("Thread T%d%s", context->tid,
+ ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
+ str.append(
+ " created by T%d%s here:\n", context->parent_tid,
+ ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
+ Printf("%s", str.data());
+ StackDepotGet(context->stack_id).Print();
// Recursively described parent thread if needed.
if (flags()->print_full_thread_history) {
AsanThreadContext *parent_context =
@@ -503,14 +597,14 @@ void DescribeThread(AsanThreadContext *context) {
// immediately after printing error report.
class ScopedInErrorReport {
public:
- ScopedInErrorReport() {
+ explicit ScopedInErrorReport(ReportData *report = nullptr) {
static atomic_uint32_t num_calls;
static u32 reporting_thread_tid;
if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
// Do not print more than one report, otherwise they will mix up.
// Error reporting functions shouldn't return at this situation, as
// they are defined as no-return.
- Report("AddressSanitizer: while reporting a bug found another one."
+ Report("AddressSanitizer: while reporting a bug found another one. "
"Ignoring.\n");
u32 current_tid = GetCurrentTidOrInvalid();
if (current_tid != reporting_thread_tid) {
@@ -523,6 +617,8 @@ class ScopedInErrorReport {
// Die() to bypass any additional checks.
internal__exit(flags()->exitcode);
}
+ if (report) report_data = *report;
+ report_happened = true;
ASAN_ON_ERROR();
// Make sure the registry and sanitizer report mutexes are locked while
// we're printing an error report.
@@ -538,6 +634,8 @@ class ScopedInErrorReport {
NORETURN ~ScopedInErrorReport() {
// Make sure the current thread is announced.
DescribeThread(GetCurrentThread());
+ // We may want to grab this lock again when printing stats.
+ asanThreadRegistry().Unlock();
// Print memory stats.
if (flags()->print_stats)
__asan_print_accumulated_stats();
@@ -549,22 +647,42 @@ class ScopedInErrorReport {
}
};
-void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
+void ReportStackOverflow(const SignalContext &sig) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: SEGV on unknown address %p"
- " (pc %p sp %p bp %p T%d)\n",
- (void*)addr, (void*)pc, (void*)sp, (void*)bp,
- GetCurrentTidOrInvalid());
+ Report(
+ "ERROR: AddressSanitizer: stack-overflow on address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp,
+ GetCurrentTidOrInvalid());
Printf("%s", d.EndWarning());
- GET_STACK_TRACE_FATAL(pc, bp);
- PrintStack(&stack);
+ GET_STACK_TRACE_SIGNAL(sig);
+ stack.Print();
+ ReportErrorSummary("stack-overflow", &stack);
+}
+
+void ReportSIGSEGV(const char *description, const SignalContext &sig) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: %s on unknown address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp,
+ (void *)sig.sp, GetCurrentTidOrInvalid());
+ if (sig.pc < GetPageSizeCached()) {
+ Report("Hint: pc points to the zero page.\n");
+ }
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_SIGNAL(sig);
+ stack.Print();
+ MaybeDumpInstructionBytes(sig.pc);
Printf("AddressSanitizer can not provide additional info.\n");
ReportErrorSummary("SEGV", &stack);
}
-void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
+void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -577,12 +695,36 @@ void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
Printf("%s", d.EndWarning());
CHECK_GT(free_stack->size, 0);
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- PrintStack(&stack);
+ stack.Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("double-free", &stack);
}
-void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
+void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+ BufferedStackTrace *free_stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in "
+ "thread T%d%s:\n",
+ addr, curr_tid,
+ ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+ Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
+ Printf(" size of the allocated type: %zd bytes;\n"
+ " size of the deallocated type: %zd bytes.\n",
+ asan_mz_size(reinterpret_cast<void*>(addr)), delete_size);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("new-delete-type-mismatch", &stack);
+ Report("HINT: if you don't care about these warnings you may set "
+ "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
+}
+
+void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -594,12 +736,12 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
Printf("%s", d.EndWarning());
CHECK_GT(free_stack->size, 0);
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- PrintStack(&stack);
+ stack.Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("bad-free", &stack);
}
-void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
+void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type) {
static const char *alloc_names[] =
@@ -615,14 +757,14 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
Printf("%s", d.EndWarning());
CHECK_GT(free_stack->size, 0);
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- PrintStack(&stack);
+ stack.Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("alloc-dealloc-mismatch", &stack);
Report("HINT: if you don't care about these warnings you may set "
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
}
-void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
+void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -630,27 +772,29 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
"malloc_usable_size() for pointer which is "
"not owned: %p\n", addr);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("bad-malloc_usable_size", stack);
}
-void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
+void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+ BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: attempting to call "
- "__asan_get_allocated_size() for pointer which is "
+ "__sanitizer_get_allocated_size() for pointer which is "
"not owned: %p\n", addr);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
- ReportErrorSummary("bad-__asan_get_allocated_size", stack);
+ ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
}
-void ReportStringFunctionMemoryRangesOverlap(
- const char *function, const char *offset1, uptr length1,
- const char *offset2, uptr length2, StackTrace *stack) {
+void ReportStringFunctionMemoryRangesOverlap(const char *function,
+ const char *offset1, uptr length1,
+ const char *offset2, uptr length2,
+ BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
char bug_type[100];
@@ -660,44 +804,129 @@ void ReportStringFunctionMemoryRangesOverlap(
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ stack->Print();
DescribeAddress((uptr)offset1, length1);
DescribeAddress((uptr)offset2, length2);
ReportErrorSummary(bug_type, stack);
}
+void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ const char *bug_type = "negative-size-param";
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeAddress(offset, size);
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+ uptr old_mid, uptr new_mid,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Report("ERROR: AddressSanitizer: bad parameters to "
+ "__sanitizer_annotate_contiguous_container:\n"
+ " beg : %p\n"
+ " end : %p\n"
+ " old_mid : %p\n"
+ " new_mid : %p\n",
+ beg, end, old_mid, new_mid);
+ stack->Print();
+ ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
+}
+
+void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
+ const __asan_global *g2, u32 stack_id2) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg);
+ Printf("%s", d.EndWarning());
+ InternalScopedString g1_loc(256), g2_loc(256);
+ PrintGlobalLocation(&g1_loc, *g1);
+ PrintGlobalLocation(&g2_loc, *g2);
+ Printf(" [1] size=%zd '%s' %s\n", g1->size,
+ MaybeDemangleGlobalName(g1->name), g1_loc.data());
+ Printf(" [2] size=%zd '%s' %s\n", g2->size,
+ MaybeDemangleGlobalName(g2->name), g2_loc.data());
+ if (stack_id1 && stack_id2) {
+ Printf("These globals were registered at these points:\n");
+ Printf(" [1]:\n");
+ StackDepotGet(stack_id1).Print();
+ Printf(" [2]:\n");
+ StackDepotGet(stack_id2).Print();
+ }
+ Report("HINT: if you don't care about these warnings you may set "
+ "ASAN_OPTIONS=detect_odr_violation=0\n");
+ InternalScopedString error_msg(256);
+ error_msg.append("odr-violation: global '%s' at %s",
+ MaybeDemangleGlobalName(g1->name), g1_loc.data());
+ ReportErrorSummary(error_msg.data());
+}
+
+// ----------------------- CheckForInvalidPointerPair ----------- {{{1
+static NOINLINE void
+ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2);
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_FATAL(pc, bp);
+ stack.Print();
+ DescribeAddress(a1, 1);
+ DescribeAddress(a2, 1);
+ ReportErrorSummary("invalid-pointer-pair", &stack);
+}
+
+static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
+ if (!flags()->detect_invalid_pointer_pairs) return;
+ uptr a1 = reinterpret_cast<uptr>(p1);
+ uptr a2 = reinterpret_cast<uptr>(p2);
+ AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
+ AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
+ bool valid1 = chunk1.IsValid();
+ bool valid2 = chunk2.IsValid();
+ if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) {
+ GET_CALLER_PC_BP_SP; \
+ return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
+ }
+}
// ----------------------- Mac-specific reports ----------------- {{{1
-void WarnMacFreeUnallocated(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack) {
// Just print a warning here.
Printf("free_common(%p) -- attempting to free unallocated memory.\n"
"AddressSanitizer is ignoring this error on Mac OS now.\n",
addr);
PrintZoneForPointer(addr, zone_ptr, zone_name);
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
}
-void ReportMacMzReallocUnknown(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
"This is an unrecoverable problem, exiting now.\n",
addr);
PrintZoneForPointer(addr, zone_ptr, zone_name);
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
}
-void ReportMacCfReallocUnknown(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
"This is an unrecoverable problem, exiting now.\n",
addr);
PrintZoneForPointer(addr, zone_ptr, zone_name);
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
}
@@ -706,10 +935,8 @@ void ReportMacCfReallocUnknown(
// --------------------------- Interface --------------------- {{{1
using namespace __asan; // NOLINT
-void __asan_report_error(uptr pc, uptr bp, uptr sp,
- uptr addr, bool is_write, uptr access_size) {
- ScopedInErrorReport in_report;
-
+void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
+ uptr access_size) {
// Determine the error type.
const char *bug_descr = "unknown-crash";
if (AddrIsInMem(addr)) {
@@ -723,6 +950,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
switch (*shadow_addr) {
case kAsanHeapLeftRedzoneMagic:
case kAsanHeapRightRedzoneMagic:
+ case kAsanArrayCookieMagic:
bug_descr = "heap-buffer-overflow";
break;
case kAsanHeapFreeMagic:
@@ -745,18 +973,33 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
case kAsanUserPoisonedMemoryMagic:
bug_descr = "use-after-poison";
break;
+ case kAsanContiguousContainerOOBMagic:
+ bug_descr = "container-overflow";
+ break;
case kAsanStackUseAfterScopeMagic:
bug_descr = "stack-use-after-scope";
break;
case kAsanGlobalRedzoneMagic:
bug_descr = "global-buffer-overflow";
break;
+ case kAsanIntraObjectRedzone:
+ bug_descr = "intra-object-overflow";
+ break;
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
+ bug_descr = "dynamic-stack-buffer-overflow";
+ break;
}
}
+
+ ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
+ bug_descr };
+ ScopedInErrorReport in_report(&report);
+
Decorator d;
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: %s on address "
- "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
+ "%p at pc %p bp %p sp %p\n",
bug_descr, (void*)addr, pc, bp, sp);
Printf("%s", d.EndWarning());
@@ -770,7 +1013,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
d.EndAccess());
GET_STACK_TRACE_FATAL(pc, bp);
- PrintStack(&stack);
+ stack.Print();
DescribeAddress(addr, access_size);
ReportErrorSummary(bug_descr, &stack);
@@ -782,14 +1025,60 @@ void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
if (callback) {
error_message_buffer_size = 1 << 16;
error_message_buffer =
- (char*)MmapOrDie(error_message_buffer_size, __FUNCTION__);
+ (char*)MmapOrDie(error_message_buffer_size, __func__);
error_message_buffer_pos = 0;
}
}
void __asan_describe_address(uptr addr) {
+ // Thread registry must be locked while we're describing an address.
+ asanThreadRegistry().Lock();
DescribeAddress(addr, 1);
+ asanThreadRegistry().Unlock();
+}
+
+int __asan_report_present() {
+ return report_happened ? 1 : 0;
+}
+
+uptr __asan_get_report_pc() {
+ return report_data.pc;
+}
+
+uptr __asan_get_report_bp() {
+ return report_data.bp;
+}
+
+uptr __asan_get_report_sp() {
+ return report_data.sp;
+}
+
+uptr __asan_get_report_address() {
+ return report_data.addr;
+}
+
+int __asan_get_report_access_type() {
+ return report_data.is_write ? 1 : 0;
+}
+
+uptr __asan_get_report_access_size() {
+ return report_data.access_size;
+}
+
+const char *__asan_get_report_description() {
+ return report_data.description;
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_ptr_sub(void *a, void *b) {
+ CheckForInvalidPointerPair(a, b);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_ptr_cmp(void *a, void *b) {
+ CheckForInvalidPointerPair(a, b);
}
+} // extern "C"
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default implementation of __asan_on_error that does nothing
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index f55b57bd4d9f..029c914b8a04 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -18,13 +18,33 @@
namespace __asan {
+struct StackVarDescr {
+ uptr beg;
+ uptr size;
+ const char *name_pos;
+ uptr name_len;
+};
+
+struct AddressDescription {
+ char *name;
+ uptr name_size;
+ uptr region_address;
+ uptr region_size;
+ const char *region_kind;
+};
+
// The following functions prints address description depending
// on the memory type (shadow/heap/stack/global).
void DescribeHeapAddress(uptr addr, uptr access_size);
bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
const __asan_global &g);
-bool DescribeAddressIfShadow(uptr addr);
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g);
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr);
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr,
+ bool print = true);
+bool ParseFrameDescription(const char *frame_descr,
+ InternalMmapVector<StackVarDescr> *vars);
bool DescribeAddressIfStack(uptr addr, uptr access_size);
// Determines memory type on its own.
void DescribeAddress(uptr addr, uptr access_size);
@@ -32,26 +52,44 @@ void DescribeAddress(uptr addr, uptr access_size);
void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
-void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
-void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
-void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
-void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
+void NORETURN ReportStackOverflow(const SignalContext &sig);
+void NORETURN ReportSIGSEGV(const char *description, const SignalContext &sig);
+void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+ BufferedStackTrace *free_stack);
+void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
+void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
+void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type);
-void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
- StackTrace *stack);
-void NORETURN ReportAsanGetAllocatedSizeNotOwned(uptr addr,
- StackTrace *stack);
-void NORETURN ReportStringFunctionMemoryRangesOverlap(
- const char *function, const char *offset1, uptr length1,
- const char *offset2, uptr length2, StackTrace *stack);
+void NORETURN
+ ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
+void NORETURN
+ ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+ BufferedStackTrace *stack);
+void NORETURN
+ ReportStringFunctionMemoryRangesOverlap(const char *function,
+ const char *offset1, uptr length1,
+ const char *offset2, uptr length2,
+ BufferedStackTrace *stack);
+void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+ BufferedStackTrace *stack);
+void NORETURN
+ ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+ uptr old_mid, uptr new_mid,
+ BufferedStackTrace *stack);
+
+void NORETURN
+ReportODRViolation(const __asan_global *g1, u32 stack_id1,
+ const __asan_global *g2, u32 stack_id2);
// Mac-specific errors and warnings.
-void WarnMacFreeUnallocated(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
-void NORETURN ReportMacMzReallocUnknown(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
-void NORETURN ReportMacCfReallocUnknown(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
+void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack);
+void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
+ const char *zone_name,
+ BufferedStackTrace *stack);
+void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
+ const char *zone_name,
+ BufferedStackTrace *stack);
} // namespace __asan
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 11f05954d31e..34fb111d5607 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -11,6 +11,7 @@
//
// Main file of the ASan run-time library.
//===----------------------------------------------------------------------===//
+#include "asan_activation.h"
#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_interface_internal.h"
@@ -20,6 +21,7 @@
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
+#include "asan_suppressions.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_flags.h"
@@ -28,6 +30,7 @@
#include "lsan/lsan_common.h"
int __asan_option_detect_stack_use_after_return; // Global interface symbol.
+uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan.
namespace __asan {
@@ -51,6 +54,8 @@ static void AsanDie() {
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
}
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
if (death_callback)
death_callback();
if (flags()->abort_on_error)
@@ -60,10 +65,10 @@ static void AsanDie() {
static void AsanCheckFailed(const char *file, int line, const char *cond,
u64 v1, u64 v2) {
- Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n",
- file, line, cond, (uptr)v1, (uptr)v2);
+ Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
+ line, cond, (uptr)v1, (uptr)v2);
// FIXME: check for infinite recursion without a thread-local counter here.
- PRINT_CURRENT_STACK();
+ PRINT_CURRENT_STACK_CHECK();
Die();
}
@@ -76,7 +81,7 @@ static const char *MaybeCallAsanDefaultOptions() {
return (&__asan_default_options) ? __asan_default_options() : "";
}
-static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
+static const char *MaybeUseAsanDefaultOptionsCompileDefinition() {
#ifdef ASAN_DEFAULT_OPTIONS
// Stringize the macro value.
# define ASAN_STRINGIZE(x) #x
@@ -88,58 +93,162 @@ static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
}
static void ParseFlagsFromString(Flags *f, const char *str) {
- ParseCommonFlagsFromString(str);
- CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
-
- ParseFlag(str, &f->quarantine_size, "quarantine_size");
- ParseFlag(str, &f->redzone, "redzone");
+ CommonFlags *cf = common_flags();
+ ParseCommonFlagsFromString(cf, str);
+ CHECK((uptr)cf->malloc_context_size <= kStackTraceMax);
+ // Please write meaningful flag descriptions when adding new flags.
+ ParseFlag(str, &f->quarantine_size, "quarantine_size",
+ "Size (in bytes) of quarantine used to detect use-after-free "
+ "errors. Lower value may reduce memory usage but increase the "
+ "chance of false negatives.");
+ ParseFlag(str, &f->redzone, "redzone",
+ "Minimal size (in bytes) of redzones around heap objects. "
+ "Requirement: redzone >= 16, is a power of two.");
+ ParseFlag(str, &f->max_redzone, "max_redzone",
+ "Maximal size (in bytes) of redzones around heap objects.");
CHECK_GE(f->redzone, 16);
+ CHECK_GE(f->max_redzone, f->redzone);
+ CHECK_LE(f->max_redzone, 2048);
CHECK(IsPowerOfTwo(f->redzone));
-
- ParseFlag(str, &f->debug, "debug");
- ParseFlag(str, &f->report_globals, "report_globals");
- ParseFlag(str, &f->check_initialization_order, "check_initialization_order");
-
- ParseFlag(str, &f->replace_str, "replace_str");
- ParseFlag(str, &f->replace_intrin, "replace_intrin");
- ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free");
+ CHECK(IsPowerOfTwo(f->max_redzone));
+
+ ParseFlag(str, &f->debug, "debug",
+ "If set, prints some debugging information and does additional checks.");
+ ParseFlag(str, &f->report_globals, "report_globals",
+ "Controls the way to handle globals (0 - don't detect buffer overflow on "
+ "globals, 1 - detect buffer overflow, 2 - print data about registered "
+ "globals).");
+
+ ParseFlag(str, &f->check_initialization_order,
+ "check_initialization_order",
+ "If set, attempts to catch initialization order issues.");
+
+ ParseFlag(str, &f->replace_str, "replace_str",
+ "If set, uses custom wrappers and replacements for libc string functions "
+ "to find more errors.");
+
+ ParseFlag(str, &f->replace_intrin, "replace_intrin",
+ "If set, uses custom wrappers for memset/memcpy/memmove intinsics.");
+ ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free",
+ "Ignore invalid free() calls to work around some bugs. Used on OS X "
+ "only.");
ParseFlag(str, &f->detect_stack_use_after_return,
- "detect_stack_use_after_return");
- ParseFlag(str, &f->uar_stack_size_log, "uar_stack_size_log");
- ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size");
- ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte");
- ParseFlag(str, &f->exitcode, "exitcode");
- ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning");
- ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying");
- ParseFlag(str, &f->handle_segv, "handle_segv");
- ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler");
- ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack");
- ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
- ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
- ParseFlag(str, &f->abort_on_error, "abort_on_error");
- ParseFlag(str, &f->print_stats, "print_stats");
- ParseFlag(str, &f->print_legend, "print_legend");
- ParseFlag(str, &f->atexit, "atexit");
- ParseFlag(str, &f->coverage, "coverage");
- ParseFlag(str, &f->disable_core, "disable_core");
- ParseFlag(str, &f->allow_reexec, "allow_reexec");
- ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
- ParseFlag(str, &f->poison_heap, "poison_heap");
- ParseFlag(str, &f->poison_partial, "poison_partial");
- ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
- ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
- ParseFlag(str, &f->strict_init_order, "strict_init_order");
+ "detect_stack_use_after_return",
+ "Enables stack-use-after-return checking at run-time.");
+ ParseFlag(str, &f->min_uar_stack_size_log, "min_uar_stack_size_log",
+ "Minimum fake stack size log.");
+ ParseFlag(str, &f->max_uar_stack_size_log, "max_uar_stack_size_log",
+ "Maximum fake stack size log.");
+ ParseFlag(str, &f->uar_noreserve, "uar_noreserve",
+ "Use mmap with 'norserve' flag to allocate fake stack.");
+ ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size",
+ "ASan allocator flag. max_malloc_fill_size is the maximal amount of "
+ "bytes that will be filled with malloc_fill_byte on malloc.");
+ ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte",
+ "Value used to fill the newly allocated memory.");
+ ParseFlag(str, &f->exitcode, "exitcode",
+ "Override the program exit status if the tool found an error.");
+ ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning",
+ "If set, user may manually mark memory regions as poisoned or "
+ "unpoisoned.");
+ ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying",
+ "Number of seconds to sleep between printing an error report and "
+ "terminating the program. Useful for debugging purposes (e.g. when one "
+ "needs to attach gdb).");
+
+ ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size",
+ "Allows the users to work around the bug in Nvidia drivers prior to "
+ "295.*.");
+
+ ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit",
+ "If set, explicitly unmaps the (huge) shadow at exit.");
+ ParseFlag(str, &f->abort_on_error, "abort_on_error",
+ "If set, the tool calls abort() instead of _exit() after printing the "
+ "error report.");
+ ParseFlag(str, &f->print_stats, "print_stats",
+ "Print various statistics after printing an error message or if "
+ "atexit=1.");
+ ParseFlag(str, &f->print_legend, "print_legend",
+ "Print the legend for the shadow bytes.");
+ ParseFlag(str, &f->atexit, "atexit",
+ "If set, prints ASan exit stats even after program terminates "
+ "successfully.");
+
+ ParseFlag(str, &f->allow_reexec, "allow_reexec",
+ "Allow the tool to re-exec the program. This may interfere badly with "
+ "the debugger.");
+
+ ParseFlag(str, &f->print_full_thread_history,
+ "print_full_thread_history",
+ "If set, prints thread creation stacks for the threads involved in the "
+ "report and their ancestors up to the main thread.");
+
+ ParseFlag(str, &f->poison_heap, "poison_heap",
+ "Poison (or not) the heap memory on [de]allocation. Zero value is useful "
+ "for benchmarking the allocator or instrumentator.");
+
+ ParseFlag(str, &f->poison_array_cookie, "poison_array_cookie",
+ "Poison (or not) the array cookie after operator new[].");
+
+ ParseFlag(str, &f->poison_partial, "poison_partial",
+ "If true, poison partially addressable 8-byte aligned words "
+ "(default=true). This flag affects heap and global buffers, but not "
+ "stack buffers.");
+
+ ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch",
+ "Report errors on malloc/delete, new/free, new/delete[], etc.");
+
+ ParseFlag(str, &f->new_delete_type_mismatch, "new_delete_type_mismatch",
+ "Report errors on mismatch betwen size of new and delete.");
+
+ ParseFlag(str, &f->strict_memcmp, "strict_memcmp",
+ "If true, assume that memcmp(p1, p2, n) always reads n bytes before "
+ "comparing p1 and p2.");
+
+ ParseFlag(str, &f->strict_init_order, "strict_init_order",
+ "If true, assume that dynamic initializers can never access globals from "
+ "other modules, even if the latter are already initialized.");
+
+ ParseFlag(str, &f->start_deactivated, "start_deactivated",
+ "If true, ASan tweaks a bunch of other flags (quarantine, redzone, heap "
+ "poisoning) to reduce memory consumption as much as possible, and "
+ "restores them to original values when the first instrumented module is "
+ "loaded into the process. This is mainly intended to be used on "
+ "Android. ");
+
+ ParseFlag(str, &f->detect_invalid_pointer_pairs,
+ "detect_invalid_pointer_pairs",
+ "If non-zero, try to detect operations like <, <=, >, >= and - on "
+ "invalid pointer pairs (e.g. when pointers belong to different objects). "
+ "The bigger the value the harder we try.");
+
+ ParseFlag(str, &f->detect_container_overflow,
+ "detect_container_overflow",
+ "If true, honor the container overflow annotations. "
+ "See https://code.google.com/p/address-sanitizer/wiki/ContainerOverflow");
+
+ ParseFlag(str, &f->detect_odr_violation, "detect_odr_violation",
+ "If >=2, detect violation of One-Definition-Rule (ODR); "
+ "If ==1, detect ODR-violation only if the two variables "
+ "have different sizes");
+
+ ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes",
+ "If true, dump 16 bytes starting at the instruction that caused SEGV");
}
void InitializeFlags(Flags *f, const char *env) {
CommonFlags *cf = common_flags();
- SetCommonFlagDefaults();
+ SetCommonFlagsDefaults(cf);
+ cf->detect_leaks = CAN_SANITIZE_LEAKS;
cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
cf->malloc_context_size = kDefaultMallocContextSize;
+ cf->intercept_tls_get_addr = true;
+ cf->coverage = false;
internal_memset(f, 0, sizeof(*f));
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
f->redzone = 16;
+ f->max_redzone = 2048;
f->debug = false;
f->report_globals = 1;
f->check_initialization_order = false;
@@ -147,53 +256,58 @@ void InitializeFlags(Flags *f, const char *env) {
f->replace_intrin = true;
f->mac_ignore_invalid_free = false;
f->detect_stack_use_after_return = false; // Also needs the compiler flag.
- f->uar_stack_size_log = 0;
+ f->min_uar_stack_size_log = 16; // We can't do smaller anyway.
+ f->max_uar_stack_size_log = 20; // 1Mb per size class, i.e. ~11Mb per thread.
+ f->uar_noreserve = false;
f->max_malloc_fill_size = 0x1000; // By default, fill only the first 4K.
f->malloc_fill_byte = 0xbe;
f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE;
f->allow_user_poisoning = true;
f->sleep_before_dying = 0;
- f->handle_segv = ASAN_NEEDS_SEGV;
- f->allow_user_segv_handler = false;
- f->use_sigaltstack = false;
f->check_malloc_usable_size = true;
f->unmap_shadow_on_exit = false;
f->abort_on_error = false;
f->print_stats = false;
f->print_legend = true;
f->atexit = false;
- f->coverage = false;
- f->disable_core = (SANITIZER_WORDSIZE == 64);
f->allow_reexec = true;
f->print_full_thread_history = true;
f->poison_heap = true;
+ f->poison_array_cookie = true;
f->poison_partial = true;
// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=131
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=309
// TODO(glider,timurrrr): Fix known issues and enable this back.
f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
+ f->new_delete_type_mismatch = true;
f->strict_memcmp = true;
f->strict_init_order = false;
+ f->start_deactivated = false;
+ f->detect_invalid_pointer_pairs = 0;
+ f->detect_container_overflow = true;
+ f->detect_odr_violation = 2;
+ f->dump_instruction_bytes = false;
// Override from compile definition.
- ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
+ ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition());
// Override from user-specified string.
ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
- if (common_flags()->verbosity) {
- Report("Using the defaults from __asan_default_options: %s\n",
- MaybeCallAsanDefaultOptions());
- }
+ VReport(1, "Using the defaults from __asan_default_options: %s\n",
+ MaybeCallAsanDefaultOptions());
// Override from command line.
ParseFlagsFromString(f, env);
+ if (common_flags()->help) {
+ PrintFlagDescriptions();
+ }
-#if !CAN_SANITIZE_LEAKS
- if (cf->detect_leaks) {
+ if (!CAN_SANITIZE_LEAKS && cf->detect_leaks) {
Report("%s: detect_leaks is not supported on this platform.\n",
SanitizerToolName);
cf->detect_leaks = false;
}
-#endif
// Make "strict_init_order" imply "check_initialization_order".
// TODO(samsonov): Use a single runtime flag for an init-order checker.
@@ -202,6 +316,17 @@ void InitializeFlags(Flags *f, const char *env) {
}
}
+// Parse flags that may change between startup and activation.
+// On Android they come from a system property.
+// On other platforms this is no-op.
+void ParseExtraActivationFlags() {
+ char buf[100];
+ GetExtraActivationFlags(buf, sizeof(buf));
+ ParseFlagsFromString(flags(), buf);
+ if (buf[0] != '\0')
+ VReport(1, "Extra activation flags: %s\n", buf);
+}
+
// -------------------------- Globals --------------------- {{{1
int asan_inited;
bool asan_init_is_running;
@@ -223,6 +348,7 @@ static void ReserveShadowMemoryRange(uptr beg, uptr end) {
CHECK_EQ((beg % GetPageSizeCached()), 0);
CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
uptr size = end - beg + 1;
+ DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
void *res = MmapFixedNoReserve(beg, size);
if (res != (void*)beg) {
Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
@@ -268,6 +394,53 @@ void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
ASAN_REPORT_ERROR_N(load, false)
ASAN_REPORT_ERROR_N(store, true)
+#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \
+ extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_##type##size(uptr addr); \
+ void __asan_##type##size(uptr addr) { \
+ uptr sp = MEM_TO_SHADOW(addr); \
+ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \
+ : *reinterpret_cast<u16 *>(sp); \
+ if (UNLIKELY(s)) { \
+ if (UNLIKELY(size >= SHADOW_GRANULARITY || \
+ ((s8)((addr & (SHADOW_GRANULARITY - 1)) + size - 1)) >= \
+ (s8)s)) { \
+ if (__asan_test_only_reported_buggy_pointer) { \
+ *__asan_test_only_reported_buggy_pointer = addr; \
+ } else { \
+ GET_CALLER_PC_BP_SP; \
+ __asan_report_error(pc, bp, sp, addr, is_write, size); \
+ } \
+ } \
+ } \
+ }
+
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16)
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ __asan_report_error(pc, bp, sp, addr, false, size);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ __asan_report_error(pc, bp, sp, addr, true, size);
+ }
+}
+
// Force the linker to keep the symbols for various ASan interface functions.
// We want to keep those in the executable in order to let the instrumented
// dynamic libraries access the symbol even if it is not used by the executable
@@ -294,13 +467,6 @@ static NOINLINE void force_interface_symbols() {
case 15: __asan_set_error_report_callback(0); break;
case 16: __asan_handle_no_return(); break;
case 17: __asan_address_is_poisoned(0); break;
- case 18: __asan_get_allocated_size(0); break;
- case 19: __asan_get_current_allocated_bytes(); break;
- case 20: __asan_get_estimated_allocated_size(0); break;
- case 21: __asan_get_free_bytes(); break;
- case 22: __asan_get_heap_size(); break;
- case 23: __asan_get_ownership(0); break;
- case 24: __asan_get_unmapped_bytes(); break;
case 25: __asan_poison_memory_region(0, 0); break;
case 26: __asan_unpoison_memory_region(0, 0); break;
case 27: __asan_set_error_exit_code(0); break;
@@ -371,7 +537,8 @@ static void PrintAddressSpaceLayout() {
(void*)MEM_TO_SHADOW(kMidShadowEnd));
}
Printf("\n");
- Printf("red_zone=%zu\n", (uptr)flags()->redzone);
+ Printf("redzone=%zu\n", (uptr)flags()->redzone);
+ Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
Printf("quarantine_size=%zuM\n", (uptr)flags()->quarantine_size >> 20);
Printf("malloc_context_size=%zu\n",
(uptr)common_flags()->malloc_context_size);
@@ -386,59 +553,17 @@ static void PrintAddressSpaceLayout() {
kHighShadowBeg > kMidMemEnd);
}
-} // namespace __asan
-
-// ---------------------- Interface ---------------- {{{1
-using namespace __asan; // NOLINT
-
-#if !SANITIZER_SUPPORTS_WEAK_HOOKS
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-const char* __asan_default_options() { return ""; }
-} // extern "C"
-#endif
-
-int NOINLINE __asan_set_error_exit_code(int exit_code) {
- int old = flags()->exitcode;
- flags()->exitcode = exit_code;
- return old;
-}
-
-void NOINLINE __asan_handle_no_return() {
- int local_stack;
- AsanThread *curr_thread = GetCurrentThread();
- CHECK(curr_thread);
- uptr PageSize = GetPageSizeCached();
- uptr top = curr_thread->stack_top();
- uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1);
- static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
- if (top - bottom > kMaxExpectedCleanupSize) {
- static bool reported_warning = false;
- if (reported_warning)
- return;
- reported_warning = true;
- Report("WARNING: ASan is ignoring requested __asan_handle_no_return: "
- "stack top: %p; bottom %p; size: %p (%zd)\n"
- "False positive error reports may follow\n"
- "For details see "
- "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n",
- top, bottom, top - bottom, top - bottom);
- return;
- }
- PoisonShadow(bottom, top - bottom, 0);
- if (curr_thread->has_fake_stack())
- curr_thread->fake_stack()->HandleNoReturn();
-}
-
-void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
- death_callback = callback;
-}
-
-void __asan_init() {
- if (asan_inited) return;
+static void AsanInitInternal() {
+ if (LIKELY(asan_inited)) return;
SanitizerToolName = "AddressSanitizer";
CHECK(!asan_init_is_running && "ASan init calls itself!");
asan_init_is_running = true;
+
+ // Initialize flags. This must be done early, because most of the
+ // initialization steps look at flags().
+ const char *options = GetEnv("ASAN_OPTIONS");
+ InitializeFlags(flags(), options);
+
InitializeHighMemEnd();
// Make sure we are not statically linked.
@@ -449,18 +574,21 @@ void __asan_init() {
SetCheckFailedCallback(AsanCheckFailed);
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
- // Initialize flags. This must be done early, because most of the
- // initialization steps look at flags().
- const char *options = GetEnv("ASAN_OPTIONS");
- InitializeFlags(flags(), options);
+ if (!flags()->start_deactivated)
+ ParseExtraActivationFlags();
+
__sanitizer_set_report_path(common_flags()->log_path);
__asan_option_detect_stack_use_after_return =
flags()->detect_stack_use_after_return;
+ CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
- if (common_flags()->verbosity && options) {
- Report("Parsed ASAN_OPTIONS: %s\n", options);
+ if (options) {
+ VReport(1, "Parsed ASAN_OPTIONS: %s\n", options);
}
+ if (flags()->start_deactivated)
+ AsanStartDeactivated();
+
// Re-exec ourselves if we need to set additional env or command line args.
MaybeReexec();
@@ -469,8 +597,12 @@ void __asan_init() {
InitializeAsanInterceptors();
+ // Enable system log ("adb logcat") on Android.
+ // Doing this before interceptors are initialized crashes in:
+ // AsanInitInternal -> android_log_write -> __interceptor_strcmp
+ AndroidLogInit();
+
ReplaceSystemMalloc();
- ReplaceOperatorsNewAndDelete();
uptr shadow_start = kLowShadowBeg;
if (kLowShadowBeg)
@@ -478,7 +610,8 @@ void __asan_init() {
bool full_shadow_is_available =
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
-#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
+#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
+ !ASAN_FIXED_MAPPING
if (!full_shadow_is_available) {
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
@@ -488,9 +621,7 @@ void __asan_init() {
if (common_flags()->verbosity)
PrintAddressSpaceLayout();
- if (flags()->disable_core) {
- DisableCoreDumper();
- }
+ DisableCoreDumperIfNecessary();
if (full_shadow_is_available) {
// mmap the low shadow plus at least one page at the left.
@@ -500,6 +631,7 @@ void __asan_init() {
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
// protect the gap.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+ CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
} else if (kMidMemBeg &&
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
@@ -522,19 +654,10 @@ void __asan_init() {
}
AsanTSDInit(PlatformTSDDtor);
- InstallSignalHandlers();
+ InstallDeadlySignalHandlers(AsanOnSIGSEGV);
- // Allocator should be initialized before starting external symbolizer, as
- // fork() on Mac locks the allocator.
InitializeAllocator();
- // Start symbolizer process if necessary.
- if (common_flags()->symbolize) {
- Symbolizer::Init(common_flags()->external_symbolizer_path);
- } else {
- Symbolizer::Disable();
- }
-
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
// should be set to 1 prior to initializing the threads.
asan_inited = 1;
@@ -543,30 +666,111 @@ void __asan_init() {
if (flags()->atexit)
Atexit(asan_atexit);
- if (flags()->coverage)
+ if (common_flags()->coverage) {
+ __sanitizer_cov_init();
Atexit(__sanitizer_cov_dump);
+ }
// interceptors
InitTlsSize();
// Create main thread.
- AsanThread *main_thread = AsanThread::Create(0, 0);
- CreateThreadContextArgs create_main_args = { main_thread, 0 };
- u32 main_tid = asanThreadRegistry().CreateThread(
- 0, true, 0, &create_main_args);
- CHECK_EQ(0, main_tid);
+ AsanThread *main_thread = AsanThread::Create(
+ /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
+ /* stack */ nullptr, /* detached */ true);
+ CHECK_EQ(0, main_thread->tid());
SetCurrentThread(main_thread);
- main_thread->ThreadStart(internal_getpid());
+ main_thread->ThreadStart(internal_getpid(),
+ /* signal_thread_is_registered */ nullptr);
force_interface_symbols(); // no-op.
+ SanitizerInitializeUnwinder();
#if CAN_SANITIZE_LEAKS
- __lsan::InitCommonLsan();
+ __lsan::InitCommonLsan(false);
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
Atexit(__lsan::DoLeakCheck);
}
#endif // CAN_SANITIZE_LEAKS
- if (common_flags()->verbosity) {
- Report("AddressSanitizer Init done\n");
+ InitializeSuppressions();
+
+ VReport(1, "AddressSanitizer Init done\n");
+}
+
+// Initialize as requested from some part of ASan runtime library (interceptors,
+// allocator, etc).
+void AsanInitFromRtl() {
+ AsanInitInternal();
+}
+
+#if ASAN_DYNAMIC
+// Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable
+// (and thus normal initializer from .preinit_array haven't run).
+
+class AsanInitializer {
+public: // NOLINT
+ AsanInitializer() {
+ AsanCheckIncompatibleRT();
+ AsanCheckDynamicRTPrereqs();
+ AsanInitFromRtl();
+ }
+};
+
+static AsanInitializer asan_initializer;
+#endif // ASAN_DYNAMIC
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char* __asan_default_options() { return ""; }
+} // extern "C"
+#endif
+
+int NOINLINE __asan_set_error_exit_code(int exit_code) {
+ int old = flags()->exitcode;
+ flags()->exitcode = exit_code;
+ return old;
+}
+
+void NOINLINE __asan_handle_no_return() {
+ int local_stack;
+ AsanThread *curr_thread = GetCurrentThread();
+ CHECK(curr_thread);
+ uptr PageSize = GetPageSizeCached();
+ uptr top = curr_thread->stack_top();
+ uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1);
+ static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
+ if (top - bottom > kMaxExpectedCleanupSize) {
+ static bool reported_warning = false;
+ if (reported_warning)
+ return;
+ reported_warning = true;
+ Report("WARNING: ASan is ignoring requested __asan_handle_no_return: "
+ "stack top: %p; bottom %p; size: %p (%zd)\n"
+ "False positive error reports may follow\n"
+ "For details see "
+ "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n",
+ top, bottom, top - bottom, top - bottom);
+ return;
}
+ PoisonShadow(bottom, top - bottom, 0);
+ if (curr_thread->has_fake_stack())
+ curr_thread->fake_stack()->HandleNoReturn();
+}
+
+void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
+ death_callback = callback;
+}
+
+// Initialize as requested from instrumented application code.
+// We use this call as a trigger to wake up ASan from deactivated state.
+void __asan_init() {
+ AsanCheckIncompatibleRT();
+ AsanActivate();
+ AsanInitInternal();
}
diff --git a/lib/asan/asan_stack.cc b/lib/asan/asan_stack.cc
index 0bc5a5f2d036..8188f3b5b6e9 100644
--- a/lib/asan/asan_stack.cc
+++ b/lib/asan/asan_stack.cc
@@ -12,36 +12,14 @@
// Code for ASan stack trace.
//===----------------------------------------------------------------------===//
#include "asan_internal.h"
-#include "asan_flags.h"
#include "asan_stack.h"
-#include "sanitizer_common/sanitizer_flags.h"
-
-namespace __asan {
-
-static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer,
- int out_size) {
- return (&__asan_symbolize) ? __asan_symbolize(pc, out_buffer, out_size)
- : false;
-}
-
-void PrintStack(const uptr *trace, uptr size) {
- StackTrace::PrintStack(trace, size, MaybeCallAsanSymbolize);
-}
-
-void PrintStack(StackTrace *stack) {
- PrintStack(stack->trace, stack->size);
-}
-
-} // namespace __asan
// ------------------ Interface -------------- {{{1
-// Provide default implementation of __asan_symbolize that does nothing
-// and may be overriden by user if he wants to use his own symbolization.
-// ASan on Windows has its own implementation of this.
-#if !SANITIZER_WINDOWS && !SANITIZER_SUPPORTS_WEAK_HOOKS
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
-bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
- return false;
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ using namespace __asan;
+ PRINT_CURRENT_STACK();
}
-#endif
+} // extern "C"
diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index 7f5fd661eec8..a995256212e1 100644
--- a/lib/asan/asan_stack.h
+++ b/lib/asan/asan_stack.h
@@ -21,48 +21,75 @@
namespace __asan {
-void PrintStack(StackTrace *stack);
-void PrintStack(const uptr *trace, uptr size);
-
-} // namespace __asan
-
// Get the stack trace with the given pc and bp.
// The pc will be in the position 0 of the resulting stack trace.
// The bp may refer to the current frame or to the caller's frame.
+ALWAYS_INLINE
+void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
+ uptr pc, uptr bp, void *context,
+ bool fast) {
#if SANITIZER_WINDOWS
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- stack.Unwind(max_s, pc, bp, 0, 0, fast)
+ stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
#else
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- { \
- AsanThread *t; \
- stack.size = 0; \
- if (asan_inited && (t = GetCurrentThread()) && !t->isUnwinding()) { \
- uptr stack_top = t->stack_top(); \
- uptr stack_bottom = t->stack_bottom(); \
- ScopedUnwinding unwind_scope(t); \
- stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \
- } \
+ AsanThread *t;
+ stack->size = 0;
+ if (LIKELY(asan_inited)) {
+ if ((t = GetCurrentThread()) && !t->isUnwinding()) {
+ // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
+ // yields the call stack of the signal's handler and not of the code
+ // that raised the signal (as it does on Linux).
+ if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
+ uptr stack_top = t->stack_top();
+ uptr stack_bottom = t->stack_bottom();
+ ScopedUnwinding unwind_scope(t);
+ stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast);
+ } else if (t == 0 && !fast) {
+ /* If GetCurrentThread() has failed, try to do slow unwind anyways. */
+ stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
+ }
}
#endif // SANITIZER_WINDOWS
+}
+
+} // namespace __asan
// NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
// as early as possible (in functions exposed to the user), as we generally
// don't want stack trace to contain functions from ASan internals.
-#define GET_STACK_TRACE(max_size, fast) \
- GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \
- StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), fast)
+#define GET_STACK_TRACE(max_size, fast) \
+ BufferedStackTrace stack; \
+ if (max_size <= 2) { \
+ stack.size = max_size; \
+ if (max_size > 0) { \
+ stack.top_frame_bp = GET_CURRENT_FRAME(); \
+ stack.trace_buffer[0] = StackTrace::GetCurrentPc(); \
+ if (max_size > 1) \
+ stack.trace_buffer[1] = GET_CALLER_PC(); \
+ } \
+ } else { \
+ GetStackTraceWithPcBpAndContext(&stack, max_size, \
+ StackTrace::GetCurrentPc(), \
+ GET_CURRENT_FRAME(), 0, fast); \
+ }
+
+#define GET_STACK_TRACE_FATAL(pc, bp) \
+ BufferedStackTrace stack; \
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0, \
+ common_flags()->fast_unwind_on_fatal)
-#define GET_STACK_TRACE_FATAL(pc, bp) \
- GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp, \
- common_flags()->fast_unwind_on_fatal)
+#define GET_STACK_TRACE_SIGNAL(sig) \
+ BufferedStackTrace stack; \
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, \
+ (sig).pc, (sig).bp, (sig).context, \
+ common_flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_FATAL_HERE \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
+#define GET_STACK_TRACE_CHECK_HERE \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
+
#define GET_STACK_TRACE_THREAD \
GET_STACK_TRACE(kStackTraceMax, true)
@@ -72,11 +99,16 @@ void PrintStack(const uptr *trace, uptr size);
#define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
-#define PRINT_CURRENT_STACK() \
- { \
- GET_STACK_TRACE(kStackTraceMax, \
- common_flags()->fast_unwind_on_fatal); \
- PrintStack(&stack); \
+#define PRINT_CURRENT_STACK() \
+ { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ stack.Print(); \
+ }
+
+#define PRINT_CURRENT_STACK_CHECK() \
+ { \
+ GET_STACK_TRACE_CHECK_HERE; \
+ stack.Print(); \
}
#endif // ASAN_STACK_H
diff --git a/lib/asan/asan_stats.cc b/lib/asan/asan_stats.cc
index 73dc3c5ac44f..a78b7b1e926d 100644
--- a/lib/asan/asan_stats.cc
+++ b/lib/asan/asan_stats.cc
@@ -15,6 +15,7 @@
#include "asan_internal.h"
#include "asan_stats.h"
#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -129,8 +130,8 @@ static void PrintAccumulatedStats() {
BlockingMutexLock lock(&print_lock);
stats.Print();
StackDepotStats *stack_depot_stats = StackDepotGetStats();
- Printf("Stats: StackDepot: %zd ids; %zdM mapped\n",
- stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20);
+ Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
+ stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20);
PrintInternalAllocatorStats();
}
@@ -139,7 +140,7 @@ static void PrintAccumulatedStats() {
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
-uptr __asan_get_current_allocated_bytes() {
+uptr __sanitizer_get_current_allocated_bytes() {
AsanStats stats;
GetAccumulatedStats(&stats);
uptr malloced = stats.malloced;
@@ -149,13 +150,13 @@ uptr __asan_get_current_allocated_bytes() {
return (malloced > freed) ? malloced - freed : 1;
}
-uptr __asan_get_heap_size() {
+uptr __sanitizer_get_heap_size() {
AsanStats stats;
GetAccumulatedStats(&stats);
return stats.mmaped - stats.munmaped;
}
-uptr __asan_get_free_bytes() {
+uptr __sanitizer_get_free_bytes() {
AsanStats stats;
GetAccumulatedStats(&stats);
uptr total_free = stats.mmaped
@@ -169,7 +170,7 @@ uptr __asan_get_free_bytes() {
return (total_free > total_used) ? total_free - total_used : 1;
}
-uptr __asan_get_unmapped_bytes() {
+uptr __sanitizer_get_unmapped_bytes() {
return 0;
}
diff --git a/lib/asan/asan_stats.h b/lib/asan/asan_stats.h
index e3030e88fdc2..c66848dc5713 100644
--- a/lib/asan/asan_stats.h
+++ b/lib/asan/asan_stats.h
@@ -47,9 +47,9 @@ struct AsanStats {
uptr malloc_large;
uptr malloc_small_slow;
- // Ctor for global AsanStats (accumulated stats and main thread stats).
+ // Ctor for global AsanStats (accumulated stats for dead threads).
explicit AsanStats(LinkerInitialized) { }
- // Default ctor for thread-local stats.
+ // Creates empty stats.
AsanStats();
void Print(); // Prints formatted stats to stderr.
diff --git a/lib/asan/asan_suppressions.cc b/lib/asan/asan_suppressions.cc
new file mode 100644
index 000000000000..ef554716faa0
--- /dev/null
+++ b/lib/asan/asan_suppressions.cc
@@ -0,0 +1,87 @@
+//===-- asan_suppressions.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.
+//
+// Issue suppression and suppression-related functions.
+//===----------------------------------------------------------------------===//
+
+#include "asan_suppressions.h"
+
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+namespace __asan {
+
+static bool suppressions_inited = false;
+
+void InitializeSuppressions() {
+ CHECK(!suppressions_inited);
+ SuppressionContext::InitIfNecessary();
+ suppressions_inited = true;
+}
+
+bool IsInterceptorSuppressed(const char *interceptor_name) {
+ CHECK(suppressions_inited);
+ SuppressionContext *ctx = SuppressionContext::Get();
+ Suppression *s;
+ // Match "interceptor_name" suppressions.
+ return ctx->Match(interceptor_name, SuppressionInterceptorName, &s);
+}
+
+bool HaveStackTraceBasedSuppressions() {
+ CHECK(suppressions_inited);
+ SuppressionContext *ctx = SuppressionContext::Get();
+ return ctx->HasSuppressionType(SuppressionInterceptorViaFunction) ||
+ ctx->HasSuppressionType(SuppressionInterceptorViaLibrary);
+}
+
+bool IsStackTraceSuppressed(const StackTrace *stack) {
+ CHECK(suppressions_inited);
+ if (!HaveStackTraceBasedSuppressions())
+ return false;
+
+ SuppressionContext *ctx = SuppressionContext::Get();
+ Symbolizer *symbolizer = Symbolizer::GetOrInit();
+ Suppression *s;
+ for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
+ uptr addr = stack->trace[i];
+
+ if (ctx->HasSuppressionType(SuppressionInterceptorViaLibrary)) {
+ const char *module_name;
+ uptr module_offset;
+ // Match "interceptor_via_lib" suppressions.
+ if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name,
+ &module_offset) &&
+ ctx->Match(module_name, SuppressionInterceptorViaLibrary, &s)) {
+ return true;
+ }
+ }
+
+ if (ctx->HasSuppressionType(SuppressionInterceptorViaFunction)) {
+ SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ const char *function_name = cur->info.function;
+ if (!function_name) {
+ continue;
+ }
+ // Match "interceptor_via_fun" suppressions.
+ if (ctx->Match(function_name, SuppressionInterceptorViaFunction, &s)) {
+ frames->ClearAll();
+ return true;
+ }
+ }
+ frames->ClearAll();
+ }
+ }
+ return false;
+}
+
+} // namespace __asan
diff --git a/lib/asan/asan_suppressions.h b/lib/asan/asan_suppressions.h
new file mode 100644
index 000000000000..cd7ba2ef0ae7
--- /dev/null
+++ b/lib/asan/asan_suppressions.h
@@ -0,0 +1,29 @@
+//===-- asan_suppressions.h -------------------------------------*- 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.
+//
+// ASan-private header for asan_suppressions.cc.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_SUPPRESSIONS_H
+#define ASAN_SUPPRESSIONS_H
+
+#include "asan_internal.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+namespace __asan {
+
+void InitializeSuppressions();
+bool IsInterceptorSuppressed(const char *interceptor_name);
+bool HaveStackTraceBasedSuppressions();
+bool IsStackTraceSuppressed(const StackTrace *stack);
+
+} // namespace __asan
+
+#endif // ASAN_SUPPRESSIONS_H
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index 328ac2fcd398..9af5706d86d0 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -20,16 +20,22 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "lsan/lsan_common.h"
namespace __asan {
// AsanThreadContext implementation.
+struct CreateThreadContextArgs {
+ AsanThread *thread;
+ StackTrace *stack;
+};
+
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
if (args->stack)
- stack_id = StackDepotPut(args->stack->trace, args->stack->size);
+ stack_id = StackDepotPut(*args->stack);
thread = args->thread;
thread->set_context(this);
}
@@ -74,42 +80,44 @@ AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
// AsanThread implementation.
-AsanThread *AsanThread::Create(thread_callback_t start_routine,
- void *arg) {
+AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
+ u32 parent_tid, StackTrace *stack,
+ bool detached) {
uptr PageSize = GetPageSizeCached();
uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
- AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
+ AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
thread->start_routine_ = start_routine;
thread->arg_ = arg;
- thread->context_ = 0;
+ CreateThreadContextArgs args = { thread, stack };
+ asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
+ parent_tid, &args);
return thread;
}
void AsanThread::TSDDtor(void *tsd) {
AsanThreadContext *context = (AsanThreadContext*)tsd;
- if (common_flags()->verbosity >= 1)
- Report("T%d TSDDtor\n", context->tid);
+ VReport(1, "T%d TSDDtor\n", context->tid);
if (context->thread)
context->thread->Destroy();
}
void AsanThread::Destroy() {
- if (common_flags()->verbosity >= 1) {
- Report("T%d exited\n", tid());
- }
+ int tid = this->tid();
+ VReport(1, "T%d exited\n", tid);
malloc_storage().CommitBack();
- if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
- asanThreadRegistry().FinishThread(tid());
+ if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
+ asanThreadRegistry().FinishThread(tid);
FlushToDeadThreadStats(&stats_);
// We also clear the shadow on thread destruction because
// some code may still be executing in later TSD destructors
// and we don't want it to have any poisoned stack.
ClearShadowForThreadStackAndTLS();
- DeleteFakeStack();
+ DeleteFakeStack(tid);
uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
UnmapOrDie(this, size);
+ DTLS_Destroy();
}
// We want to create the FakeStack lazyly on the first use, but not eralier
@@ -124,13 +132,16 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
// 1 -- being initialized
// ptr -- initialized
// This CAS checks if the state was 0 and if so changes it to state 1,
- // if that was successfull, it initilizes the pointer.
+ // if that was successful, it initializes the pointer.
if (atomic_compare_exchange_strong(
reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
memory_order_relaxed)) {
uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
- if (flags()->uar_stack_size_log)
- stack_size_log = static_cast<uptr>(flags()->uar_stack_size_log);
+ CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
+ stack_size_log =
+ Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
+ stack_size_log =
+ Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
fake_stack_ = FakeStack::Create(stack_size_log);
SetTLSFakeStack(fake_stack_);
return fake_stack_;
@@ -139,24 +150,28 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
}
void AsanThread::Init() {
+ fake_stack_ = 0; // Will be initialized lazily if needed.
+ CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls();
+ CHECK_GT(this->stack_size(), 0U);
CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1));
ClearShadowForThreadStackAndTLS();
- if (common_flags()->verbosity >= 1) {
- int local = 0;
- Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
- tid(), (void*)stack_bottom_, (void*)stack_top_,
- stack_top_ - stack_bottom_, &local);
- }
- fake_stack_ = 0; // Will be initialized lazily if needed.
+ int local = 0;
+ VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
+ (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
+ &local);
AsanPlatformThreadInit();
}
-thread_return_t AsanThread::ThreadStart(uptr os_id) {
+thread_return_t AsanThread::ThreadStart(
+ uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
Init();
asanThreadRegistry().StartThread(tid(), os_id, 0);
- if (flags()->use_sigaltstack) SetAlternateSignalStack();
+ if (signal_thread_is_registered)
+ atomic_store(signal_thread_is_registered, 1, memory_order_release);
+
+ if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
if (!start_routine_) {
// start_routine_ == 0 if we're on the main thread or on one of the
@@ -196,17 +211,18 @@ void AsanThread::ClearShadowForThreadStackAndTLS() {
PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
}
-const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
- uptr *frame_pc) {
+bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
+ StackFrameAccess *access) {
uptr bottom = 0;
if (AddrIsInStack(addr)) {
bottom = stack_bottom();
} else if (has_fake_stack()) {
bottom = fake_stack()->AddrIsInFakeStack(addr);
CHECK(bottom);
- *offset = addr - bottom;
- *frame_pc = ((uptr*)bottom)[2];
- return (const char *)((uptr*)bottom)[1];
+ access->offset = addr - bottom;
+ access->frame_pc = ((uptr*)bottom)[2];
+ access->frame_descr = (const char *)((uptr*)bottom)[1];
+ return true;
}
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
@@ -223,15 +239,15 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
}
if (shadow_ptr < shadow_bottom) {
- *offset = 0;
- return "UNKNOWN";
+ return false;
}
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
CHECK(ptr[0] == kCurrentStackFrameMagic);
- *offset = addr - (uptr)ptr;
- *frame_pc = ptr[2];
- return (const char*)ptr[1];
+ access->offset = addr - (uptr)ptr;
+ access->frame_pc = ptr[2];
+ access->frame_descr = (const char*)ptr[1];
+ return true;
}
static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
@@ -268,10 +284,8 @@ AsanThread *GetCurrentThread() {
void SetCurrentThread(AsanThread *t) {
CHECK(t->context());
- if (common_flags()->verbosity >= 2) {
- Report("SetCurrentThread: %p for thread %p\n",
- t->context(), (void*)GetThreadSelf());
- }
+ VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(),
+ (void *)GetThreadSelf());
// Make sure we do not reset the current AsanThread.
CHECK_EQ(0, AsanTSDGet());
AsanTSDSet(t->context());
diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index 11771ecd09f0..9da136c87ef1 100644
--- a/lib/asan/asan_thread.h
+++ b/lib/asan/asan_thread.h
@@ -17,7 +17,6 @@
#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_fake_stack.h"
-#include "asan_stack.h"
#include "asan_stats.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
@@ -56,12 +55,14 @@ COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
// AsanThread are stored in TSD and destroyed when the thread dies.
class AsanThread {
public:
- static AsanThread *Create(thread_callback_t start_routine, void *arg);
+ static AsanThread *Create(thread_callback_t start_routine, void *arg,
+ u32 parent_tid, StackTrace *stack, bool detached);
static void TSDDtor(void *tsd);
void Destroy();
void Init(); // Should be called from the thread itself.
- thread_return_t ThreadStart(uptr os_id);
+ thread_return_t ThreadStart(uptr os_id,
+ atomic_uintptr_t *signal_thread_is_registered);
uptr stack_top() { return stack_top_; }
uptr stack_bottom() { return stack_bottom_; }
@@ -72,18 +73,23 @@ class AsanThread {
AsanThreadContext *context() { return context_; }
void set_context(AsanThreadContext *context) { context_ = context; }
- const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
+ struct StackFrameAccess {
+ uptr offset;
+ uptr frame_pc;
+ const char *frame_descr;
+ };
+ bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
bool AddrIsInStack(uptr addr) {
return addr >= stack_bottom_ && addr < stack_top_;
}
- void DeleteFakeStack() {
+ void DeleteFakeStack(int tid) {
if (!fake_stack_) return;
FakeStack *t = fake_stack_;
fake_stack_ = 0;
SetTLSFakeStack(0);
- t->Destroy();
+ t->Destroy(tid);
}
bool has_fake_stack() {
@@ -101,14 +107,19 @@ class AsanThread {
// True is this thread is currently unwinding stack (i.e. collecting a stack
// trace). Used to prevent deadlocks on platforms where libc unwinder calls
// malloc internally. See PR17116 for more details.
- bool isUnwinding() const { return unwinding; }
- void setUnwinding(bool b) { unwinding = b; }
+ bool isUnwinding() const { return unwinding_; }
+ void setUnwinding(bool b) { unwinding_ = b; }
+
+ // True if we are in a deadly signal handler.
+ bool isInDeadlySignal() const { return in_deadly_signal_; }
+ void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; }
private:
- AsanThread() : unwinding(false) {}
+ // NOTE: There is no AsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
void SetThreadStackAndTls();
void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack();
@@ -116,18 +127,19 @@ class AsanThread {
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
- uptr stack_top_;
- uptr stack_bottom_;
+ uptr stack_top_;
+ uptr stack_bottom_;
// stack_size_ == stack_top_ - stack_bottom_;
// It needs to be set in a async-signal-safe manner.
- uptr stack_size_;
+ uptr stack_size_;
uptr tls_begin_;
uptr tls_end_;
FakeStack *fake_stack_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
- bool unwinding;
+ bool unwinding_;
+ bool in_deadly_signal_;
};
// ScopedUnwinding is a scope for stacktracing member of a context
@@ -142,9 +154,18 @@ class ScopedUnwinding {
AsanThread *thread;
};
-struct CreateThreadContextArgs {
+// ScopedDeadlySignal is a scope for handling deadly signals.
+class ScopedDeadlySignal {
+ public:
+ explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
+ if (thread) thread->setInDeadlySignal(true);
+ }
+ ~ScopedDeadlySignal() {
+ if (thread) thread->setInDeadlySignal(false);
+ }
+
+ private:
AsanThread *thread;
- StackTrace *stack;
};
// Returns a single instance of registry.
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 9e66b3417a1e..4f02b022fe79 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -21,6 +21,7 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
+#include "asan_report.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
@@ -35,11 +36,6 @@ extern "C" {
namespace __asan {
-// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
-static BlockingMutex dbghelp_lock(LINKER_INITIALIZED);
-static bool dbghelp_initialized = false;
-#pragma comment(lib, "dbghelp.lib")
-
// ---------------------- TSD ---------------- {{{1
static bool tsd_key_inited = false;
@@ -75,17 +71,9 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
-void SetAlternateSignalStack() {
- // FIXME: Decide what to do on Windows.
-}
+void AsanCheckDynamicRTPrereqs() {}
-void UnsetAlternateSignalStack() {
- // FIXME: Decide what to do on Windows.
-}
-
-void InstallSignalHandlers() {
- // FIXME: Decide what to do on Windows.
-}
+void AsanCheckIncompatibleRT() {}
void AsanPlatformThreadInit() {
// Nothing here for now.
@@ -95,54 +83,82 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}
-} // namespace __asan
+void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+ UNIMPLEMENTED();
+}
-// ---------------------- Interface ---------------- {{{1
-using namespace __asan; // NOLINT
+static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
-bool __asan_symbolize(const void *addr, char *out_buffer, int buffer_size) {
- BlockingMutexLock lock(&dbghelp_lock);
- if (!dbghelp_initialized) {
- SymSetOptions(SYMOPT_DEFERRED_LOADS |
- SYMOPT_UNDNAME |
- SYMOPT_LOAD_LINES);
- CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
- // FIXME: We don't call SymCleanup() on exit yet - should we?
- dbghelp_initialized = true;
- }
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+ EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
+ CONTEXT *context_record = (CONTEXT*)context;
- // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
- char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
- PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
- symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
- symbol->MaxNameLen = MAX_SYM_NAME;
- DWORD64 offset = 0;
- BOOL got_objname = SymFromAddr(GetCurrentProcess(),
- (DWORD64)addr, &offset, symbol);
- if (!got_objname)
- return false;
-
- DWORD unused;
- IMAGEHLP_LINE64 info;
- info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
- BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
- (DWORD64)addr, &unused, &info);
- int written = 0;
- out_buffer[0] = '\0';
- // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
- if (got_fileline) {
- written += internal_snprintf(out_buffer + written, buffer_size - written,
- " %s %s:%d", symbol->Name,
- info.FileName, info.LineNumber);
- } else {
- written += internal_snprintf(out_buffer + written, buffer_size - written,
- " %s+0x%p", symbol->Name, offset);
+ uptr pc = (uptr)exception_record->ExceptionAddress;
+#ifdef _WIN64
+ uptr bp = (uptr)context_record->Rbp;
+ uptr sp = (uptr)context_record->Rsp;
+#else
+ uptr bp = (uptr)context_record->Ebp;
+ uptr sp = (uptr)context_record->Esp;
+#endif
+ uptr access_addr = exception_record->ExceptionInformation[1];
+
+ return SignalContext(context, access_addr, pc, sp, bp);
+}
+
+static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+ EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
+ CONTEXT *context = info->ContextRecord;
+
+ if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+ exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
+ const char *description =
+ (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ? "access-violation"
+ : "in-page-error";
+ SignalContext sig = SignalContext::Create(exception_record, context);
+ ReportSIGSEGV(description, sig);
}
- return true;
+
+ // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
+
+ return default_seh_handler(info);
+}
+
+// We want to install our own exception handler (EH) to print helpful reports
+// on access violations and whatnot. Unfortunately, the CRT initializers assume
+// they are run before any user code and drop any previously-installed EHs on
+// the floor, so we can't install our handler inside __asan_init.
+// (See crt0dat.c in the CRT sources for the details)
+//
+// Things get even more complicated with the dynamic runtime, as it finishes its
+// initialization before the .exe module CRT begins to initialize.
+//
+// For the static runtime (-MT), it's enough to put a callback to
+// __asan_set_seh_filter in the last section for C initializers.
+//
+// For the dynamic runtime (-MD), we want link the same
+// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
+// will be called for each instrumented module. This ensures that at least one
+// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __asan_set_seh_filter() {
+ // We should only store the previous handler if it's not our own handler in
+ // order to avoid loops in the EH chain.
+ auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+ if (prev_seh_handler != &SEHHandler)
+ default_seh_handler = prev_seh_handler;
+ return 0;
}
-} // extern "C"
+#if !ASAN_DYNAMIC
+// Put a pointer to __asan_set_seh_filter at the end of the global list
+// of C initializers, after the default EH is set by the CRT.
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+static __declspec(allocate(".CRT$XIZ"))
+ int (*__intercept_seh)() = __asan_set_seh_filter;
+#endif
+
+} // namespace __asan
#endif // _WIN32
diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc
new file mode 100644
index 000000000000..b38a2d16087f
--- /dev/null
+++ b/lib/asan/asan_win_dll_thunk.cc
@@ -0,0 +1,376 @@
+//===-- asan_win_dll_thunk.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.
+//
+// This file defines a family of thunks that should be statically linked into
+// the DLLs that have ASan instrumentation in order to delegate the calls to the
+// shared runtime that lives in the main binary.
+// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
+// details.
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dll_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DLL_THUNK
+#include "asan_init_version.h"
+#include "interception/interception.h"
+
+// ---------- Function interception helper functions and macros ----------- {{{1
+extern "C" {
+void *__stdcall GetModuleHandleA(const char *module_name);
+void *__stdcall GetProcAddress(void *module, const char *proc_name);
+void abort();
+}
+
+static void *getRealProcAddressOrDie(const char *name) {
+ void *ret = GetProcAddress(GetModuleHandleA(0), name);
+ if (!ret)
+ abort();
+ return ret;
+}
+
+// We need to intercept some functions (e.g. ASan interface, memory allocator --
+// let's call them "hooks") exported by the DLL thunk and forward the hooks to
+// the runtime in the main module.
+// However, we don't want to keep two lists of these hooks.
+// To avoid that, the list of hooks should be defined using the
+// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
+// at once by calling INTERCEPT_HOOKS().
+
+// Use macro+template magic to automatically generate the list of hooks.
+// Each hook at line LINE defines a template class with a static
+// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
+// The default implementation of FunctionInterceptor<LINE> is to call
+// the Execute() method corresponding to the previous line.
+template<int LINE>
+struct FunctionInterceptor {
+ static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
+};
+
+// There shouldn't be any hooks with negative definition line number.
+template<>
+struct FunctionInterceptor<0> {
+ static void Execute() {}
+};
+
+#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
+ template<> struct FunctionInterceptor<__LINE__> { \
+ static void Execute() { \
+ void *wrapper = getRealProcAddressOrDie(main_function); \
+ if (!__interception::OverrideFunction((uptr)dll_function, \
+ (uptr)wrapper, 0)) \
+ abort(); \
+ FunctionInterceptor<__LINE__-1>::Execute(); \
+ } \
+ };
+
+// Special case of hooks -- ASan own interface functions. Those are only called
+// after __asan_init, thus an empty implementation is sufficient.
+#define INTERFACE_FUNCTION(name) \
+ extern "C" __declspec(noinline) void name() { \
+ volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \
+ __debugbreak(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name)
+
+// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
+#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
+
+// We can't define our own version of strlen etc. because that would lead to
+// link-time or even type mismatch errors. Instead, we can declare a function
+// just to be able to get its address. Me may miss the first few calls to the
+// functions since it can be called before __asan_init, but that would lead to
+// false negatives in the startup code before user's global initializers, which
+// isn't a big deal.
+#define INTERCEPT_LIBRARY_FUNCTION(name) \
+ extern "C" void name(); \
+ INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
+
+// Disable compiler warnings that show up if we declare our own version
+// of a compiler intrinsic (e.g. strlen).
+#pragma warning(disable: 4391)
+#pragma warning(disable: 4392)
+
+static void InterceptHooks();
+// }}}
+
+// ---------- Function wrapping helpers ----------------------------------- {{{1
+#define WRAP_V_V(name) \
+ extern "C" void name() { \
+ typedef void (*fntype)(); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_W(name) \
+ extern "C" void name(void *arg) { \
+ typedef void (*fntype)(void *arg); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_WW(name) \
+ extern "C" void name(void *arg1, void *arg2) { \
+ typedef void (*fntype)(void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg1, arg2); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_WWW(name) \
+ extern "C" void name(void *arg1, void *arg2, void *arg3) { \
+ typedef void *(*fntype)(void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_V(name) \
+ extern "C" void *name() { \
+ typedef void *(*fntype)(); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_W(name) \
+ extern "C" void *name(void *arg) { \
+ typedef void *(*fntype)(void *arg); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WW(name) \
+ extern "C" void *name(void *arg1, void *arg2) { \
+ typedef void *(*fntype)(void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
+ typedef void *(*fntype)(void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
+ typedef void *(*fntype)(void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5) { \
+ typedef void *(*fntype)(void *, void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5, void *arg6) { \
+ typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+// }}}
+
+// ----------------- ASan own interface functions --------------------
+// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
+// want to call it in the __asan_init interceptor.
+WRAP_W_V(__asan_should_detect_stack_use_after_return)
+
+extern "C" {
+ int __asan_option_detect_stack_use_after_return;
+
+ // Manually wrap __asan_init as we need to initialize
+ // __asan_option_detect_stack_use_after_return afterwards.
+ void __asan_init() {
+ typedef void (*fntype)();
+ static fntype fn = 0;
+ // __asan_init is expected to be called by only one thread.
+ if (fn) return;
+
+ fn = (fntype)getRealProcAddressOrDie(__asan_init_name);
+ fn();
+ __asan_option_detect_stack_use_after_return =
+ (__asan_should_detect_stack_use_after_return() != 0);
+
+ InterceptHooks();
+ }
+}
+
+INTERFACE_FUNCTION(__asan_handle_no_return)
+
+INTERFACE_FUNCTION(__asan_report_store1)
+INTERFACE_FUNCTION(__asan_report_store2)
+INTERFACE_FUNCTION(__asan_report_store4)
+INTERFACE_FUNCTION(__asan_report_store8)
+INTERFACE_FUNCTION(__asan_report_store16)
+INTERFACE_FUNCTION(__asan_report_store_n)
+
+INTERFACE_FUNCTION(__asan_report_load1)
+INTERFACE_FUNCTION(__asan_report_load2)
+INTERFACE_FUNCTION(__asan_report_load4)
+INTERFACE_FUNCTION(__asan_report_load8)
+INTERFACE_FUNCTION(__asan_report_load16)
+INTERFACE_FUNCTION(__asan_report_load_n)
+
+INTERFACE_FUNCTION(__asan_store1)
+INTERFACE_FUNCTION(__asan_store2)
+INTERFACE_FUNCTION(__asan_store4)
+INTERFACE_FUNCTION(__asan_store8)
+INTERFACE_FUNCTION(__asan_store16)
+INTERFACE_FUNCTION(__asan_storeN)
+
+INTERFACE_FUNCTION(__asan_load1)
+INTERFACE_FUNCTION(__asan_load2)
+INTERFACE_FUNCTION(__asan_load4)
+INTERFACE_FUNCTION(__asan_load8)
+INTERFACE_FUNCTION(__asan_load16)
+INTERFACE_FUNCTION(__asan_loadN)
+
+INTERFACE_FUNCTION(__asan_memcpy);
+INTERFACE_FUNCTION(__asan_memset);
+INTERFACE_FUNCTION(__asan_memmove);
+
+INTERFACE_FUNCTION(__asan_register_globals)
+INTERFACE_FUNCTION(__asan_unregister_globals)
+
+INTERFACE_FUNCTION(__asan_before_dynamic_init)
+INTERFACE_FUNCTION(__asan_after_dynamic_init)
+
+INTERFACE_FUNCTION(__asan_poison_stack_memory)
+INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
+
+INTERFACE_FUNCTION(__asan_poison_memory_region)
+INTERFACE_FUNCTION(__asan_unpoison_memory_region)
+
+INTERFACE_FUNCTION(__asan_address_is_poisoned)
+INTERFACE_FUNCTION(__asan_region_is_poisoned)
+
+INTERFACE_FUNCTION(__asan_get_current_fake_stack)
+INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
+
+INTERFACE_FUNCTION(__asan_stack_malloc_0)
+INTERFACE_FUNCTION(__asan_stack_malloc_1)
+INTERFACE_FUNCTION(__asan_stack_malloc_2)
+INTERFACE_FUNCTION(__asan_stack_malloc_3)
+INTERFACE_FUNCTION(__asan_stack_malloc_4)
+INTERFACE_FUNCTION(__asan_stack_malloc_5)
+INTERFACE_FUNCTION(__asan_stack_malloc_6)
+INTERFACE_FUNCTION(__asan_stack_malloc_7)
+INTERFACE_FUNCTION(__asan_stack_malloc_8)
+INTERFACE_FUNCTION(__asan_stack_malloc_9)
+INTERFACE_FUNCTION(__asan_stack_malloc_10)
+
+INTERFACE_FUNCTION(__asan_stack_free_0)
+INTERFACE_FUNCTION(__asan_stack_free_1)
+INTERFACE_FUNCTION(__asan_stack_free_2)
+INTERFACE_FUNCTION(__asan_stack_free_4)
+INTERFACE_FUNCTION(__asan_stack_free_5)
+INTERFACE_FUNCTION(__asan_stack_free_6)
+INTERFACE_FUNCTION(__asan_stack_free_7)
+INTERFACE_FUNCTION(__asan_stack_free_8)
+INTERFACE_FUNCTION(__asan_stack_free_9)
+INTERFACE_FUNCTION(__asan_stack_free_10)
+
+INTERFACE_FUNCTION(__sanitizer_cov_module_init)
+
+// TODO(timurrrr): Add more interface functions on the as-needed basis.
+
+// ----------------- Memory allocation functions ---------------------
+WRAP_V_W(free)
+WRAP_V_WW(_free_dbg)
+
+WRAP_W_W(malloc)
+WRAP_W_WWWW(_malloc_dbg)
+
+WRAP_W_WW(calloc)
+WRAP_W_WWWWW(_calloc_dbg)
+WRAP_W_WWW(_calloc_impl)
+
+WRAP_W_WW(realloc)
+WRAP_W_WWW(_realloc_dbg)
+WRAP_W_WWW(_recalloc)
+
+WRAP_W_W(_msize)
+WRAP_W_W(_expand)
+WRAP_W_W(_expand_dbg)
+
+// TODO(timurrrr): Might want to add support for _aligned_* allocation
+// functions to detect a bit more bugs. Those functions seem to wrap malloc().
+
+// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
+
+INTERCEPT_LIBRARY_FUNCTION(atoi);
+INTERCEPT_LIBRARY_FUNCTION(atol);
+INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
+
+// _except_handler4 checks -GS cookie which is different for each module, so we
+// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
+}
+
+INTERCEPT_LIBRARY_FUNCTION(frexp);
+INTERCEPT_LIBRARY_FUNCTION(longjmp);
+INTERCEPT_LIBRARY_FUNCTION(memchr);
+INTERCEPT_LIBRARY_FUNCTION(memcmp);
+INTERCEPT_LIBRARY_FUNCTION(memcpy);
+INTERCEPT_LIBRARY_FUNCTION(memmove);
+INTERCEPT_LIBRARY_FUNCTION(memset);
+INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT
+INTERCEPT_LIBRARY_FUNCTION(strchr);
+INTERCEPT_LIBRARY_FUNCTION(strcmp);
+INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT
+INTERCEPT_LIBRARY_FUNCTION(strlen);
+INTERCEPT_LIBRARY_FUNCTION(strncat);
+INTERCEPT_LIBRARY_FUNCTION(strncmp);
+INTERCEPT_LIBRARY_FUNCTION(strncpy);
+INTERCEPT_LIBRARY_FUNCTION(strnlen);
+INTERCEPT_LIBRARY_FUNCTION(strtol);
+INTERCEPT_LIBRARY_FUNCTION(wcslen);
+
+// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
+// is defined.
+void InterceptHooks() {
+ INTERCEPT_HOOKS();
+ INTERCEPT_FUNCTION(_except_handler4);
+}
+
+// We want to call __asan_init before C/C++ initializers/constructors are
+// executed, otherwise functions like memset might be invoked.
+// For some strange reason, merely linking in asan_preinit.cc doesn't work
+// as the callback is never called... Is link.exe doing something too smart?
+
+// In DLLs, the callbacks are expected to return 0,
+// otherwise CRT initialization fails.
+static int call_asan_init() {
+ __asan_init();
+ return 0;
+}
+#pragma section(".CRT$XIB", long, read) // NOLINT
+__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
+
+#endif // ASAN_DLL_THUNK
diff --git a/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc
new file mode 100644
index 000000000000..3a4de7dbf1fb
--- /dev/null
+++ b/lib/asan/asan_win_dynamic_runtime_thunk.cc
@@ -0,0 +1,52 @@
+//===-- asan_win_uar_thunk.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.
+//
+// This file defines things that need to be present in the application modules
+// to interact with the ASan DLL runtime correctly and can't be implemented
+// using the default "import library" generated when linking the DLL RTL.
+//
+// This includes:
+// - forwarding the detect_stack_use_after_return runtime option
+// - installing a custom SEH handler
+//
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dynamic_runtime_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
+extern "C" {
+__declspec(dllimport) int __asan_set_seh_filter();
+__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
+
+// Define a copy of __asan_option_detect_stack_use_after_return that should be
+// used when linking an MD runtime with a set of object files on Windows.
+//
+// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
+// so normally we would just dllimport it. Unfortunately, the dllimport
+// attribute adds __imp_ prefix to the symbol name of a variable.
+// Since in general we don't know if a given TU is going to be used
+// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
+// just to work around this issue, let's clone the a variable that is
+// constant after initialization anyways.
+int __asan_option_detect_stack_use_after_return =
+ __asan_should_detect_stack_use_after_return();
+
+// Set the ASan-specific SEH handler at the end of CRT initialization of each
+// module (see asan_win.cc for the details).
+//
+// Unfortunately, putting a pointer to __asan_set_seh_filter into
+// __asan_intercept_seh gets optimized out, so we have to use an extra function.
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
+}
+#endif // ASAN_DYNAMIC_RUNTIME_THUNK
diff --git a/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in
deleted file mode 100644
index faef4e8c9b17..000000000000
--- a/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in
+++ /dev/null
@@ -1,13 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Tool-specific config options.
-config.asan_source_dir = "@ASAN_SOURCE_DIR@"
-config.bits = "32"
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
-
diff --git a/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in
deleted file mode 100644
index a35994484d5f..000000000000
--- a/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in
+++ /dev/null
@@ -1,12 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Tool-specific config options.
-config.asan_source_dir = "@ASAN_SOURCE_DIR@"
-config.bits = "64"
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/lib/asan/lit_tests/CMakeLists.txt b/lib/asan/lit_tests/CMakeLists.txt
deleted file mode 100644
index 72a3f5439b70..000000000000
--- a/lib/asan/lit_tests/CMakeLists.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-set(ASAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
-set(ASAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/64bitConfig/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg
- )
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/32bitConfig/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
- )
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
- )
-
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
- set(ASAN_TESTSUITES)
- if(CAN_TARGET_i386)
- list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
- endif()
- if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64)
- list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig)
- endif()
- # Run ASan tests only if we're sure we may produce working binaries.
- set(ASAN_TEST_DEPS
- ${SANITIZER_COMMON_LIT_TEST_DEPS}
- asan_runtime_libraries)
- set(ASAN_TEST_PARAMS
- asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
- if(LLVM_INCLUDE_TESTS)
- list(APPEND ASAN_TEST_DEPS AsanUnitTests)
- list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
- endif()
- add_lit_testsuite(check-asan "Running the AddressSanitizer tests"
- ${ASAN_TESTSUITES}
- PARAMS ${ASAN_TEST_PARAMS}
- DEPENDS ${ASAN_TEST_DEPS})
- set_target_properties(check-asan PROPERTIES FOLDER "ASan tests")
-endif()
diff --git a/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c b/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
deleted file mode 100644
index b453b64cafd2..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// Check the presense of interface symbols in the ASan runtime dylib.
-// If you're changing this file, please also change
-// ../Linux/interface_symbols.c
-
-// RUN: %clang_asan -dead_strip -O2 %s -o %t.exe
-// RUN: rm -f %t.symbols %t.interface
-
-// RUN: nm -g `otool -L %t.exe | grep "asan_osx_dynamic.dylib" | \
-// RUN: tr -d '\011' | \
-// RUN: sed "s/.dylib.*/.dylib/"` \
-// RUN: | grep " T " | sed "s/.* T //" \
-// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
-// RUN: | grep -v "__asan_malloc_hook" \
-// RUN: | grep -v "__asan_free_hook" \
-// RUN: | grep -v "__asan_symbolize" \
-// RUN: | grep -v "__asan_default_options" \
-// RUN: | grep -v "__asan_on_error" > %t.symbols
-
-// RUN: cat %p/../../../asan_interface_internal.h \
-// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
-// RUN: | grep -v "OPTIONAL" \
-// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
-// RUN: > %t.interface
-// RUN: echo __asan_report_load1 >> %t.interface
-// RUN: echo __asan_report_load2 >> %t.interface
-// RUN: echo __asan_report_load4 >> %t.interface
-// RUN: echo __asan_report_load8 >> %t.interface
-// RUN: echo __asan_report_load16 >> %t.interface
-// RUN: echo __asan_report_store1 >> %t.interface
-// RUN: echo __asan_report_store2 >> %t.interface
-// RUN: echo __asan_report_store4 >> %t.interface
-// RUN: echo __asan_report_store8 >> %t.interface
-// RUN: echo __asan_report_store16 >> %t.interface
-// RUN: echo __asan_report_load_n >> %t.interface
-// RUN: echo __asan_report_store_n >> %t.interface
-// RUN: for i in `jot - 0 10`; do echo __asan_stack_malloc_$i >> %t.interface; done
-// RUN: for i in `jot - 0 10`; do echo __asan_stack_free_$i >> %t.interface; done
-
-// RUN: cat %t.interface | sort -u | diff %t.symbols -
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg b/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg
deleted file mode 100644
index a85dfcd24c08..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-if root.host_os not in ['Darwin']:
- config.unsupported = True
diff --git a/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc b/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
deleted file mode 100644
index 807a8283e788..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Regression test for a bug in malloc_create_zone()
-// (https://code.google.com/p/address-sanitizer/issues/detail?id=203)
-// The old implementation of malloc_create_zone() didn't always return a
-// page-aligned address, so we can only test on a best-effort basis.
-
-// RUN: %clangxx_asan %s -o %t
-// RUN: %t 2>&1
-
-#include <malloc/malloc.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-const int kNumIter = 4096;
-const int kNumZones = 100;
-int main() {
- char *mem[kNumIter * 2];
- // Allocate memory chunks from different size classes up to 1 page.
- // (For the case malloc() returns memory chunks in descending order)
- for (int i = 0; i < kNumIter; i++) {
- mem[i] = (char*)malloc(8 * i);
- }
- // Try to allocate a page-aligned malloc zone. Otherwise the mprotect() call
- // in malloc_set_zone_name() will silently fail.
- malloc_zone_t *zone = NULL;
- bool aligned = false;
- for (int i = 0; i < kNumZones; i++) {
- zone = malloc_create_zone(0, 0);
- if (((uintptr_t)zone & (~0xfff)) == (uintptr_t)zone) {
- aligned = true;
- break;
- }
- }
- if (!aligned) {
- printf("Warning: couldn't allocate a page-aligned zone.");
- return 0;
- }
- // malloc_set_zone_name() calls mprotect(zone, 4096, PROT_READ | PROT_WRITE),
- // modifies the zone contents and then calls mprotect(zone, 4096, PROT_READ).
- malloc_set_zone_name(zone, "foobar");
- // Allocate memory chunks from different size classes again.
- for (int i = 0; i < kNumIter; i++) {
- mem[i + kNumIter] = (char*)malloc(8 * i);
- }
- // Access the allocated memory chunks and free them.
- for (int i = 0; i < kNumIter * 2; i++) {
- memset(mem[i], 'a', 8 * (i % kNumIter));
- free(mem[i]);
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc b/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc
deleted file mode 100644
index d5f6c7c12e67..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Make sure the zones created by malloc_create_zone() are write-protected.
-#include <malloc/malloc.h>
-#include <stdio.h>
-
-// RUN: %clangxx_asan %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-
-void *pwn(malloc_zone_t *unused_zone, size_t unused_size) {
- printf("PWNED\n");
- return NULL;
-}
-
-int main() {
- malloc_zone_t *zone = malloc_create_zone(0, 0);
- zone->malloc = pwn;
- void *v = malloc_zone_malloc(zone, 1);
- // CHECK-NOT: PWNED
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc b/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
deleted file mode 100644
index 208fe43ac7e4..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Make sure ASan doesn't hang in an exec loop if DYLD_INSERT_LIBRARIES is set.
-// This is a regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=159
-
-// RUN: %clangxx_asan %s -o %t
-// RUN: %clangxx %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
-// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib
-
-// FIXME: the following command line may hang in the case of a regression.
-// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
-// RUN: %t 2>&1 | FileCheck %s || exit 1
-#include <stdio.h>
-#include <stdlib.h>
-
-int main() {
- const char kEnvName[] = "DYLD_INSERT_LIBRARIES";
- printf("%s=%s\n", kEnvName, getenv(kEnvName));
- // CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}}
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
deleted file mode 100644
index fa0dd4f9df88..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Make sure ASan removes the runtime library from DYLD_INSERT_LIBRARIES before
-// executing other programs.
-
-// RUN: %clangxx_asan %s -o %t
-// RUN: %clangxx %p/../Helpers/echo-env.cc -o %T/echo-env
-// RUN: %clangxx %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
-// RUN: -dynamiclib -o %t-darwin-dummy-shared-lib-so.dylib
-
-// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before
-// execl().
-
-// RUN: %t %T/echo-env >/dev/null 2>&1
-// RUN: DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \
-// RUN: %t %T/echo-env 2>&1 | FileCheck %s || exit 1
-#include <unistd.h>
-int main(int argc, char *argv[]) {
- execl(argv[1], argv[1], "DYLD_INSERT_LIBRARIES", NULL);
- // CHECK: {{DYLD_INSERT_LIBRARIES = .*darwin-dummy-shared-lib-so.dylib.*}}
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc
deleted file mode 100644
index 627115cdda2b..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc
+++ /dev/null
@@ -1,5 +0,0 @@
-// This function is broken, but this file is blacklisted
-int externalBrokenFunction(int argc) {
- char x[10] = {0};
- return x[argc * 10]; // BOOM
-}
diff --git a/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc b/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc
deleted file mode 100644
index 65e91c155c84..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Helper binary for
-// lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
-// Prints the environment variable with the given name.
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char *argv[]) {
- if (argc != 2) {
- printf("Usage: %s ENVNAME\n", argv[0]);
- exit(1);
- }
- const char *value = getenv(argv[1]);
- if (value) {
- printf("%s = %s\n", argv[1], value);
- } else {
- printf("%s not set.\n", argv[1]);
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc
deleted file mode 100644
index e4189d19d099..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <stdio.h>
-
-class C {
- public:
- C() { value = 42; }
- ~C() { }
- int value;
-};
-
-C c;
-
-void AccessC() {
- printf("C value: %d\n", c.value);
-}
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc
deleted file mode 100644
index d4606f0afb52..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc
+++ /dev/null
@@ -1,2 +0,0 @@
-void *bar(void *input);
-void *glob2 = bar((void*)0x2345);
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc
deleted file mode 100644
index 09aed2112d5e..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-int zero_init() { return 0; }
-int badGlobal = zero_init();
-int readBadGlobal() { return badGlobal; }
-
-namespace badNamespace {
-class BadClass {
- public:
- BadClass() { value = 0; }
- int value;
-};
-// Global object with non-trivial constructor.
-BadClass bad_object;
-} // namespace badNamespace
-
-int accessBadObject() { return badNamespace::bad_object.value; }
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc
deleted file mode 100644
index 69455a0a6fc9..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc
+++ /dev/null
@@ -1,4 +0,0 @@
-int zero_init();
-int badSrcGlobal = zero_init();
-int readBadSrcGlobal() { return badSrcGlobal; }
-
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt
deleted file mode 100644
index 83294635622d..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-global:*badGlobal*=init
-type:*badNamespace::BadClass*=init
-src:*initialization-blacklist-extra2.cc=init
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc
deleted file mode 100644
index 3c4cb411defa..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc
+++ /dev/null
@@ -1,5 +0,0 @@
-// This file simply declares a dynamically initialized var by the name of 'y'.
-int initY() {
- return 5;
-}
-int y = initY();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc
deleted file mode 100644
index a3d8f190e58b..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc
+++ /dev/null
@@ -1,6 +0,0 @@
-// 'z' is dynamically initialized global from different TU.
-extern int z;
-int __attribute__((noinline)) initY() {
- return z + 1;
-}
-int y = initY();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc
deleted file mode 100644
index b32466a981b3..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-// Constexpr:
-int getCoolestInteger();
-static int coolest_integer = getCoolestInteger();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc
deleted file mode 100644
index 886165affd76..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-// Linker initialized:
-int getAB();
-static int ab = getAB();
-// Function local statics:
-int countCalls();
-static int one = countCalls();
-// Trivial constructor, non-trivial destructor:
-int getStructWithDtorValue();
-static int val = getStructWithDtorValue();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg b/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg
deleted file mode 100644
index 2fc4d99456b0..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Sources in this directory are helper files for tests which test functionality
-# involving multiple translation units.
-config.suffixes = []
diff --git a/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
deleted file mode 100644
index 0f158c1bb3dd..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Test if asan works with prelink.
-// It does not actually use prelink, but relies on ld's flag -Ttext-segment
-// or gold's flag -Ttext (we try the first flag first, if that fails we
-// try the second flag).
-//
-// RUN: %clangxx_asan -c %s -o %t.o
-// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\
-// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000
-// RUN: %clangxx_asan %t.o %t.so -Wl,-R. -o %t
-// RUN: ASAN_OPTIONS=verbosity=1 %t 2>&1 | FileCheck %s
-
-// REQUIRES: x86_64-supported-target, asan-64-bits
-#if BUILD_SO
-int G;
-int *getG() {
- return &G;
-}
-#else
-#include <stdio.h>
-extern int *getG();
-int main(int argc, char **argv) {
- long p = (long)getG();
- printf("SO mapped at %lx\n", p & ~0xffffffffUL);
- *getG() = 0;
-}
-#endif
-// CHECK: 0x003000000000, 0x004fffffffff{{.*}} MidMem
-// CHECK: SO mapped at 3600000000
diff --git a/lib/asan/lit_tests/TestCases/Linux/clone_test.cc b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
deleted file mode 100644
index 0e12f35b400a..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Regression test for:
-// http://code.google.com/p/address-sanitizer/issues/detail?id=37
-
-// RUN: %clangxx_asan -O0 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && %t | FileCheck %s
-
-#include <stdio.h>
-#include <sched.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-int Child(void *arg) {
- char x[32] = {0}; // Stack gets poisoned.
- printf("Child: %p\n", x);
- _exit(1); // NoReturn, stack will remain unpoisoned unless we do something.
-}
-
-int main(int argc, char **argv) {
- const int kStackSize = 1 << 20;
- char child_stack[kStackSize + 1];
- char *sp = child_stack + kStackSize; // Stack grows down.
- printf("Parent: %p\n", sp);
- pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL, 0, 0, 0);
- int status;
- pid_t wait_result = waitpid(clone_pid, &status, __WCLONE);
- if (wait_result < 0) {
- perror("waitpid");
- return 0;
- }
- if (wait_result == clone_pid && WIFEXITED(status)) {
- // Make sure the child stack was indeed unpoisoned.
- for (int i = 0; i < kStackSize; i++)
- child_stack[i] = i;
- int ret = child_stack[argc - 1];
- printf("PASSED\n");
- // CHECK: PASSED
- return ret;
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/coverage.cc b/lib/asan/lit_tests/TestCases/Linux/coverage.cc
deleted file mode 100644
index 4373e9b13c68..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/coverage.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %t.so -fPIC
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t -Wl,-R. %t.so
-// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
-// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
-// RUN: %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo
-// RUN: %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar
-// RUN: %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef SHARED
-void bar() { printf("bar\n"); }
-#else
-__attribute__((noinline))
-void foo() { printf("foo\n"); }
-extern void bar();
-
-int main(int argc, char **argv) {
- fprintf(stderr, "PID: %d\n", getpid());
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "foo"))
- foo();
- if (!strcmp(argv[i], "bar"))
- bar();
- }
-}
-#endif
-
-// CHECK-main: PID: [[PID:[0-9]+]]
-// CHECK-main: [[PID]].sancov: 1 PCs written
-// CHECK-main-NOT: .so.[[PID]]
-//
-// CHECK-foo: PID: [[PID:[0-9]+]]
-// CHECK-foo: [[PID]].sancov: 2 PCs written
-// CHECK-foo-NOT: .so.[[PID]]
-//
-// CHECK-bar: PID: [[PID:[0-9]+]]
-// CHECK-bar: [[PID]].sancov: 1 PCs written
-// CHECK-bar: .so.[[PID]].sancov: 1 PCs written
-//
-// CHECK-foo-bar: PID: [[PID:[0-9]+]]
-// CHECK-foo-bar: [[PID]].sancov: 2 PCs written
-// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob.cc b/lib/asan/lit_tests/TestCases/Linux/glob.cc
deleted file mode 100644
index 123768b099ed..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/glob.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <glob.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <string>
-
-
-int main(int argc, char *argv[]) {
- std::string path = argv[1];
- std::string pattern = path + "/glob_test_root/*a";
- printf("pattern: %s\n", pattern.c_str());
-
- glob_t globbuf;
- int res = glob(pattern.c_str(), 0, 0, &globbuf);
-
- printf("%d %s\n", errno, strerror(errno));
- assert(res == 0);
- assert(globbuf.gl_pathc == 2);
- printf("%zu\n", strlen(globbuf.gl_pathv[0]));
- printf("%zu\n", strlen(globbuf.gl_pathv[1]));
- globfree(&globbuf);
- printf("PASS\n");
- // CHECK: PASS
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
+++ /dev/null
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
+++ /dev/null
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
+++ /dev/null
diff --git a/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc b/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc
deleted file mode 100644
index 67e9c3718d59..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=183
-
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %t 12 2>&1 | FileCheck %s
-// RUN: not %t 100 2>&1 | FileCheck %s
-// RUN: not %t 10000 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-#include <string.h>
-
-int main(int argc, char *argv[]) {
- int *x = new int[5];
- memset(x, 0, sizeof(x[0]) * 5);
- int index = atoi(argv[1]);
- int res = x[index];
- // CHECK: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
- // CHECK: #0 0x{{.*}} in main {{.*}}heap-overflow-large.cc:[[@LINE-2]]
- // CHECK: AddressSanitizer can not {{(provide additional info|describe address in more detail \(wild memory access suspected\))}}
- // CHECK: SUMMARY: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
- delete[] x;
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
deleted file mode 100644
index 27b179e83624..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
-// RUN: %clangxx_asan -O0 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-__attribute__((noinline))
-char *pretend_to_do_something(char *x) {
- __asm__ __volatile__("" : : "r" (x) : "memory");
- return x;
-}
-
-__attribute__((noinline))
-char *LeakStack() {
- char x[1024];
- memset(x, 0, sizeof(x));
- return pretend_to_do_something(x);
-}
-
-template<size_t kFrameSize>
-__attribute__((noinline))
-void RecuriveFunctionWithStackFrame(int depth) {
- if (depth <= 0) return;
- char x[kFrameSize];
- x[0] = depth;
- pretend_to_do_something(x);
- RecuriveFunctionWithStackFrame<kFrameSize>(depth - 1);
-}
-
-int main(int argc, char **argv) {
- int n_iter = argc >= 2 ? atoi(argv[1]) : 1000;
- int depth = argc >= 3 ? atoi(argv[2]) : 500;
- for (int i = 0; i < n_iter; i++) {
- RecuriveFunctionWithStackFrame<10>(depth);
- RecuriveFunctionWithStackFrame<100>(depth);
- RecuriveFunctionWithStackFrame<500>(depth);
- RecuriveFunctionWithStackFrame<1024>(depth);
- RecuriveFunctionWithStackFrame<2000>(depth);
- RecuriveFunctionWithStackFrame<5000>(depth);
- RecuriveFunctionWithStackFrame<10000>(depth);
- }
- char *stale_stack = LeakStack();
- RecuriveFunctionWithStackFrame<1024>(10);
- stale_stack[100]++;
- // CHECK: ERROR: AddressSanitizer: stack-use-after-return on address
- // CHECK: is located in stack of thread T0 at offset 132 in frame
- // CHECK: in LeakStack(){{.*}}heavy_uar_test.cc:
- // CHECK: [32, 1056) 'x'
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
deleted file mode 100644
index 042a07e428d9..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Test to make sure basic initialization order errors are caught.
-// Check that on Linux initialization order bugs are caught
-// independently on order in which we list source files (if we specify
-// strict init-order checking).
-
-// RUN: %clangxx_asan -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s
-
-// Do not test with optimization -- the error may be optimized away.
-
-#include <cstdio>
-
-// 'y' is a dynamically initialized global residing in a different TU. This
-// dynamic initializer will read the value of 'y' before main starts. The
-// result is undefined behavior, which should be caught by initialization order
-// checking.
-extern int y;
-int __attribute__((noinline)) initX() {
- return y + 1;
- // CHECK: {{AddressSanitizer: initialization-order-fiasco}}
- // CHECK: {{READ of size .* at 0x.* thread T0}}
- // CHECK: {{#0 0x.* in .*initX.* .*initialization-bug-any-order.cc:}}[[@LINE-3]]
- // CHECK: {{0x.* is located 0 bytes inside of global variable .*y.*}}
-}
-
-// This initializer begins our initialization order problems.
-static int x = initX();
-
-int main() {
- // ASan should have caused an exit before main runs.
- printf("PASS\n");
- // CHECK-NOT: PASS
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
deleted file mode 100644
index 9d161aa2dccb..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// If user provides his own libc functions, ASan doesn't
-// intercept these functions.
-
-// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-
-extern "C" long strtol(const char *nptr, char **endptr, int base) {
- fprintf(stderr, "my_strtol_interceptor\n");
- return 0;
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return (int)strtol(x, 0, 10);
- // CHECK: my_strtol_interceptor
- // CHECK-NOT: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
deleted file mode 100644
index cdd7239ab7bc..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// ASan interceptor can be accessed with __interceptor_ prefix.
-
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" void *__interceptor_malloc(size_t size);
-extern "C" void *malloc(size_t size) {
- write(2, "malloc call\n", sizeof("malloc call\n") - 1);
- return __interceptor_malloc(size);
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return (int)strtol(x, 0, 10);
- // CHECK: malloc call
- // CHECK: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
deleted file mode 100644
index 198e1f3884dd..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-//
-// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-
-#include <dirent.h>
-#include <memory.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-
-int main() {
- // Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent
- // as written when the end of the directory pointer is reached.
- fputs("test1: reading the " TEMP_DIR " directory...\n", stderr);
- DIR *d = opendir(TEMP_DIR);
- struct dirent *result = (struct dirent *)(0xfeedbeef);
- // We assume the temp dir for this test doesn't have crazy long file names.
- char entry_buffer[4096];
- memset(entry_buffer, 0xab, sizeof(entry_buffer));
- unsigned count = 0;
- do {
- // Stamp the entry struct to try to trick the interceptor.
- ((struct dirent *)entry_buffer)->d_reclen = 9999;
- if (readdir_r(d, (struct dirent *)entry_buffer, &result) != 0)
- abort();
- ++count;
- } while (result != NULL);
- fprintf(stderr, "read %d entries\n", count);
- closedir(d);
- // CHECK: test1: reading the {{.*}} directory...
- // CHECK-NOT: stack-buffer-overflow
- // CHECK: read {{.*}} entries
-
- // Ensure the readdir64_r interceptor doesn't have the bug either.
- fputs("test2: reading the " TEMP_DIR " directory...\n", stderr);
- d = opendir(TEMP_DIR);
- struct dirent64 *result64;
- memset(entry_buffer, 0xab, sizeof(entry_buffer));
- count = 0;
- do {
- // Stamp the entry struct to try to trick the interceptor.
- ((struct dirent64 *)entry_buffer)->d_reclen = 9999;
- if (readdir64_r(d, (struct dirent64 *)entry_buffer, &result64) != 0)
- abort();
- ++count;
- } while (result64 != NULL);
- fprintf(stderr, "read %d entries\n", count);
- closedir(d);
- // CHECK: test2: reading the {{.*}} directory...
- // CHECK-NOT: stack-buffer-overflow
- // CHECK: read {{.*}} entries
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
deleted file mode 100644
index 2b3316d7dc8a..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// ASan interceptor can be accessed with __interceptor_ prefix.
-
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-
-extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
-extern "C" long strtol(const char *nptr, char **endptr, int base) {
- fprintf(stderr, "my_strtol_interceptor\n");
- return __interceptor_strtol(nptr, endptr, base);
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return (int)strtol(x, 0, 10);
- // CHECK: my_strtol_interceptor
- // CHECK: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
deleted file mode 100644
index d6ceda7af8b6..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
+++ /dev/null
@@ -1,35 +0,0 @@
-// Check the presense of interface symbols in compiled file.
-
-// RUN: %clang_asan -O2 %s -o %t.exe
-// RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \
-// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
-// RUN: | grep -v "__asan_malloc_hook" \
-// RUN: | grep -v "__asan_free_hook" \
-// RUN: | grep -v "__asan_symbolize" \
-// RUN: | grep -v "__asan_default_options" \
-// RUN: | grep -v "__asan_stack_" \
-// RUN: | grep -v "__asan_on_error" > %t.symbols
-// RUN: cat %p/../../../asan_interface_internal.h \
-// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
-// RUN: | grep -v "OPTIONAL" \
-// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
-// RUN: > %t.interface
-// RUN: echo __asan_report_load1 >> %t.interface
-// RUN: echo __asan_report_load2 >> %t.interface
-// RUN: echo __asan_report_load4 >> %t.interface
-// RUN: echo __asan_report_load8 >> %t.interface
-// RUN: echo __asan_report_load16 >> %t.interface
-// RUN: echo __asan_report_store1 >> %t.interface
-// RUN: echo __asan_report_store2 >> %t.interface
-// RUN: echo __asan_report_store4 >> %t.interface
-// RUN: echo __asan_report_store8 >> %t.interface
-// RUN: echo __asan_report_store16 >> %t.interface
-// RUN: echo __asan_report_load_n >> %t.interface
-// RUN: echo __asan_report_store_n >> %t.interface
-// RUN: cat %t.interface | sort -u | diff %t.symbols -
-
-// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
-// in "initialized data section".
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg b/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
deleted file mode 100644
index 57271b8078a4..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-if root.host_os not in ['Linux']:
- config.unsupported = True
diff --git a/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
deleted file mode 100644
index 3251b35e143c..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
-// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
-
-// Test how well we unwind in presence of qsort in the stack
-// (i.e. if we can unwind through a function compiled w/o frame pointers).
-// https://code.google.com/p/address-sanitizer/issues/detail?id=137
-
-// Fast unwinder is only avaliable on x86_64 and i386.
-// REQUIRES: x86_64-supported-target
-
-// REQUIRES: compiler-rt-optimized
-
-#include <stdlib.h>
-#include <stdio.h>
-
-int *GlobalPtr;
-
-extern "C" {
-int QsortCallback(const void *a, const void *b) {
- char *x = (char*)a;
- char *y = (char*)b;
- printf("Calling QsortCallback\n");
- GlobalPtr = new int[10];
- return (int)*x - (int)*y;
-}
-
-__attribute__((noinline))
-void MyQsort(char *a, size_t size) {
- printf("Calling qsort\n");
- qsort(a, size, sizeof(char), QsortCallback);
- printf("Done\n"); // Avoid tail call.
-}
-} // extern "C"
-
-int main() {
- char a[2] = {1, 2};
- MyQsort(a, 2);
- return GlobalPtr[10];
-}
-
-// Fast unwind: can not unwind through qsort.
-// FIXME: this test does not properly work with slow unwind yet.
-
-// CHECK-FAST: ERROR: AddressSanitizer: heap-buffer-overflow
-// CHECK-FAST: is located 0 bytes to the right
-// CHECK-FAST: #0{{.*}}operator new
-// CHECK-FAST-NEXT: #1{{.*}}QsortCallback
-// CHECK-FAST-NOT: MyQsort
-//
-// CHECK-SLOW: ERROR: AddressSanitizer: heap-buffer-overflow
-// CHECK-SLOW: is located 0 bytes to the right
-// CHECK-SLOW: #0{{.*}}operator new
-// CHECK-SLOW-NEXT: #1{{.*}}QsortCallback
-// CHECK-SLOW: #{{.*}}MyQsort
-// CHECK-SLOW-NEXT: #{{.*}}main
diff --git a/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
deleted file mode 100644
index 7010eb2de2e7..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Check that we detect malloc/delete mismatch only if the approptiate flag
-// is set.
-
-// RUN: %clangxx_asan -g %s -o %t 2>&1
-
-// Find error and provide malloc context.
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALLOC-STACK
-
-// No error here.
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %t
-
-// Also works if no malloc context is available.
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-
-static volatile char *x;
-
-int main() {
- x = (char*)malloc(10);
- x[0] = 0;
- delete x;
-}
-// CHECK: ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator delete) on 0x
-// CHECK-NEXT: #0{{.*}}operator delete
-// CHECK: #{{.*}}main
-// CHECK: is located 0 bytes inside of 10-byte region
-// CHECK-NEXT: allocated by thread T0 here:
-// ALLOC-STACK-NEXT: #0{{.*}}malloc
-// ALLOC-STACK: #{{.*}}main
-// CHECK: HINT: {{.*}} you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0
diff --git a/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
deleted file mode 100644
index 139977261ec9..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
-// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
-
-// Test how well we unwind in presence of qsort in the stack
-// (i.e. if we can unwind through a function compiled w/o frame pointers).
-// https://code.google.com/p/address-sanitizer/issues/detail?id=137
-
-// Fast unwinder is only avaliable on x86_64 and i386.
-// REQUIRES: x86_64-supported-target
-
-#include <stdlib.h>
-#include <stdio.h>
-
-int global_array[10];
-volatile int one = 1;
-
-extern "C" {
-int QsortCallback(const void *a, const void *b) {
- char *x = (char*)a;
- char *y = (char*)b;
- printf("Calling QsortCallback\n");
- global_array[one * 10] = 0; // BOOM
- return (int)*x - (int)*y;
-}
-
-__attribute__((noinline))
-void MyQsort(char *a, size_t size) {
- printf("Calling qsort\n");
- qsort(a, size, sizeof(char), QsortCallback);
- printf("Done\n"); // Avoid tail call.
-}
-} // extern "C"
-
-int main() {
- char a[2] = {1, 2};
- MyQsort(a, 2);
-}
-
-// Fast unwind: can not unwind through qsort.
-
-// CHECK-FAST: ERROR: AddressSanitizer: global-buffer-overflow
-// CHECK-FAST: #0{{.*}} in QsortCallback
-// CHECK-FAST-NOT: MyQsort
-// CHECK-FAST: is located 0 bytes to the right of global variable 'global_array
-
-// CHECK-SLOW: ERROR: AddressSanitizer: global-buffer-overflow
-// CHECK-SLOW: #0{{.*}} in QsortCallback
-// CHECK-SLOW: #{{.*}} in MyQsort
-// CHECK-SLOW: #{{.*}} in main
-// CHECK-SLOW: is located 0 bytes to the right of global variable 'global_array
diff --git a/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
deleted file mode 100644
index 28e509472c0c..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx -DFUNC=zzzz %s -shared -o %t.so -fPIC
-// RUN: %clangxx_asan -DFUNC=main %s -o %t -Wl,-R. %t.so
-// RUN: %t
-
-// This test ensures that we call __asan_init early enough.
-// We build a shared library w/o asan instrumentation
-// and the binary with asan instrumentation.
-// Both files include the same header (emulated by -DFUNC here)
-// with C++ template magic which runs global initializer at library load time.
-// The function get() is instrumented with asan, but called
-// before the usual constructors are run.
-// So, we must make sure that __asan_init is executed even earlier.
-//
-// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56393
-
-struct A {
- int foo() const { return 0; }
-};
-A get () { return A(); }
-template <class> struct O {
- static A const e;
-};
-template <class T> A const O <T>::e = get();
-int FUNC() {
- return O<int>::e.foo();
-}
-
diff --git a/lib/asan/lit_tests/TestCases/Linux/ptrace.cc b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
deleted file mode 100644
index 8831b81efa96..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-// RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <stdio.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/user.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-int main(void) {
- pid_t pid;
- pid = fork();
- if (pid == 0) { // child
- ptrace(PTRACE_TRACEME, 0, NULL, NULL);
- execl("/bin/true", "true", NULL);
- } else {
- wait(NULL);
- user_regs_struct regs;
- int res;
- user_regs_struct * volatile pregs = &regs;
-#ifdef POSITIVE
- ++pregs;
-#endif
- res = ptrace(PTRACE_GETREGS, pid, NULL, pregs);
- // CHECK: AddressSanitizer: stack-buffer-overflow
- // CHECK: {{.*ptrace.cc:}}[[@LINE-2]]
- assert(!res);
-#if __WORDSIZE == 64
- printf("%zx\n", regs.rip);
-#else
- printf("%lx\n", regs.eip);
-#endif
-
- user_fpregs_struct fpregs;
- res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
- assert(!res);
- printf("%lx\n", (unsigned long)fpregs.cwd);
-
-#if __WORDSIZE == 32
- user_fpxregs_struct fpxregs;
- res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs);
- assert(!res);
- printf("%lx\n", (unsigned long)fpxregs.mxcsr);
-#endif
-
- ptrace(PTRACE_CONT, pid, NULL, NULL);
- wait(NULL);
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
deleted file mode 100644
index 0d1d4baa7671..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Check that we properly report mmap failure.
-// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <assert.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-static volatile void *x;
-
-int main(int argc, char **argv) {
- struct rlimit mmap_resource_limit = { 0, 0 };
- assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
- x = malloc(10000000);
-// CHECK: ERROR: Failed to mmap
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
deleted file mode 100644
index 6cbb69a35321..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Check that ASan plays well with easy cases of makecontext/swapcontext.
-
-// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
-//
-// This test is too sublte to try on non-x86 arch for now.
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-#include <stdio.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-ucontext_t orig_context;
-ucontext_t child_context;
-
-const int kStackSize = 1 << 20;
-
-__attribute__((noinline))
-void Throw() {
- throw 1;
-}
-
-__attribute__((noinline))
-void ThrowAndCatch() {
- try {
- Throw();
- } catch(int a) {
- printf("ThrowAndCatch: %d\n", a);
- }
-}
-
-void Child(int mode) {
- char x[32] = {0}; // Stack gets poisoned.
- printf("Child: %p\n", x);
- ThrowAndCatch(); // Simulate __asan_handle_no_return().
- // (a) Do nothing, just return to parent function.
- // (b) Jump into the original function. Stack remains poisoned unless we do
- // something.
- if (mode == 1) {
- if (swapcontext(&child_context, &orig_context) < 0) {
- perror("swapcontext");
- _exit(0);
- }
- }
-}
-
-int Run(int arg, int mode, char *child_stack) {
- printf("Child stack: %p\n", child_stack);
- // Setup child context.
- getcontext(&child_context);
- child_context.uc_stack.ss_sp = child_stack;
- child_context.uc_stack.ss_size = kStackSize / 2;
- if (mode == 0) {
- child_context.uc_link = &orig_context;
- }
- makecontext(&child_context, (void (*)())Child, 1, mode);
- if (swapcontext(&orig_context, &child_context) < 0) {
- perror("swapcontext");
- return 0;
- }
- // Touch childs's stack to make sure it's unpoisoned.
- for (int i = 0; i < kStackSize; i++) {
- child_stack[i] = i;
- }
- return child_stack[arg];
-}
-
-int main(int argc, char **argv) {
- char stack[kStackSize + 1];
- // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
- int ret = 0;
- ret += Run(argc - 1, 0, stack);
- printf("Test1 passed\n");
- // CHECK: Test1 passed
- ret += Run(argc - 1, 1, stack);
- printf("Test2 passed\n");
- // CHECK: Test2 passed
- char *heap = new char[kStackSize + 1];
- ret += Run(argc - 1, 0, heap);
- printf("Test3 passed\n");
- // CHECK: Test3 passed
- ret += Run(argc - 1, 1, heap);
- printf("Test4 passed\n");
- // CHECK: Test4 passed
-
- delete [] heap;
- return ret;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/syscalls.cc b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
deleted file mode 100644
index 4bcbe446113e..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <errno.h>
-#include <glob.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <sanitizer/linux_syscall_hooks.h>
-
-/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
- sanity of their behaviour. */
-
-int main(int argc, char *argv[]) {
- char buf[1000];
- __sanitizer_syscall_pre_recvmsg(0, buf - 1, 0);
- // CHECK: AddressSanitizer: stack-buffer-{{.*}}erflow
- // CHECK: READ of size {{.*}} at {{.*}} thread T0
- // CHECK: #0 {{.*}} in __sanitizer_syscall{{.*}}recvmsg
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
deleted file mode 100644
index 566409be6a19..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | FileCheck %s
-
-// Zero-base shadow only works on x86_64 and i386.
-// REQUIRES: x86_64-supported-target
-
-// A regression test for time(NULL), which caused ASan to crash in the
-// zero-based shadow mode on Linux.
-// FIXME: this test does not work on Darwin, because the code pages of the
-// executable interleave with the zero-based shadow.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-int main() {
- time_t t = time(NULL);
- fprintf(stderr, "Time: %s\n", ctime(&t)); // NOLINT
- // CHECK: {{Time: .* .* .*}}
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc b/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc
deleted file mode 100644
index a1d89ee437d4..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Regression test for a leak in tsd:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=233
-// RUN: %clangxx_asan -O1 %s -o %t
-// RUN: ASAN_OPTIONS=quarantine_size=1 %t
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-extern "C" size_t __asan_get_heap_size();
-static pthread_key_t tsd_key;
-
-void *Thread(void *) {
- pthread_setspecific(tsd_key, malloc(10));
- return 0;
-}
-
-static volatile void *v;
-
-void Dtor(void *tsd) {
- v = malloc(10000);
- free(tsd);
- free((void*)v); // The bug was that this was leaking.
-}
-
-int main() {
- assert(0 == pthread_key_create(&tsd_key, Dtor));
- size_t old_heap_size = 0;
- for (int i = 0; i < 10; i++) {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
- size_t new_heap_size = __asan_get_heap_size();
- fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size, old_heap_size);
- if (old_heap_size)
- assert(old_heap_size == new_heap_size);
- old_heap_size = new_heap_size;
- }
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc
deleted file mode 100644
index 9663859dfefd..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// This test shows that the current implementation of use-after-return is
-// not signal-safe.
-// RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t
-// RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <pthread.h>
-
-int *g;
-int n_signals;
-
-typedef void (*Sigaction)(int, siginfo_t *, void *);
-
-void SignalHandler(int, siginfo_t*, void*) {
- int local;
- g = &local;
- n_signals++;
- // printf("s: %p\n", &local);
-}
-
-static void EnableSigprof(Sigaction SignalHandler) {
- struct sigaction sa;
- sa.sa_sigaction = SignalHandler;
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- sigemptyset(&sa.sa_mask);
- if (sigaction(SIGPROF, &sa, NULL) != 0) {
- perror("sigaction");
- abort();
- }
- struct itimerval timer;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = 1;
- timer.it_value = timer.it_interval;
- if (setitimer(ITIMER_PROF, &timer, 0) != 0) {
- perror("setitimer");
- abort();
- }
-}
-
-void RecursiveFunction(int depth) {
- if (depth == 0) return;
- int local;
- g = &local;
- // printf("r: %p\n", &local);
- // printf("[%2d] n_signals: %d\n", depth, n_signals);
- RecursiveFunction(depth - 1);
- RecursiveFunction(depth - 1);
-}
-
-void *Thread(void *) {
- RecursiveFunction(18);
- return NULL;
-}
-
-int main(int argc, char **argv) {
- EnableSigprof(SignalHandler);
-
- for (int i = 0; i < 4; i++) {
- fprintf(stderr, ".");
- const int kNumThread = sizeof(void*) == 8 ? 16 : 8;
- pthread_t t[kNumThread];
- for (int i = 0; i < kNumThread; i++)
- pthread_create(&t[i], 0, Thread, 0);
- for (int i = 0; i < kNumThread; i++)
- pthread_join(t[i], 0);
- }
- fprintf(stderr, "\n");
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
deleted file mode 100644
index d67c4f954e43..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Test that TLS is unpoisoned on thread death.
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-
-#include <sanitizer/asan_interface.h>
-
-__thread int64_t tls_var[2];
-
-volatile int64_t *p_tls_var;
-
-void *first(void *arg) {
- ASAN_POISON_MEMORY_REGION(&tls_var, sizeof(tls_var));
- p_tls_var = tls_var;
- return 0;
-}
-
-void *second(void *arg) {
- assert(tls_var == p_tls_var);
- *p_tls_var = 1;
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- pthread_t p;
- assert(0 == pthread_create(&p, 0, first, 0));
- assert(0 == pthread_join(p, 0));
- assert(0 == pthread_create(&p, 0, second, 0));
- assert(0 == pthread_join(p, 0));
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
deleted file mode 100644
index e6bcc5597471..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-// Zero-base shadow only works on x86_64 and i386.
-// REQUIRES: i386-supported-target, asan-32-bits
-
-#include <string.h>
-int main(int argc, char **argv) {
- char x[10];
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*zero-base-shadow32.cc:}}[[@LINE-2]]
- // CHECK: {{Address 0x.* is .* frame}}
- // CHECK: main
-
- // Check that shadow for stack memory occupies lower part of address space.
- // CHECK: =>0x1
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
deleted file mode 100644
index 1db725c95752..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-// Zero-base shadow only works on x86_64 and i386.
-// REQUIRES: x86_64-supported-target, asan-64-bits
-
-#include <string.h>
-int main(int argc, char **argv) {
- char x[10];
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*zero-base-shadow64.cc:}}[[@LINE-2]]
- // CHECK: {{Address 0x.* is .* frame}}
- // CHECK: main
-
- // Check that shadow for stack memory occupies lower part of address space.
- // CHECK: =>0x0f
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc
deleted file mode 100644
index 5d939991476e..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-//===----------- darwin-dummy-shared-lib-so.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.
-//
-//===----------------------------------------------------------------------===//
-void foo() {}
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc
deleted file mode 100644
index 73e00507358a..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-//===----------- dlclose-test-so.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/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc
deleted file mode 100644
index dc097a520d03..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" void inc_global();
-
-int slow_init() {
- sleep(1);
- inc_global();
- return 42;
-}
-
-int slowly_init_glob = slow_init();
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg b/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg
deleted file mode 100644
index b3677c17a0f2..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-# Sources in this directory are compiled as shared libraries and used by
-# tests in parent directory.
-
-config.suffixes = []
diff --git a/lib/asan/lit_tests/TestCases/allocator_returns_null.cc b/lib/asan/lit_tests/TestCases/allocator_returns_null.cc
deleted file mode 100644
index 595c9e252f86..000000000000
--- a/lib/asan/lit_tests/TestCases/allocator_returns_null.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
-// By default (allocator_may_return_null=0) the process should crash.
-// With allocator_may_return_null=1 the allocator should return 0.
-//
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
-
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <limits>
-int main(int argc, char **argv) {
- volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
- assert(argc == 2);
- char *x = 0;
- if (!strcmp(argv[1], "malloc")) {
- fprintf(stderr, "malloc:\n");
- x = (char*)malloc(size);
- }
- if (!strcmp(argv[1], "calloc")) {
- fprintf(stderr, "calloc:\n");
- x = (char*)calloc(size / 4, 4);
- }
-
- if (!strcmp(argv[1], "calloc-overflow")) {
- fprintf(stderr, "calloc-overflow:\n");
- volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
- size_t kArraySize = 4096;
- volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
- x = (char*)calloc(kArraySize, kArraySize2);
- }
-
- if (!strcmp(argv[1], "realloc")) {
- fprintf(stderr, "realloc:\n");
- x = (char*)realloc(0, size);
- }
- if (!strcmp(argv[1], "realloc-after-malloc")) {
- fprintf(stderr, "realloc-after-malloc:\n");
- char *t = (char*)malloc(100);
- *t = 42;
- x = (char*)realloc(t, size);
- assert(*t == 42);
- }
- // The NULL pointer is printed differently on different systems, while (long)0
- // is always the same.
- fprintf(stderr, "x: %lx\n", (long)x);
- return x != 0;
-}
-// CHECK-mCRASH: malloc:
-// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process
-// CHECK-cCRASH: calloc:
-// CHECK-cCRASH: AddressSanitizer's allocator is terminating the process
-// CHECK-coCRASH: calloc-overflow:
-// CHECK-coCRASH: AddressSanitizer's allocator is terminating the process
-// CHECK-rCRASH: realloc:
-// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process
-// CHECK-mrCRASH: realloc-after-malloc:
-// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process
-
-// CHECK-mNULL: malloc:
-// CHECK-mNULL: x: 0
-// CHECK-cNULL: calloc:
-// CHECK-cNULL: x: 0
-// CHECK-coNULL: calloc-overflow:
-// CHECK-coNULL: x: 0
-// CHECK-rNULL: realloc:
-// CHECK-rNULL: x: 0
-// CHECK-mrNULL: realloc-after-malloc:
-// CHECK-mrNULL: x: 0
diff --git a/lib/asan/lit_tests/TestCases/allow_user_segv.cc b/lib/asan/lit_tests/TestCases/allow_user_segv.cc
deleted file mode 100644
index 55cf6044e7a0..000000000000
--- a/lib/asan/lit_tests/TestCases/allow_user_segv.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=180
-
-// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %t 2>&1 | FileCheck %s
-
-#include <signal.h>
-#include <stdio.h>
-
-struct sigaction user_sigaction;
-struct sigaction original_sigaction;
-
-void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) {
- fprintf(stderr, "User sigaction called\n");
- if (original_sigaction.sa_flags | SA_SIGINFO)
- original_sigaction.sa_sigaction(signum, siginfo, context);
- else
- original_sigaction.sa_handler(signum);
-}
-
-int DoSEGV() {
- volatile int *x = 0;
- return *x;
-}
-
-int main() {
- user_sigaction.sa_sigaction = User_OnSIGSEGV;
- user_sigaction.sa_flags = SA_SIGINFO;
-#if defined(__APPLE__) && !defined(__LP64__)
- // On 32-bit Darwin KERN_PROTECTION_FAILURE (SIGBUS) is delivered.
- int signum = SIGBUS;
-#else
- // On 64-bit Darwin KERN_INVALID_ADDRESS (SIGSEGV) is delivered.
- // On Linux SIGSEGV is delivered as well.
- int signum = SIGSEGV;
-#endif
- if (sigaction(signum, &user_sigaction, &original_sigaction)) {
- perror("sigaction");
- return 1;
- }
- fprintf(stderr, "User sigaction installed\n");
- return DoSEGV();
-}
-
-// CHECK: User sigaction installed
-// CHECK-NEXT: User sigaction called
-// CHECK-NEXT: ASAN:SIGSEGV
-// CHECK: AddressSanitizer: SEGV on unknown address
diff --git a/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc b/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc
deleted file mode 100644
index 0efe245bb6b5..000000000000
--- a/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Check that asan_symbolize.py script works (for binaries, ASan RTL and
-// shared object files.
-
-// RUN: %clangxx_asan -O0 %p/SharedLibs/shared-lib-test-so.cc -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: ASAN_SYMBOLIZER_PATH= not %t 2>&1 | %asan_symbolize | FileCheck %s
-#include <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <string>
-
-using std::string;
-
-typedef void (fun_t)(int*, int);
-
-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 *inc2 = (fun_t*)dlsym(lib, "inc2");
- if (!inc2) return 1;
- printf("ok\n");
- int *array = (int*)malloc(40);
- inc2(array, 1);
- inc2(array, -1); // BOOM
- // CHECK: ERROR: AddressSanitizer: heap-buffer-overflow
- // CHECK: READ of size 4 at 0x{{.*}}
- // CHECK: #0 {{.*}} in inc2 {{.*}}shared-lib-test-so.cc:25
- // CHECK: #1 {{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-4]]
- // CHECK: allocated by thread T{{.*}} here:
- // CHECK: #{{.*}} in {{(wrap_|__interceptor_)?}}malloc
- // CHECK: #{{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-9]]
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc b/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
deleted file mode 100644
index b0a501576945..000000000000
--- a/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Make sure we don't report a leak nor hang.
-// RUN: %clangxx_asan -O3 %s -o %t && %t
-#include <stdlib.h>
-#ifndef __APPLE__
-#include <malloc.h>
-#endif // __APPLE__
-int *p = (int*)valloc(1 << 20);
-int main() { }
diff --git a/lib/asan/lit_tests/TestCases/atexit_stats.cc b/lib/asan/lit_tests/TestCases/atexit_stats.cc
deleted file mode 100644
index e3b1269d25cc..000000000000
--- a/lib/asan/lit_tests/TestCases/atexit_stats.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Make sure we report atexit stats.
-// RUN: %clangxx_asan -O3 %s -o %t
-// RUN: ASAN_OPTIONS=atexit=1:print_stats=1 %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#if !defined(__APPLE__)
-#include <malloc.h>
-#endif
-int *p1 = (int*)malloc(900);
-int *p2 = (int*)malloc(90000);
-int *p3 = (int*)malloc(9000000);
-int main() { }
-
-// CHECK: AddressSanitizer exit stats:
diff --git a/lib/asan/lit_tests/TestCases/blacklist.cc b/lib/asan/lit_tests/TestCases/blacklist.cc
deleted file mode 100644
index 46625ee7bdb5..000000000000
--- a/lib/asan/lit_tests/TestCases/blacklist.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Test the blacklist functionality of ASan
-
-// RUN: echo "fun:*brokenFunction*" > %tmp
-// RUN: echo "global:*badGlobal*" >> %tmp
-// RUN: echo "src:*blacklist-extra.cc" >> %tmp
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O0 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O1 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O2 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O3 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-
-// badGlobal is accessed improperly, but we blacklisted it. Align
-// it to make sure memory past the end of badGlobal will be in
-// the same page.
-__attribute__((aligned(16))) int badGlobal;
-int readBadGlobal() {
- return (&badGlobal)[1];
-}
-
-// A function which is broken, but excluded in the blacklist.
-int brokenFunction(int argc) {
- char x[10] = {0};
- return x[argc * 10]; // BOOM
-}
-
-// This function is defined in Helpers/blacklist-extra.cc, a source file which
-// is blacklisted by name
-int externalBrokenFunction(int x);
-
-int main(int argc, char **argv) {
- brokenFunction(argc);
- int x = readBadGlobal();
- externalBrokenFunction(argc);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/contiguous_container.cc b/lib/asan/lit_tests/TestCases/contiguous_container.cc
deleted file mode 100644
index aa97592c7bb9..000000000000
--- a/lib/asan/lit_tests/TestCases/contiguous_container.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// RUN: %clangxx_asan -O %s -o %t && %t
-//
-// Test __sanitizer_annotate_contiguous_container.
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-extern "C" {
-void __sanitizer_annotate_contiguous_container(void *beg, void *end,
- void *old_mid, void *new_mid);
-bool __asan_address_is_poisoned(void *addr);
-} // extern "C"
-
-void TestContainer(size_t capacity) {
- char *beg = new char[capacity];
- char *end = beg + capacity;
- char *mid = beg + capacity;
- char *old_mid = 0;
- unsigned seed = 0;
-
- for (int i = 0; i < 10000; i++) {
- size_t size = rand_r(&seed) % (capacity + 1);
- assert(size <= capacity);
- old_mid = mid;
- mid = beg + size;
- __sanitizer_annotate_contiguous_container(beg, end, old_mid, mid);
-
- for (size_t idx = 0; idx < size; idx++)
- assert(!__asan_address_is_poisoned(beg + idx));
- for (size_t idx = size; idx < capacity; idx++)
- assert(__asan_address_is_poisoned(beg + idx));
- }
-
- // Don't forget to unpoison the whole thing before destroing/reallocating.
- __sanitizer_annotate_contiguous_container(beg, end, mid, end);
- for (size_t idx = 0; idx < capacity; idx++)
- assert(!__asan_address_is_poisoned(beg + idx));
- delete[] beg;
-}
-
-int main(int argc, char **argv) {
- int n = argc == 1 ? 128 : atoi(argv[1]);
- for (int i = 0; i <= n; i++)
- TestContainer(i);
-}
diff --git a/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc b/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc
deleted file mode 100644
index 669cf150bdfb..000000000000
--- a/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-// RUN: %clangxx_asan -O2 %s -o %t && %t
-
-#include <assert.h>
-#include <pthread.h>
-#include <sanitizer/asan_interface.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-const size_t kLargeAlloc = 1UL << 20;
-
-void* allocate(void *arg) {
- volatile void *ptr = malloc(kLargeAlloc);
- free((void*)ptr);
- return 0;
-}
-
-void* check_stats(void *arg) {
- assert(__asan_get_current_allocated_bytes() > 0);
- return 0;
-}
-
-int main() {
- size_t used_mem = __asan_get_current_allocated_bytes();
- printf("Before: %zu\n", used_mem);
- const int kNumIterations = 1000;
- for (int iter = 0; iter < kNumIterations; iter++) {
- pthread_t thr[4];
- for (int j = 0; j < 4; j++) {
- assert(0 ==
- pthread_create(&thr[j], 0, (j < 2) ? allocate : check_stats, 0));
- }
- for (int j = 0; j < 4; j++)
- assert(0 == pthread_join(thr[j], 0));
- used_mem = __asan_get_current_allocated_bytes();
- if (used_mem > kLargeAlloc) {
- printf("After iteration %d: %zu\n", iter, used_mem);
- return 1;
- }
- }
- printf("Success after %d iterations\n", kNumIterations);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/deep_call_stack.cc b/lib/asan/lit_tests/TestCases/deep_call_stack.cc
deleted file mode 100644
index e24704b9019e..000000000000
--- a/lib/asan/lit_tests/TestCases/deep_call_stack.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Check that UAR mode can handle very deep recusrion.
-// export ASAN_OPTIONS=detect_stack_use_after_return=1
-// RUN: %clangxx_asan -O2 %s -o %t && \
-// RUN: %t 2>&1 | FileCheck %s
-// Also check that use_sigaltstack+verbosity doesn't crash.
-// RUN: ASAN_OPTIONS=verbosity=1:use_sigaltstack=1 %t | FileCheck %s
-#include <stdio.h>
-
-__attribute__((noinline))
-void RecursiveFunc(int depth, int *ptr) {
- if ((depth % 1000) == 0)
- printf("[%05d] ptr: %p\n", depth, ptr);
- if (depth == 0)
- return;
- int local;
- RecursiveFunc(depth - 1, &local);
-}
-
-int main(int argc, char **argv) {
- RecursiveFunc(40000, 0);
- return 0;
-}
-// CHECK: [40000] ptr:
-// CHECK: [20000] ptr:
-// CHECK: [00000] ptr
diff --git a/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc b/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
deleted file mode 100644
index 920411c4ac52..000000000000
--- a/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Check that we can store lots of stack frames if asked to.
-
-// RUN: %clangxx_asan -O0 %s -o %t 2>&1
-// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-
-template <int depth>
-struct DeepFree {
- static void free(char *x) {
- DeepFree<depth - 1>::free(x);
- }
-};
-
-template<>
-struct DeepFree<0> {
- static void free(char *x) {
- ::free(x);
- }
-};
-
-int main() {
- char *x = (char*)malloc(10);
- // deep_free(x);
- DeepFree<200>::free(x);
- return x[5];
- // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
- // CHECK: DeepFree<36>
- // CHECK: DeepFree<98>
- // CHECK: DeepFree<115>
-}
diff --git a/lib/asan/lit_tests/TestCases/deep_tail_call.cc b/lib/asan/lit_tests/TestCases/deep_tail_call.cc
deleted file mode 100644
index 2e7aa8e0208f..000000000000
--- a/lib/asan/lit_tests/TestCases/deep_tail_call.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// CHECK: AddressSanitizer: global-buffer-overflow
-int global[10];
-// CHECK: {{#0.*call4}}
-void __attribute__((noinline)) call4(int i) { global[i+10]++; }
-// CHECK: {{#1.*call3}}
-void __attribute__((noinline)) call3(int i) { call4(i); }
-// CHECK: {{#2.*call2}}
-void __attribute__((noinline)) call2(int i) { call3(i); }
-// CHECK: {{#3.*call1}}
-void __attribute__((noinline)) call1(int i) { call2(i); }
-// CHECK: {{#4.*main}}
-int main(int argc, char **argv) {
- call1(argc);
- return global[0];
-}
diff --git a/lib/asan/lit_tests/TestCases/deep_thread_stack.cc b/lib/asan/lit_tests/TestCases/deep_thread_stack.cc
deleted file mode 100644
index 92e0d66c82eb..000000000000
--- a/lib/asan/lit_tests/TestCases/deep_thread_stack.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <pthread.h>
-
-int *x;
-
-void *AllocThread(void *arg) {
- x = new int;
- *x = 42;
- return NULL;
-}
-
-void *FreeThread(void *arg) {
- delete x;
- return NULL;
-}
-
-void *AccessThread(void *arg) {
- *x = 43; // BOOM
- return NULL;
-}
-
-typedef void* (*callback_type)(void* arg);
-
-void *RunnerThread(void *function) {
- pthread_t thread;
- pthread_create(&thread, NULL, (callback_type)function, NULL);
- pthread_join(thread, NULL);
- return NULL;
-}
-
-void RunThread(callback_type function) {
- pthread_t runner;
- pthread_create(&runner, NULL, RunnerThread, (void*)function);
- pthread_join(runner, NULL);
-}
-
-int main(int argc, char *argv[]) {
- RunThread(AllocThread);
- RunThread(FreeThread);
- RunThread(AccessThread);
- return (x != 0);
-}
-
-// CHECK: AddressSanitizer: heap-use-after-free
-// CHECK: WRITE of size 4 at 0x{{.*}} thread T[[ACCESS_THREAD:[0-9]+]]
-// CHECK: freed by thread T[[FREE_THREAD:[0-9]+]] here:
-// CHECK: previously allocated by thread T[[ALLOC_THREAD:[0-9]+]] here:
-// CHECK: Thread T[[ACCESS_THREAD]] created by T[[ACCESS_RUNNER:[0-9]+]] here:
-// CHECK: Thread T[[ACCESS_RUNNER]] created by T0 here:
-// CHECK: Thread T[[FREE_THREAD]] created by T[[FREE_RUNNER:[0-9]+]] here:
-// CHECK: Thread T[[FREE_RUNNER]] created by T0 here:
-// CHECK: Thread T[[ALLOC_THREAD]] created by T[[ALLOC_RUNNER:[0-9]+]] here:
-// CHECK: Thread T[[ALLOC_RUNNER]] created by T0 here:
diff --git a/lib/asan/lit_tests/TestCases/default_blacklist.cc b/lib/asan/lit_tests/TestCases/default_blacklist.cc
deleted file mode 100644
index 25a1ae1752b0..000000000000
--- a/lib/asan/lit_tests/TestCases/default_blacklist.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-// Test that ASan uses the default blacklist from resource directory.
-// RUN: %clangxx_asan -### %s 2>&1 | FileCheck %s
-// CHECK: fsanitize-blacklist={{.*}}asan_blacklist.txt
diff --git a/lib/asan/lit_tests/TestCases/default_options.cc b/lib/asan/lit_tests/TestCases/default_options.cc
deleted file mode 100644
index 84b80557b852..000000000000
--- a/lib/asan/lit_tests/TestCases/default_options.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: %t 2>&1 | FileCheck %s
-
-const char *kAsanDefaultOptions="verbosity=1 foo=bar";
-
-extern "C"
-__attribute__((no_sanitize_address))
-const char *__asan_default_options() {
- // CHECK: Using the defaults from __asan_default_options: {{.*}} foo=bar
- return kAsanDefaultOptions;
-}
-
-int main() {
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/dlclose-test.cc b/lib/asan/lit_tests/TestCases/dlclose-test.cc
deleted file mode 100644
index 03ed16016116..000000000000
--- a/lib/asan/lit_tests/TestCases/dlclose-test.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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
-
-// This sublte test assumes that after a foo.so is dlclose-d
-// we can mmap the region of memory that has been occupied by the library.
-// It works on i368/x86_64 Linux, but not necessary anywhere else.
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-// RUN: %clangxx_asan -O0 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <string>
-
-using std::string;
-
-typedef int *(fun_t)();
-
-int main(int argc, char *argv[]) {
- string path = string(argv[0]) + "-so.so";
- size_t PageSize = sysconf(_SC_PAGESIZE);
- 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) & ~(PageSize - 1);
- void *res = mmap((void*)(page_beg), PageSize,
- 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");
- // CHECK: PASS
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/double-free.cc b/lib/asan/lit_tests/TestCases/double-free.cc
deleted file mode 100644
index 6bfd4fa2c7e5..000000000000
--- a/lib/asan/lit_tests/TestCases/double-free.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t 2>&1
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX
-
-// Also works if no malloc context is available.
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s
-
-#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];
- free(x);
- free(x + argc - 1); // BOOM
- // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
- // CHECK: #0 0x{{.*}} in {{.*}}free
- // CHECK: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-3]]
- // CHECK: freed by thread T0 here:
- // MALLOC-CTX: #0 0x{{.*}} in {{.*}}free
- // MALLOC-CTX: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-7]]
- // CHECK: allocated by thread T0 here:
- // MALLOC-CTX: double-free.cc:[[@LINE-12]]
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/force_inline_opt0.cc b/lib/asan/lit_tests/TestCases/force_inline_opt0.cc
deleted file mode 100644
index 775a66dfe2fe..000000000000
--- a/lib/asan/lit_tests/TestCases/force_inline_opt0.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// This test checks that we are no instrumenting a memory access twice
-// (before and after inlining)
-// RUN: %clangxx_asan -O1 %s -o %t && %t
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-__attribute__((always_inline))
-void foo(int *x) {
- *x = 0;
-}
-
-int main() {
- int x;
- foo(&x);
- return x;
-}
diff --git a/lib/asan/lit_tests/TestCases/free_hook_realloc.cc b/lib/asan/lit_tests/TestCases/free_hook_realloc.cc
deleted file mode 100644
index 7a71964b0032..000000000000
--- a/lib/asan/lit_tests/TestCases/free_hook_realloc.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that free hook doesn't conflict with Realloc.
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <unistd.h>
-
-static void *glob_ptr;
-
-extern "C" {
-void __asan_free_hook(void *ptr) {
- if (ptr == glob_ptr) {
- *(int*)ptr = 0;
- write(1, "FreeHook\n", sizeof("FreeHook\n"));
- }
-}
-}
-
-int main() {
- int *x = (int*)malloc(100);
- x[0] = 42;
- glob_ptr = x;
- int *y = (int*)realloc(x, 200);
- // Verify that free hook was called and didn't spoil the memory.
- if (y[0] != 42) {
- _exit(1);
- }
- write(1, "Passed\n", sizeof("Passed\n"));
- free(y);
- // CHECK: FreeHook
- // CHECK: Passed
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/global-demangle.cc b/lib/asan/lit_tests/TestCases/global-demangle.cc
deleted file mode 100644
index d050b70f0fca..000000000000
--- a/lib/asan/lit_tests/TestCases/global-demangle.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-namespace XXX {
-class YYY {
- public:
- static char ZZZ[];
-};
-char YYY::ZZZ[] = "abc";
-}
-
-int main(int argc, char **argv) {
- return (int)XXX::YYY::ZZZ[argc + 5]; // BOOM
- // CHECK: {{READ of size 1 at 0x.*}}
- // CHECK: {{0x.* is located 2 bytes to the right of global variable}}
- // CHECK: 'XXX::YYY::ZZZ' {{.*}} of size 4
- // CHECK: 'XXX::YYY::ZZZ' is ascii string 'abc'
-}
diff --git a/lib/asan/lit_tests/TestCases/global-overflow.cc b/lib/asan/lit_tests/TestCases/global-overflow.cc
deleted file mode 100644
index 0f080f55f2f1..000000000000
--- a/lib/asan/lit_tests/TestCases/global-overflow.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#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
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*global-overflow.cc:}}[[@LINE-2]]
- // CHECK: {{0x.* is located 0 bytes to the right of global variable}}
- // CHECK: {{.*YYY.* of size 10}}
- res += XXX[argc] + ZZZ[argc];
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/heap-overflow.cc b/lib/asan/lit_tests/TestCases/heap-overflow.cc
deleted file mode 100644
index 2c943a36014f..000000000000
--- a/lib/asan/lit_tests/TestCases/heap-overflow.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-#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
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*heap-overflow.cc:}}[[@LINE-2]]
- // CHECK: {{0x.* is located 0 bytes to the right of 10-byte region}}
- // CHECK: {{allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*heap-overflow.cc:9}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in main .*heap-overflow.cc:9}}
- free(x);
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc b/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc
deleted file mode 100644
index 58a44c5fb68e..000000000000
--- a/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O %s -o %t && not %t 2>&1 | FileCheck %s
-// Check that we can find huge buffer overflows to the left.
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- char *x = (char*)malloc(1 << 20);
- memset(x, 0, 10);
- int res = x[-argc * 4000]; // BOOOM
- // CHECK: is located 4000 bytes to the left of
- free(x);
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/init-order-atexit.cc b/lib/asan/lit_tests/TestCases/init-order-atexit.cc
deleted file mode 100644
index e38cdd273d58..000000000000
--- a/lib/asan/lit_tests/TestCases/init-order-atexit.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Test for the following situation:
-// (1) global A is constructed.
-// (2) exit() is called during construction of global B.
-// (3) destructor of A reads uninitialized global C from another module.
-// We do *not* want to report init-order bug in this case.
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-void AccessC();
-
-class A {
- public:
- A() { }
- ~A() { AccessC(); printf("PASSED\n"); }
- // CHECK-NOT: AddressSanitizer
- // CHECK: PASSED
-};
-
-A a;
-
-class B {
- public:
- B() { exit(1); }
- ~B() { }
-};
-
-B b;
diff --git a/lib/asan/lit_tests/TestCases/init-order-dlopen.cc b/lib/asan/lit_tests/TestCases/init-order-dlopen.cc
deleted file mode 100644
index d30d11999246..000000000000
--- a/lib/asan/lit_tests/TestCases/init-order-dlopen.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=178
-
-// Assume we're on Darwin and try to pass -U to the linker. If this flag is
-// unsupported, don't use it.
-// RUN: %clangxx_asan -O0 %p/SharedLibs/init-order-dlopen-so.cc \
-// RUN: -fPIC -shared -o %t-so.so -Wl,-U,_inc_global || \
-// RUN: %clangxx_asan -O0 %p/SharedLibs/init-order-dlopen-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// If the linker doesn't support --export-dynamic (which is ELF-specific),
-// try to link without that option.
-// FIXME: find a better solution.
-// RUN: %clangxx_asan -O0 %s -o %t -Wl,--export-dynamic || \
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true %t 2>&1 | FileCheck %s
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <string>
-
-using std::string;
-
-int foo() {
- return 42;
-}
-int global = foo();
-
-__attribute__((visibility("default")))
-extern "C"
-void inc_global() {
- global++;
-}
-
-void *global_poller(void *arg) {
- while (true) {
- if (global != 42)
- break;
- usleep(100);
- }
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- pthread_t p;
- pthread_create(&p, 0, global_poller, 0);
- string path = string(argv[0]) + "-so.so";
- if (0 == dlopen(path.c_str(), RTLD_NOW)) {
- fprintf(stderr, "dlerror: %s\n", dlerror());
- return 1;
- }
- pthread_join(p, 0);
- printf("PASSED\n");
- // CHECK: PASSED
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc b/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc
deleted file mode 100644
index 52031216d5bb..000000000000
--- a/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that init-order checking is properly disabled if pthread_create is
-// called.
-
-// RUN: %clangxx_asan %s %p/Helpers/init-order-pthread-create-extra.cc -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true %t
-
-#include <stdio.h>
-#include <pthread.h>
-
-void *run(void *arg) {
- return arg;
-}
-
-void *foo(void *input) {
- pthread_t t;
- pthread_create(&t, 0, run, input);
- void *res;
- pthread_join(t, &res);
- return res;
-}
-
-void *bar(void *input) {
- return input;
-}
-
-void *glob = foo((void*)0x1234);
-extern void *glob2;
-
-int main() {
- printf("%p %p\n", glob, glob2);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/initialization-blacklist.cc b/lib/asan/lit_tests/TestCases/initialization-blacklist.cc
deleted file mode 100644
index f40fcc082f9a..000000000000
--- a/lib/asan/lit_tests/TestCases/initialization-blacklist.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Test for blacklist functionality of initialization-order checker.
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
-// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN: -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
-// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN: -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
-// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN: -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-
-// Function is defined in another TU.
-int readBadGlobal();
-int x = readBadGlobal(); // init-order bug.
-
-// Function is defined in another TU.
-int accessBadObject();
-int y = accessBadObject(); // init-order bug.
-
-int readBadSrcGlobal();
-int z = readBadSrcGlobal(); // init-order bug.
-
-int main(int argc, char **argv) {
- return argc + x + y + z - 1;
-}
diff --git a/lib/asan/lit_tests/TestCases/initialization-bug.cc b/lib/asan/lit_tests/TestCases/initialization-bug.cc
deleted file mode 100644
index fb289b1c7ebe..000000000000
--- a/lib/asan/lit_tests/TestCases/initialization-bug.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Test to make sure basic initialization order errors are caught.
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true not %t 2>&1 | FileCheck %s
-
-// Do not test with optimization -- the error may be optimized away.
-
-// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=186
-// XFAIL: darwin
-
-#include <cstdio>
-
-// The structure of the test is:
-// "x", "y", "z" are dynamically initialized globals.
-// Value of "x" depends on "y", value of "y" depends on "z".
-// "x" and "z" are defined in this TU, "y" is defined in another one.
-// Thus we shoud stably report initialization order fiasco independently of
-// the translation unit order.
-
-int initZ() {
- return 5;
-}
-int z = initZ();
-
-// 'y' is a dynamically initialized global residing in a different TU. This
-// dynamic initializer will read the value of 'y' before main starts. The
-// result is undefined behavior, which should be caught by initialization order
-// checking.
-extern int y;
-int __attribute__((noinline)) initX() {
- return y + 1;
- // CHECK: {{AddressSanitizer: initialization-order-fiasco}}
- // CHECK: {{READ of size .* at 0x.* thread T0}}
- // CHECK: {{0x.* is located 0 bytes inside of global variable .*(y|z).*}}
-}
-
-// This initializer begins our initialization order problems.
-static int x = initX();
-
-int main() {
- // ASan should have caused an exit before main runs.
- printf("PASS\n");
- // CHECK-NOT: PASS
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/initialization-constexpr.cc b/lib/asan/lit_tests/TestCases/initialization-constexpr.cc
deleted file mode 100644
index 65c95edd5081..000000000000
--- a/lib/asan/lit_tests/TestCases/initialization-constexpr.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Constexpr:
-// We need to check that a global variable initialized with a constexpr
-// constructor can be accessed during dynamic initialization (as a constexpr
-// constructor implies that it was initialized during constant initialization,
-// not dynamic initialization).
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-constexpr-extra.cc\
-// RUN: --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-constexpr-extra.cc\
-// RUN: --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-constexpr-extra.cc\
-// RUN: --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-constexpr-extra.cc\
-// RUN: --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-
-class Integer {
- private:
- int value;
-
- public:
- constexpr Integer(int x = 0) : value(x) {}
- int getValue() {return value;}
-};
-Integer coolestInteger(42);
-int getCoolestInteger() { return coolestInteger.getValue(); }
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/initialization-nobug.cc b/lib/asan/lit_tests/TestCases/initialization-nobug.cc
deleted file mode 100644
index ed37d137f8cb..000000000000
--- a/lib/asan/lit_tests/TestCases/initialization-nobug.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// A collection of various initializers which shouldn't trip up initialization
-// order checking. If successful, this will just return 0.
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-
-// Simple access:
-// Make sure that accessing a global in the same TU is safe
-
-bool condition = true;
-int initializeSameTU() {
- return condition ? 0x2a : 052;
-}
-int sameTU = initializeSameTU();
-
-// Linker initialized:
-// Check that access to linker initialized globals originating from a different
-// TU's initializer is safe.
-
-int A = (1 << 1) + (1 << 3) + (1 << 5), B;
-int getAB() {
- return A * B;
-}
-
-// Function local statics:
-// Check that access to function local statics originating from a different
-// TU's initializer is safe.
-
-int countCalls() {
- static int calls;
- return ++calls;
-}
-
-// Trivial constructor, non-trivial destructor.
-struct StructWithDtor {
- ~StructWithDtor() { }
- int value;
-};
-StructWithDtor struct_with_dtor;
-int getStructWithDtorValue() { return struct_with_dtor.value; }
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/inline.cc b/lib/asan/lit_tests/TestCases/inline.cc
deleted file mode 100644
index 792aff59f4ba..000000000000
--- a/lib/asan/lit_tests/TestCases/inline.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -O3 %s -o %t && %t
-
-// Test that no_sanitize_address attribute applies even when the function would
-// be normally inlined.
-
-#include <stdlib.h>
-
-__attribute__((no_sanitize_address))
-int f(int *p) {
- return *p; // BOOOM?? Nope!
-}
-
-int main(int argc, char **argv) {
- int * volatile x = (int*)malloc(2*sizeof(int) + 2);
- int res = f(x + 2);
- if (res)
- exit(0);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/interface_test.cc b/lib/asan/lit_tests/TestCases/interface_test.cc
deleted file mode 100644
index 297b5526e9d9..000000000000
--- a/lib/asan/lit_tests/TestCases/interface_test.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Check that user may include ASan interface header.
-// RUN: %clang_asan %s -o %t && %t
-// RUN: %clang %s -o %t && %t
-#include <sanitizer/asan_interface.h>
-
-int main() {
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/invalid-free.cc b/lib/asan/lit_tests/TestCases/invalid-free.cc
deleted file mode 100644
index f940b501279a..000000000000
--- a/lib/asan/lit_tests/TestCases/invalid-free.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX
-
-// Also works if no malloc context is available.
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s
-
-#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];
- free(x + 5); // BOOM
- // CHECK: AddressSanitizer: attempting free on address{{.*}}in thread T0
- // CHECK: invalid-free.cc:[[@LINE-2]]
- // CHECK: is located 5 bytes inside of 10-byte region
- // CHECK: allocated by thread T0 here:
- // MALLOC-CTX: invalid-free.cc:[[@LINE-8]]
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/ioctl.cc b/lib/asan/lit_tests/TestCases/ioctl.cc
deleted file mode 100644
index 08ca688d3872..000000000000
--- a/lib/asan/lit_tests/TestCases/ioctl.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O0 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -O0 -g %s -o %t && %t
-// RUN: %clangxx_asan -O3 -g %s -o %t && %t
-
-#include <assert.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-int main(int argc, char **argv) {
- int fd = socket(AF_INET, SOCK_DGRAM, 0);
-
- int nonblock;
- int res = ioctl(fd, FIONBIO, &nonblock + 1);
- // CHECK: AddressSanitizer: stack-buffer-overflow
- // CHECK: READ of size 4 at
- // CHECK: {{#.* in main .*ioctl.cc:}}[[@LINE-3]]
- assert(res == 0);
- close(fd);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/large_func_test.cc b/lib/asan/lit_tests/TestCases/large_func_test.cc
deleted file mode 100644
index 0534bcd31142..000000000000
--- a/lib/asan/lit_tests/TestCases/large_func_test.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-#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]++;
-
- // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
- // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
- // CHECK: {{READ of size 4 at 0x.* thread T0}}
- x[zero + 103]++; // we should report this exact line
- // atos incorrectly extracts the symbol name for the static functions on
- // Darwin.
- // CHECK-Linux: {{#0 0x.* in LargeFunction.*large_func_test.cc:}}[[@LINE-3]]
- // CHECK-Darwin: {{#0 0x.* in .*LargeFunction.*large_func_test.cc}}:[[@LINE-4]]
-
- 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);
- // CHECK: {{ #1 0x.* in main .*large_func_test.cc:}}[[@LINE-1]]
- // CHECK: {{0x.* is located 12 bytes to the right of 400-byte region}}
- // CHECK: {{allocated by thread T0 here:}}
- // CHECK-Linux: {{ #0 0x.* in operator new.*}}
- // CHECK-Darwin: {{ #0 0x.* in .*_Zna.*}}
- // CHECK: {{ #1 0x.* in main .*large_func_test.cc:}}[[@LINE-7]]
- delete x;
-}
diff --git a/lib/asan/lit_tests/TestCases/log-path_test.cc b/lib/asan/lit_tests/TestCases/log-path_test.cc
deleted file mode 100644
index 1072670fbff4..000000000000
--- a/lib/asan/lit_tests/TestCases/log-path_test.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// RUN: %clangxx_asan %s -o %t
-
-// Regular run.
-// RUN: not %t 2> %t.out
-// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.out
-
-// Good log_path.
-// RUN: rm -f %t.log.*
-// RUN: ASAN_OPTIONS=log_path=%t.log not %t 2> %t.out
-// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.*
-
-// Invalid log_path.
-// RUN: ASAN_OPTIONS=log_path=/INVALID not %t 2> %t.out
-// RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t.out
-
-// Too long log_path.
-// RUN: ASAN_OPTIONS=log_path=`for((i=0;i<10000;i++)); do echo -n $i; done` \
-// RUN: not %t 2> %t.out
-// RUN: FileCheck %s --check-prefix=CHECK-LONG < %t.out
-
-// Run w/o errors should not produce any log.
-// RUN: rm -f %t.log.*
-// RUN: ASAN_OPTIONS=log_path=%t.log %t ARG ARG ARG
-// RUN: not cat %t.log.*
-
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- if (argc > 2) return 0;
- char *x = (char*)malloc(10);
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- free(x);
- return res;
-}
-// CHECK-ERROR: ERROR: AddressSanitizer
-// CHECK-INVALID: ERROR: Can't open file: /INVALID
-// CHECK-LONG: ERROR: Path is too long: 01234
diff --git a/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled b/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled
deleted file mode 100644
index c6c1b49e994d..000000000000
--- a/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_asan %s -o %t
-// RUN: rm -f %t.log.*
-// Set verbosity to 1 so that the log files are opened prior to fork().
-// RUN: ASAN_OPTIONS="log_path=%t.log verbosity=1" not %t 2> %t.out
-// RUN: for f in %t.log.* ; do FileCheck %s < $f; done
-// RUN: [ `ls %t.log.* | wc -l` == 2 ]
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-int main(int argc, char **argv) {
- void *x = malloc(10);
- free(x);
- if (fork() == -1) return 1;
- // There are two processes at this point, thus there should be two distinct
- // error logs.
- free(x);
- return 0;
-}
-
-// CHECK: ERROR: AddressSanitizer
diff --git a/lib/asan/lit_tests/TestCases/lsan_annotations.cc b/lib/asan/lit_tests/TestCases/lsan_annotations.cc
deleted file mode 100644
index c55ab8692eb5..000000000000
--- a/lib/asan/lit_tests/TestCases/lsan_annotations.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Check that LSan annotations work fine.
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-// RUN: %clangxx_asan -O3 %s -o %t && %t
-
-#include <sanitizer/lsan_interface.h>
-#include <stdlib.h>
-
-int main() {
- int *x = new int;
- __lsan_ignore_object(x);
- {
- __lsan::ScopedDisabler disabler;
- double *y = new double;
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/malloc_context_size.cc b/lib/asan/lit_tests/TestCases/malloc_context_size.cc
deleted file mode 100644
index 266ce66f59e2..000000000000
--- a/lib/asan/lit_tests/TestCases/malloc_context_size.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-
-int main() {
- char *x = new char[20];
- delete[] x;
- return x[0];
- // We need to keep duplicate lines with different 'CHECK-%os' prefixes,
- // otherwise FileCheck barks on missing 'CHECK-%os' before 'CHECK-%os-NEXT'.
-
- // CHECK-Linux: freed by thread T{{.*}} here:
- // CHECK-Linux-NEXT: #0 0x{{.*}} in operator delete[]
- // CHECK-Darwin: freed by thread T{{.*}} here:
- // CHECK-Darwin-NEXT: #0 0x{{.*}} in wrap__ZdaPv
- // CHECK-NOT: #1 0x{{.*}}
-
- // CHECK-Linux: previously allocated by thread T{{.*}} here:
- // CHECK-Linux-NEXT: #0 0x{{.*}} in operator new[]
- // CHECK-Darwin: previously allocated by thread T{{.*}} here:
- // CHECK-Darwin-NEXT: #0 0x{{.*}} in wrap__Znam
- // CHECK-NOT: #1 0x{{.*}}
-
- // CHECK: SUMMARY: AddressSanitizer: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/TestCases/malloc_fill.cc b/lib/asan/lit_tests/TestCases/malloc_fill.cc
deleted file mode 100644
index 57f50d1438b7..000000000000
--- a/lib/asan/lit_tests/TestCases/malloc_fill.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Check that we fill malloc-ed memory correctly.
-// RUN: %clangxx_asan %s -o %t
-// RUN: %t | FileCheck %s
-// RUN: ASAN_OPTIONS=max_malloc_fill_size=10:malloc_fill_byte=8 %t | FileCheck %s --check-prefix=CHECK-10-8
-// RUN: ASAN_OPTIONS=max_malloc_fill_size=20:malloc_fill_byte=171 %t | FileCheck %s --check-prefix=CHECK-20-ab
-
-#include <stdio.h>
-int main(int argc, char **argv) {
- // With asan allocator this makes sure we get memory from mmap.
- static const int kSize = 1 << 25;
- unsigned char *x = new unsigned char[kSize];
- printf("-");
- for (int i = 0; i <= 32; i++) {
- printf("%02x", x[i]);
- }
- printf("-\n");
- delete [] x;
-}
-
-// CHECK: -bebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebe-
-// CHECK-10-8: -080808080808080808080000000000000000000000000000000000000000000000-
-// CHECK-20-ab: -abababababababababababababababababababab00000000000000000000000000-
diff --git a/lib/asan/lit_tests/TestCases/malloc_hook.cc b/lib/asan/lit_tests/TestCases/malloc_hook.cc
deleted file mode 100644
index 83be1020ea43..000000000000
--- a/lib/asan/lit_tests/TestCases/malloc_hook.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <unistd.h>
-
-extern "C" {
-bool __asan_get_ownership(const void *p);
-
-void *global_ptr;
-
-// Note: avoid calling functions that allocate memory in malloc/free
-// to avoid infinite recursion.
-void __asan_malloc_hook(void *ptr, size_t sz) {
- if (__asan_get_ownership(ptr)) {
- write(1, "MallocHook\n", sizeof("MallocHook\n"));
- global_ptr = ptr;
- }
-}
-void __asan_free_hook(void *ptr) {
- if (__asan_get_ownership(ptr) && ptr == global_ptr)
- write(1, "FreeHook\n", sizeof("FreeHook\n"));
-}
-} // extern "C"
-
-int main() {
- volatile int *x = new int;
- // CHECK: MallocHook
- // Check that malloc hook was called with correct argument.
- if (global_ptr != (void*)x) {
- _exit(1);
- }
- *x = 0;
- delete x;
- // CHECK: FreeHook
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc b/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc
deleted file mode 100644
index e06a8c7e9e2f..000000000000
--- a/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=0 %t
-// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=1 not %t 2>&1 | FileCheck %s
-// Default to strict_memcmp=1.
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <string.h>
-int main() {
- char kFoo[] = "foo";
- char kFubar[] = "fubar";
- int res = memcmp(kFoo, kFubar, strlen(kFubar));
- printf("res: %d\n", res);
- // CHECK: AddressSanitizer: stack-buffer-overflow
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/memcmp_test.cc b/lib/asan/lit_tests/TestCases/memcmp_test.cc
deleted file mode 100644
index 758311ddc476..000000000000
--- a/lib/asan/lit_tests/TestCases/memcmp_test.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// REQUIRES: compiler-rt-optimized
-
-#include <string.h>
-int main(int argc, char **argv) {
- char a1[] = {argc, 2, 3, 4};
- char a2[] = {1, 2*argc, 3, 4};
- int res = memcmp(a1, a2, 4 + argc); // BOOM
- // CHECK: AddressSanitizer: stack-buffer-overflow
- // CHECK: {{#0.*memcmp}}
- // CHECK: {{#1.*main}}
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/null_deref.cc b/lib/asan/lit_tests/TestCases/null_deref.cc
deleted file mode 100644
index 476418324cc5..000000000000
--- a/lib/asan/lit_tests/TestCases/null_deref.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-__attribute__((noinline))
-static void NullDeref(int *ptr) {
- // CHECK: ERROR: AddressSanitizer: SEGV on unknown address
- // CHECK: {{0x0*00028 .*pc 0x.*}}
- ptr[10]++; // BOOM
- // atos on Mac cannot extract the symbol name correctly.
- // CHECK-Linux: {{ #0 0x.* in NullDeref.*null_deref.cc:}}[[@LINE-2]]
- // CHECK-Darwin: {{ #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]]
-}
-int main() {
- NullDeref((int*)0);
- // CHECK: {{ #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]]
- // CHECK: {{AddressSanitizer can not provide additional info.}}
-}
diff --git a/lib/asan/lit_tests/TestCases/on_error_callback.cc b/lib/asan/lit_tests/TestCases/on_error_callback.cc
deleted file mode 100644
index d0cec2eb2703..000000000000
--- a/lib/asan/lit_tests/TestCases/on_error_callback.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-extern "C"
-void __asan_on_error() {
- fprintf(stderr, "__asan_on_error called");
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: __asan_on_error called
-}
diff --git a/lib/asan/lit_tests/TestCases/partial_right.cc b/lib/asan/lit_tests/TestCases/partial_right.cc
deleted file mode 100644
index a000a913d6be..000000000000
--- a/lib/asan/lit_tests/TestCases/partial_right.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main(int argc, char **argv) {
- volatile int *x = (int*)malloc(2*sizeof(int) + 2);
- int res = x[2]; // BOOOM
- // CHECK: {{READ of size 4 at 0x.* thread T0}}
- // CHECK: [[ADDR:0x[01-9a-fa-f]+]] is located 0 bytes to the right of {{.*}}-byte region [{{.*}},{{.*}}[[ADDR]])
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/poison_partial.cc b/lib/asan/lit_tests/TestCases/poison_partial.cc
deleted file mode 100644
index f7c48bf597b6..000000000000
--- a/lib/asan/lit_tests/TestCases/poison_partial.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: not %t heap 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=poison_partial=0 %t
-// RUN: ASAN_OPTIONS=poison_partial=0 %t heap
-#include <string.h>
-char g[21];
-char *x;
-
-int main(int argc, char **argv) {
- if (argc >= 2)
- x = new char[21];
- else
- x = &g[0];
- memset(x, 0, 21);
- int *y = (int*)x;
- return y[5];
-}
-// CHECK: 0 bytes to the right
diff --git a/lib/asan/lit_tests/TestCases/print_summary.cc b/lib/asan/lit_tests/TestCases/print_summary.cc
deleted file mode 100644
index 949c9b54f8a3..000000000000
--- a/lib/asan/lit_tests/TestCases/print_summary.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=YES
-// RUN: ASAN_OPTIONS=print_summary=false not %t 2>&1 | FileCheck %s --check-prefix=NO
-
-int main() {
- char *x = new char[20];
- delete[] x;
- return x[0];
- // YES: ERROR: AddressSanitizer: heap-use-after-free
- // YES: SUMMARY: AddressSanitizer: heap-use-after-free
- // NO: ERROR: AddressSanitizer: heap-use-after-free
- // NO-NOT: SUMMARY: AddressSanitizer: heap-use-after-free
-}
-
diff --git a/lib/asan/lit_tests/TestCases/readv.cc b/lib/asan/lit_tests/TestCases/readv.cc
deleted file mode 100644
index ba17505f37ac..000000000000
--- a/lib/asan/lit_tests/TestCases/readv.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-// RUN: %clangxx_asan -O0 %s -DPOSITIVE -o %t && not %t 2>&1 | FileCheck %s
-
-// Test the readv() interceptor.
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/uio.h>
-#include <time.h>
-
-int main() {
- char buf[2011];
- struct iovec iov[2];
-#ifdef POSITIVE
- char * volatile buf_ = buf;
- iov[0].iov_base = buf_ - 1;
-#else
- iov[0].iov_base = buf + 1;
-#endif
- iov[0].iov_len = 5;
- iov[1].iov_base = buf + 10;
- iov[1].iov_len = 2000;
- int fd = open("/etc/hosts", O_RDONLY);
- assert(fd > 0);
- readv(fd, iov, 2);
- // CHECK: WRITE of size 5 at
- close(fd);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c b/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
deleted file mode 100644
index df150675bd97..000000000000
--- a/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// Sanity checking a test in pure C.
-// RUN: %clang_asan -O2 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-// Sanity checking a test in pure C with -pie.
-// RUN: %clang_asan -O2 %s -pie -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: heap-use-after-free
- // CHECK: free
- // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-4]]
- // CHECK: malloc
- // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-7]]
-}
diff --git a/lib/asan/lit_tests/TestCases/shared-lib-test.cc b/lib/asan/lit_tests/TestCases/shared-lib-test.cc
deleted file mode 100644
index 126903a55866..000000000000
--- a/lib/asan/lit_tests/TestCases/shared-lib-test.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clangxx_asan -O0 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#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); // BOOM
- // CHECK: {{.*ERROR: AddressSanitizer: global-buffer-overflow}}
- // CHECK: {{READ of size 4 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.*}}
- // CHECK: {{ #1 0x.* in main .*shared-lib-test.cc:}}[[@LINE-4]]
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/sleep_before_dying.c b/lib/asan/lit_tests/TestCases/sleep_before_dying.c
deleted file mode 100644
index 8dee9f2778ce..000000000000
--- a/lib/asan/lit_tests/TestCases/sleep_before_dying.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS="sleep_before_dying=1" not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: Sleeping for 1 second
-}
diff --git a/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc b/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc
deleted file mode 100644
index 91820db0142a..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %t -2 2>&1 | FileCheck --check-prefix=CHECK-m2 %s
-// RUN: not %t -1 2>&1 | FileCheck --check-prefix=CHECK-m1 %s
-// RUN: %t 0
-// RUN: %t 8
-// RUN: not %t 9 2>&1 | FileCheck --check-prefix=CHECK-9 %s
-// RUN: not %t 10 2>&1 | FileCheck --check-prefix=CHECK-10 %s
-// RUN: not %t 62 2>&1 | FileCheck --check-prefix=CHECK-62 %s
-// RUN: not %t 63 2>&1 | FileCheck --check-prefix=CHECK-63 %s
-// RUN: not %t 63 2>&1 | FileCheck --check-prefix=CHECK-63 %s
-// RUN: not %t 73 2>&1 | FileCheck --check-prefix=CHECK-73 %s
-// RUN: not %t 74 2>&1 | FileCheck --check-prefix=CHECK-74 %s
-// RUN: not %t 126 2>&1 | FileCheck --check-prefix=CHECK-126 %s
-// RUN: not %t 127 2>&1 | FileCheck --check-prefix=CHECK-127 %s
-// RUN: not %t 137 2>&1 | FileCheck --check-prefix=CHECK-137 %s
-// RUN: not %t 138 2>&1 | FileCheck --check-prefix=CHECK-138 %s
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-int main(int argc, char **argv) {
- assert(argc >= 2);
- int idx = atoi(argv[1]);
- char AAA[10], BBB[10], CCC[10];
- memset(AAA, 0, sizeof(AAA));
- memset(BBB, 0, sizeof(BBB));
- memset(CCC, 0, sizeof(CCC));
- int res = 0;
- char *p = AAA + idx;
- printf("AAA: %p\ny: %p\nz: %p\np: %p\n", AAA, BBB, CCC, p);
- // make sure BBB and CCC are not removed;
- return *(short*)(p) + BBB[argc % 2] + CCC[argc % 2];
-}
-// CHECK-m2: 'AAA' <== Memory access at offset 30 underflows this variable
-// CHECK-m1: 'AAA' <== Memory access at offset 31 partially underflows this variable
-// CHECK-9: 'AAA' <== Memory access at offset 41 partially overflows this variable
-// CHECK-10: 'AAA' <== Memory access at offset 42 overflows this variable
-// CHECK-62: 'BBB' <== Memory access at offset 94 underflows this variable
-// CHECK-63: 'BBB' <== Memory access at offset 95 partially underflows this variable
-// CHECK-73: 'BBB' <== Memory access at offset 105 partially overflows this variable
-// CHECK-74: 'BBB' <== Memory access at offset 106 overflows this variable
-// CHECK-126: 'CCC' <== Memory access at offset 158 underflows this variable
-// CHECK-127: 'CCC' <== Memory access at offset 159 partially underflows this variable
-// CHECK-137: 'CCC' <== Memory access at offset 169 partially overflows this variable
-// CHECK-138: 'CCC' <== Memory access at offset 170 overflows this variable
diff --git a/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc b/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc
deleted file mode 100644
index 2b83ecc2923b..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <string.h>
-
-namespace XXX {
-struct YYY {
- static int ZZZ(int x) {
- char array[10];
- memset(array, 0, 10);
- return array[x]; // BOOOM
- // CHECK: ERROR: AddressSanitizer: stack-buffer-overflow
- // CHECK: READ of size 1 at
- // CHECK: is located in stack of thread T0 at offset
- // CHECK: XXX::YYY::ZZZ
- }
-};
-} // namespace XXX
-
-int main(int argc, char **argv) {
- int res = XXX::YYY::ZZZ(argc + 10);
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/stack-oob-frames.cc b/lib/asan/lit_tests/TestCases/stack-oob-frames.cc
deleted file mode 100644
index 909e700b3d00..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-oob-frames.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// RUN: %clangxx_asan -O1 %s -o %t
-// RUN: not %t 0 2>&1 | FileCheck %s --check-prefix=CHECK0
-// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK1
-// RUN: not %t 2 2>&1 | FileCheck %s --check-prefix=CHECK2
-// RUN: not %t 3 2>&1 | FileCheck %s --check-prefix=CHECK3
-
-#define NOINLINE __attribute__((noinline))
-inline void break_optimization(void *arg) {
- __asm__ __volatile__("" : : "r" (arg) : "memory");
-}
-
-NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
- char s[4] = {0};
- char *d = s;
- break_optimization(&d);
- switch (frame) {
- case 3: a[5]++; break;
- case 2: b[5]++; break;
- case 1: c[5]++; break;
- case 0: d[5]++; break;
- }
-}
-NOINLINE static void Frame1(int frame, char *a, char *b) {
- char c[4] = {0}; Frame0(frame, a, b, c);
- break_optimization(0);
-}
-NOINLINE static void Frame2(int frame, char *a) {
- char b[4] = {0}; Frame1(frame, a, b);
- break_optimization(0);
-}
-NOINLINE static void Frame3(int frame) {
- char a[4] = {0}; Frame2(frame, a);
- break_optimization(0);
-}
-
-int main(int argc, char **argv) {
- if (argc != 2) return 1;
- Frame3(argv[1][0] - '0');
-}
-
-// CHECK0: AddressSanitizer: stack-buffer-overflow
-// CHECK0: #0{{.*}}Frame0
-// CHECK0: #1{{.*}}Frame1
-// CHECK0: #2{{.*}}Frame2
-// CHECK0: #3{{.*}}Frame3
-// CHECK0: is located in stack of thread T0 at offset
-// CHECK0-NEXT: #0{{.*}}Frame0
-//
-// CHECK1: AddressSanitizer: stack-buffer-overflow
-// CHECK1: is located in stack of thread T0 at offset
-// CHECK1-NEXT: #0{{.*}}Frame1
-//
-// CHECK2: AddressSanitizer: stack-buffer-overflow
-// CHECK2: is located in stack of thread T0 at offset
-// CHECK2-NEXT: #0{{.*}}Frame2
-//
-// CHECK3: AddressSanitizer: stack-buffer-overflow
-// CHECK3: is located in stack of thread T0 at offset
-// CHECK3-NEXT: #0{{.*}}Frame3
diff --git a/lib/asan/lit_tests/TestCases/stack-overflow.cc b/lib/asan/lit_tests/TestCases/stack-overflow.cc
deleted file mode 100644
index adf1c0784f70..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-overflow.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <string.h>
-int main(int argc, char **argv) {
- char x[10];
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*stack-overflow.cc:}}[[@LINE-2]]
- // CHECK: {{Address 0x.* is located in stack of thread T0 at offset}}
- // CHECK-NEXT: in{{.*}}main{{.*}}stack-overflow.cc
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/stack-use-after-return.cc b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc
deleted file mode 100644
index 5ed42a8c0c97..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-use-after-return.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
-// RUN: %clangxx_asan -O0 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=detect_stack_use_after_return=0 %t
-// Regression test for a CHECK failure with small stack size and large frame.
-// RUN: %clangxx_asan -O3 %s -o %t -DkSize=10000 && \
-// RUN: (ulimit -s 65; not %t) 2>&1 | FileCheck %s
-//
-// Test that we can find UAR in a thread other than main:
-// RUN: %clangxx_asan -DUseThread -O2 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck --check-prefix=THREAD %s
-//
-// Test the uar_stack_size_log flag.
-//
-// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:uar_stack_size_log=20:verbosity=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s
-// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:uar_stack_size_log=24:verbosity=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s
-
-#include <stdio.h>
-#include <pthread.h>
-
-#ifndef kSize
-# define kSize 1
-#endif
-
-#ifndef UseThread
-# define UseThread 0
-#endif
-
-__attribute__((noinline))
-char *Ident(char *x) {
- fprintf(stderr, "1: %p\n", x);
- return x;
-}
-
-__attribute__((noinline))
-char *Func1() {
- char local[kSize];
- return Ident(local);
-}
-
-__attribute__((noinline))
-void Func2(char *x) {
- fprintf(stderr, "2: %p\n", x);
- *x = 1;
- // CHECK: WRITE of size 1 {{.*}} thread T0
- // CHECK: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]]
- // CHECK: is located in stack of thread T0 at offset
- // CHECK: 'local' <== Memory access at offset 32 is inside this variable
- // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}}
- // THREAD: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-6]]
- // THREAD: is located in stack of thread T{{[1-9]}} at offset
- // THREAD: 'local' <== Memory access at offset 32 is inside this variable
- // CHECK-20: T0: FakeStack created:{{.*}} stack_size_log: 20
- // CHECK-24: T0: FakeStack created:{{.*}} stack_size_log: 24
-}
-
-void *Thread(void *unused) {
- Func2(Func1());
- return NULL;
-}
-
-int main(int argc, char **argv) {
-#if UseThread
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
-#else
- Func2(Func1());
-#endif
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/strdup_oob_test.cc b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
deleted file mode 100644
index e92afd3caaf9..000000000000
--- a/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <string.h>
-
-char kString[] = "foo";
-
-int main(int argc, char **argv) {
- char *copy = strdup(kString);
- int x = copy[4 + argc]; // BOOM
- // CHECK: AddressSanitizer: heap-buffer-overflow
- // CHECK: #0 {{.*}}main {{.*}}strdup_oob_test.cc:[[@LINE-2]]
- // CHECK: allocated by thread T{{.*}} here:
- // CHECK: #0 {{.*}}strdup
- // CHECK: strdup_oob_test.cc:[[@LINE-6]]
- return x;
-}
diff --git a/lib/asan/lit_tests/TestCases/strerror_r_test.cc b/lib/asan/lit_tests/TestCases/strerror_r_test.cc
deleted file mode 100644
index 0df009b83f9c..000000000000
--- a/lib/asan/lit_tests/TestCases/strerror_r_test.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-
-// Regression test for PR17138.
-
-#include <assert.h>
-#include <string.h>
-
-int main() {
- char buf[1024];
- char *res = (char *)strerror_r(300, buf, sizeof(buf));
- assert(res != 0);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/strip_path_prefix.c b/lib/asan/lit_tests/TestCases/strip_path_prefix.c
deleted file mode 100644
index c4d6ba49d5e3..000000000000
--- a/lib/asan/lit_tests/TestCases/strip_path_prefix.c
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS="strip_path_prefix='/'" not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // Check that paths in error report don't start with slash.
- // CHECK: heap-use-after-free
- // CHECK-NOT: #0 0x{{.*}} ({{[/].*}})
-}
diff --git a/lib/asan/lit_tests/TestCases/strncpy-overflow.cc b/lib/asan/lit_tests/TestCases/strncpy-overflow.cc
deleted file mode 100644
index f91e191fde23..000000000000
--- a/lib/asan/lit_tests/TestCases/strncpy-overflow.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-// REQUIRES: compiler-rt-optimized
-
-#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
- // CHECK: {{WRITE of size 10 at 0x.* thread T0}}
- // CHECK-Linux: {{ #0 0x.* in .*strncpy}}
- // CHECK-Darwin: {{ #0 0x.* in wrap_strncpy}}
- // CHECK: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-4]]
- // CHECK: {{0x.* is located 0 bytes to the right of 9-byte region}}
- // CHECK: {{allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-10]]
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-13]]
- return short_buffer[8];
-}
diff --git a/lib/asan/lit_tests/TestCases/symbolize_callback.cc b/lib/asan/lit_tests/TestCases/symbolize_callback.cc
deleted file mode 100644
index 058b3150fbba..000000000000
--- a/lib/asan/lit_tests/TestCases/symbolize_callback.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-extern "C"
-bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
- snprintf(out_buffer, out_size, "MySymbolizer");
- return true;
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: MySymbolizer
-}
diff --git a/lib/asan/lit_tests/TestCases/throw_call_test.cc b/lib/asan/lit_tests/TestCases/throw_call_test.cc
deleted file mode 100644
index 974bc51d97c5..000000000000
--- a/lib/asan/lit_tests/TestCases/throw_call_test.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_asan %s -o %t && %t
-// http://code.google.com/p/address-sanitizer/issues/detail?id=147 (not fixed).
-// BROKEN: %clangxx_asan %s -o %t -static-libstdc++ && %t
-#include <stdio.h>
-static volatile int zero = 0;
-inline void pretend_to_do_something(void *x) {
- __asm__ __volatile__("" : : "r" (x) : "memory");
-}
-
-__attribute__((noinline, no_sanitize_address))
-void ReallyThrow() {
- fprintf(stderr, "ReallyThrow\n");
- if (zero == 0)
- throw 42;
-}
-
-__attribute__((noinline))
-void Throw() {
- int a, b, c, d, e;
- pretend_to_do_something(&a);
- pretend_to_do_something(&b);
- pretend_to_do_something(&c);
- pretend_to_do_something(&d);
- pretend_to_do_something(&e);
- fprintf(stderr, "Throw stack = %p\n", &a);
- ReallyThrow();
-}
-
-__attribute__((noinline))
-void CheckStack() {
- int ar[100];
- pretend_to_do_something(ar);
- for (int i = 0; i < 100; i++)
- ar[i] = i;
- fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100);
-}
-
-int main(int argc, char** argv) {
- try {
- Throw();
- } catch(int a) {
- fprintf(stderr, "a = %d\n", a);
- }
- CheckStack();
-}
diff --git a/lib/asan/lit_tests/TestCases/throw_invoke_test.cc b/lib/asan/lit_tests/TestCases/throw_invoke_test.cc
deleted file mode 100644
index 077a940e8d19..000000000000
--- a/lib/asan/lit_tests/TestCases/throw_invoke_test.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// RUN: %clangxx_asan %s -o %t && %t
-// RUN: %clangxx_asan %s -o %t -static-libstdc++ && %t
-#include <stdio.h>
-static volatile int zero = 0;
-inline void pretend_to_do_something(void *x) {
- __asm__ __volatile__("" : : "r" (x) : "memory");
-}
-
-__attribute__((noinline))
-void ReallyThrow() {
- fprintf(stderr, "ReallyThrow\n");
- try {
- if (zero == 0)
- throw 42;
- else if (zero == 1)
- throw 1.;
- } catch(double x) {
- }
-}
-
-__attribute__((noinline))
-void Throw() {
- int a, b, c, d, e;
- pretend_to_do_something(&a);
- pretend_to_do_something(&b);
- pretend_to_do_something(&c);
- pretend_to_do_something(&d);
- pretend_to_do_something(&e);
- fprintf(stderr, "Throw stack = %p\n", &a);
- ReallyThrow();
-}
-
-__attribute__((noinline))
-void CheckStack() {
- int ar[100];
- pretend_to_do_something(ar);
- for (int i = 0; i < 100; i++)
- ar[i] = i;
- fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100);
-}
-
-int main(int argc, char** argv) {
- try {
- Throw();
- } catch(int a) {
- fprintf(stderr, "a = %d\n", a);
- }
- CheckStack();
-}
-
diff --git a/lib/asan/lit_tests/TestCases/time_interceptor.cc b/lib/asan/lit_tests/TestCases/time_interceptor.cc
deleted file mode 100644
index 3be00d60c01d..000000000000
--- a/lib/asan/lit_tests/TestCases/time_interceptor.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// Test the time() interceptor.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-int main() {
- time_t *tm = (time_t*)malloc(sizeof(time_t));
- free(tm);
- time_t t = time(tm);
- printf("Time: %s\n", ctime(&t)); // NOLINT
- // CHECK: use-after-free
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc b/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
deleted file mode 100644
index c967531c2c02..000000000000
--- a/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Test that use-after-return works with exceptions.
-// export ASAN_OPTIONS=detect_stack_use_after_return=1
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-
-#include <stdio.h>
-
-volatile char *g;
-
-#ifndef FRAME_SIZE
-# define FRAME_SIZE 100
-#endif
-
-#ifndef NUM_ITER
-# define NUM_ITER 4000
-#endif
-
-#ifndef DO_THROW
-# define DO_THROW 1
-#endif
-
-void Func(int depth) {
- char frame[FRAME_SIZE];
- g = &frame[0];
- if (depth)
- Func(depth - 1);
- else if (DO_THROW)
- throw 1;
-}
-
-int main(int argc, char **argv) {
- for (int i = 0; i < NUM_ITER; i++) {
- try {
- Func(argc * 100);
- } catch(...) {
- }
- if ((i % (NUM_ITER / 10)) == 0)
- fprintf(stderr, "done [%d]\n", i);
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc b/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc
deleted file mode 100644
index d50566c44e9a..000000000000
--- a/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t A 2>&1 | FileCheck --check-prefix=CHECK-A %s
-// RUN: not %t B 2>&1 | FileCheck --check-prefix=CHECK-B %s
-// RUN: not %t C 2>&1 | FileCheck --check-prefix=CHECK-C %s
-// RUN: not %t D 2>&1 | FileCheck --check-prefix=CHECK-D %s
-// RUN: not %t E 2>&1 | FileCheck --check-prefix=CHECK-E %s
-
-// RUN: not %t K 2>&1 | FileCheck --check-prefix=CHECK-K %s
-// RUN: not %t L 2>&1 | FileCheck --check-prefix=CHECK-L %s
-// RUN: not %t M 2>&1 | FileCheck --check-prefix=CHECK-M %s
-// RUN: not %t N 2>&1 | FileCheck --check-prefix=CHECK-N %s
-// RUN: not %t O 2>&1 | FileCheck --check-prefix=CHECK-O %s
-
-#include <sanitizer/asan_interface.h>
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- if (argc != 2) return 1;
- char *x = new char[16];
- memset(x, 0xab, 16);
- int res = 1;
- switch (argv[1][0]) {
- case 'A': res = __sanitizer_unaligned_load16(x + 15); break;
-// CHECK-A ERROR: AddressSanitizer: heap-buffer-overflow on address
-// CHECK-A: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]]
-// CHECK-A: is located 0 bytes to the right of 16-byte region
- case 'B': res = __sanitizer_unaligned_load32(x + 14); break;
-// CHECK-B: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'C': res = __sanitizer_unaligned_load32(x + 13); break;
-// CHECK-C: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'D': res = __sanitizer_unaligned_load64(x + 15); break;
-// CHECK-D: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'E': res = __sanitizer_unaligned_load64(x + 9); break;
-// CHECK-E: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
-
- case 'K': __sanitizer_unaligned_store16(x + 15, 0); break;
-// CHECK-K ERROR: AddressSanitizer: heap-buffer-overflow on address
-// CHECK-K: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]]
-// CHECK-K: is located 0 bytes to the right of 16-byte region
- case 'L': __sanitizer_unaligned_store32(x + 15, 0); break;
-// CHECK-L: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'M': __sanitizer_unaligned_store32(x + 13, 0); break;
-// CHECK-M: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'N': __sanitizer_unaligned_store64(x + 10, 0); break;
-// CHECK-N: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'O': __sanitizer_unaligned_store64(x + 14, 0); break;
-// CHECK-O: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- }
- delete x;
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-free-right.cc b/lib/asan/lit_tests/TestCases/use-after-free-right.cc
deleted file mode 100644
index 88d91f53d24e..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-free-right.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-// Test use-after-free report in the case when access is at the right border of
-// the allocation.
-
-#include <stdlib.h>
-int main() {
- volatile char *x = (char*)malloc(sizeof(char));
- free((void*)x);
- *x = 42;
- // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
- // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
- // CHECK: {{WRITE of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*use-after-free-right.cc:13}}
- // CHECK: {{0x.* is located 0 bytes inside of 1-byte region .0x.*,0x.*}}
- // CHECK: {{freed by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*free}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:12}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_free}}
- // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free-right.cc:12}}
-
- // CHECK: {{previously allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:11}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free-right.cc:11}}
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-free.cc b/lib/asan/lit_tests/TestCases/use-after-free.cc
deleted file mode 100644
index 84ba479c1393..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-free.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-#include <stdlib.h>
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
- // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*use-after-free.cc:10}}
- // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}}
- // CHECK: {{freed by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*free}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:9}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_free}}
- // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free.cc:9}}
-
- // CHECK: {{previously allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:8}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free.cc:8}}
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-poison.cc b/lib/asan/lit_tests/TestCases/use-after-poison.cc
deleted file mode 100644
index e3bc6ecee7f2..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-poison.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Check that __asan_poison_memory_region works.
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-//
-// Check that we can disable it
-// RUN: ASAN_OPTIONS=allow_user_poisoning=0 %t
-
-#include <stdlib.h>
-
-extern "C" void __asan_poison_memory_region(void *, size_t);
-
-int main(int argc, char **argv) {
- char *x = new char[16];
- x[10] = 0;
- __asan_poison_memory_region(x, 16);
- int res = x[argc * 10]; // BOOOM
- // CHECK: ERROR: AddressSanitizer: use-after-poison
- // CHECK: main{{.*}}use-after-poison.cc:[[@LINE-2]]
- delete [] x;
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc b/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc
deleted file mode 100644
index 32fa6ad8a464..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-#include <stdio.h>
-
-struct IntHolder {
- explicit IntHolder(int *val = 0) : val_(val) { }
- ~IntHolder() {
- printf("Value: %d\n", *val_); // BOOM
- // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
- // CHECK: #0 0x{{.*}} in IntHolder::~IntHolder{{.*}}use-after-scope-dtor-order.cc:[[@LINE-2]]
- }
- void set(int *val) { val_ = val; }
- int *get() { return val_; }
-
- int *val_;
-};
-
-int main(int argc, char *argv[]) {
- // It is incorrect to use "x" int IntHolder destructor, because "x" is
- // "destroyed" earlier as it's declared later.
- IntHolder holder;
- int x = argc;
- holder.set(&x);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc b/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
deleted file mode 100644
index 0bad048e3b8f..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Test with "-O2" only to make sure inlining (leading to use-after-scope)
-// happens. "always_inline" is not enough, as Clang doesn't emit
-// llvm.lifetime intrinsics at -O0.
-//
-// RUN: %clangxx_asan -O2 -fsanitize=use-after-scope %s -o %t && not %t 2>&1 | FileCheck %s
-
-int *arr;
-
-__attribute__((always_inline))
-void inlined(int arg) {
- int x[5];
- for (int i = 0; i < arg; i++) x[i] = i;
- arr = x;
-}
-
-int main(int argc, char *argv[]) {
- inlined(argc);
- return arr[argc - 1]; // BOOM
- // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
- // CHECK: READ of size 4 at 0x{{.*}} thread T0
- // CHECK: #0 0x{{.*}} in main
- // CHECK: {{.*}}use-after-scope-inlined.cc:[[@LINE-4]]
- // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset
- // CHECK: [[OFFSET:[^ ]*]] in frame
- // CHECK: main
- // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i'
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc b/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc
deleted file mode 100644
index c23acf76eaee..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && %t
-
-#include <stdio.h>
-
-int main() {
- int *p = 0;
- // Variable goes in and out of scope.
- for (int i = 0; i < 3; i++) {
- int x = 0;
- p = &x;
- }
- printf("PASSED\n");
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc b/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc
deleted file mode 100644
index 13d714f9def7..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
-// RUN: %t 2>&1 | FileCheck %s
-//
-// Lifetime for temporaries is not emitted yet.
-// XFAIL: *
-
-#include <stdio.h>
-
-struct IntHolder {
- explicit IntHolder(int val) : val(val) {
- printf("IntHolder: %d\n", val);
- }
- int val;
-};
-
-const IntHolder *saved;
-
-void save(const IntHolder &holder) {
- saved = &holder;
-}
-
-int main(int argc, char *argv[]) {
- save(IntHolder(10));
- int x = saved->val; // BOOM
- // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
- // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cc:[[@LINE-2]]
- printf("saved value: %d\n", x);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope.cc b/lib/asan/lit_tests/TestCases/use-after-scope.cc
deleted file mode 100644
index c46c9594c314..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS="detect_stack_use_after_return=1" not %t 2>&1 | FileCheck %s
-
-int main() {
- int *p = 0;
- {
- int x = 0;
- p = &x;
- }
- return *p; // BOOM
- // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
- // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope.cc:[[@LINE-2]]
- // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame
- // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x'
-}
diff --git a/lib/asan/lit_tests/TestCases/wait.cc b/lib/asan/lit_tests/TestCases/wait.cc
deleted file mode 100644
index b5580dc88675..000000000000
--- a/lib/asan/lit_tests/TestCases/wait.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// RUN: %clangxx_asan -DWAIT -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAITPID -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAITPID -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAITID -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAITID -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT3 -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3 -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT4 -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4 -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT3_RUSAGE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3_RUSAGE -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-
-#include <assert.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-int main(int argc, char **argv) {
- pid_t pid = fork();
- if (pid) { // parent
- int x[3];
- int *status = x + argc * 3;
- int res;
-#if defined(WAIT)
- res = wait(status);
-#elif defined(WAITPID)
- res = waitpid(pid, status, WNOHANG);
-#elif defined(WAITID)
- siginfo_t *si = (siginfo_t*)(x + argc * 3);
- res = waitid(P_ALL, 0, si, WEXITED | WNOHANG);
-#elif defined(WAIT3)
- res = wait3(status, WNOHANG, NULL);
-#elif defined(WAIT4)
- res = wait4(pid, status, WNOHANG, NULL);
-#elif defined(WAIT3_RUSAGE) || defined(WAIT4_RUSAGE)
- struct rusage *ru = (struct rusage*)(x + argc * 3);
- int good_status;
-# if defined(WAIT3_RUSAGE)
- res = wait3(&good_status, WNOHANG, ru);
-# elif defined(WAIT4_RUSAGE)
- res = wait4(pid, &good_status, WNOHANG, ru);
-# endif
-#endif
- // CHECK: stack-buffer-overflow
- // CHECK: {{WRITE of size .* at 0x.* thread T0}}
- // CHECK: {{in .*wait}}
- // CHECK: {{in main .*wait.cc:}}
- // CHECK: is located in stack of thread T0 at offset
- // CHECK: {{in main}}
- return res != -1;
- }
- // child
- return 0;
-}
diff --git a/lib/asan/lit_tests/Unit/lit.site.cfg.in b/lib/asan/lit_tests/Unit/lit.site.cfg.in
deleted file mode 100644
index a45870c9b0e1..000000000000
--- a/lib/asan/lit_tests/Unit/lit.site.cfg.in
+++ /dev/null
@@ -1,16 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-
-# Setup config name.
-config.name = 'AddressSanitizer-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with ASan unit tests.
-config.test_exec_root = "@ASAN_BINARY_DIR@/tests"
-config.test_source_root = config.test_exec_root
-
-if config.host_os == 'Linux':
- config.environment['ASAN_OPTIONS'] = 'detect_leaks=1'
diff --git a/lib/asan/lit_tests/lit.cfg b/lib/asan/lit_tests/lit.cfg
deleted file mode 100644
index 71a700c6ac3b..000000000000
--- a/lib/asan/lit_tests/lit.cfg
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- Python -*-
-
-import os
-
-import lit.util
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup config name.
-config.name = 'AddressSanitizer' + config.bits
-
-# Setup source root.
-config.test_source_root = os.path.dirname(__file__)
-
-def DisplayNoConfigMessage():
- lit_config.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-asan")
-
-# Figure out LLVM source root.
-llvm_src_root = getattr(config, 'llvm_src_root', None)
-if llvm_src_root is None:
- # We probably haven't loaded the site-specific configuration: the user
- # is likely trying to run a test file directly, and the site configuration
- # wasn't created by the build system.
- asan_site_cfg = lit_config.params.get('asan_site_config', None)
- if (asan_site_cfg) and (os.path.exists(asan_site_cfg)):
- lit_config.load_config(config, asan_site_cfg)
- raise SystemExit
-
- # Try to guess the location of site-specific configuration using llvm-config
- # util that can point where the build tree is.
- llvm_config = lit.util.which("llvm-config", config.environment["PATH"])
- if not llvm_config:
- DisplayNoConfigMessage()
-
- # Find out the presumed location of generated site config.
- llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
- asan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
- "lib", "asan", "lit_tests", "lit.site.cfg")
- if (not asan_site_cfg) or (not os.path.exists(asan_site_cfg)):
- DisplayNoConfigMessage()
-
- lit_config.load_config(config, asan_site_cfg)
- raise SystemExit
-
-# Setup default compiler flags used with -fsanitize=address option.
-# FIXME: Review the set of required flags and check if it can be reduced.
-bits_cflag = " -m" + config.bits
-clang_asan_cflags = (" -fsanitize=address"
- + " -mno-omit-leaf-frame-pointer"
- + " -fno-omit-frame-pointer"
- + " -fno-optimize-sibling-calls"
- + " -g"
- + bits_cflag)
-clang_asan_cxxflags = " --driver-mode=g++" + clang_asan_cflags
-config.substitutions.append( ("%clang ", " " + config.clang + bits_cflag + " "))
-config.substitutions.append( ("%clangxx ", (" " + config.clang +
- " --driver-mode=g++" +
- bits_cflag + " ")) )
-config.substitutions.append( ("%clang_asan ", (" " + config.clang + " " +
- clang_asan_cflags + " ")) )
-config.substitutions.append( ("%clangxx_asan ", (" " + config.clang + " " +
- clang_asan_cxxflags + " ")) )
-
-# Setup path to asan_symbolize.py script.
-asan_source_dir = get_required_attr(config, "asan_source_dir")
-asan_symbolize = os.path.join(asan_source_dir, "scripts", "asan_symbolize.py")
-if not os.path.exists(asan_symbolize):
- lit_config.fatal("Can't find script on path %r" % asan_symbolize)
-python_exec = get_required_attr(config, "python_executable")
-config.substitutions.append( ("%asan_symbolize", python_exec + " " + asan_symbolize + " ") )
-
-# Define CHECK-%os to check for OS-dependent output.
-config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
-
-config.available_features.add("asan-" + config.bits + "-bits")
-
-# Turn on leak detection on 64-bit Linux.
-if config.host_os == 'Linux' and config.bits == '64':
- config.environment['ASAN_OPTIONS'] = 'detect_leaks=1'
-
-# Default test suffixes.
-config.suffixes = ['.c', '.cc', '.cpp']
-
-# AddressSanitizer tests are currently supported on Linux and Darwin only.
-if config.host_os not in ['Linux', 'Darwin']:
- config.unsupported = True
diff --git a/lib/asan/scripts/CMakeLists.txt b/lib/asan/scripts/CMakeLists.txt
new file mode 100644
index 000000000000..e5ab8ebed024
--- /dev/null
+++ b/lib/asan/scripts/CMakeLists.txt
@@ -0,0 +1,4 @@
+if(ANDROID)
+ add_compiler_rt_script(asan_device_setup)
+ add_dependencies(asan asan_device_setup)
+endif()
diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup
new file mode 100755
index 000000000000..a620f51b0836
--- /dev/null
+++ b/lib/asan/scripts/asan_device_setup
@@ -0,0 +1,267 @@
+#!/bin/bash
+#===- lib/asan/scripts/asan_device_setup -----------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+# Prepare Android device to run ASan applications.
+#
+#===------------------------------------------------------------------------===#
+
+set -e
+
+HERE="$(cd "$(dirname "$0")" && pwd)"
+
+revert=no
+extra_options=
+device=
+lib=
+
+function usage {
+ echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]"
+ echo " --revert: Uninstall ASan from the device."
+ echo " --lib: Path to ASan runtime library."
+ echo " --extra-options: Extra ASAN_OPTIONS."
+ echo " --device: Install to the given device. Use 'adb devices' to find"
+ echo " device-id."
+ echo
+ exit 1
+}
+
+function get_device_arch { # OUTVAR
+ local _outvar=$1
+ local _ABI=$($ADB shell getprop ro.product.cpu.abi)
+ local _ARCH=
+ if [[ $_ABI == x86* ]]; then
+ _ARCH=i686
+ elif [[ $_ABI == armeabi* ]]; then
+ _ARCH=arm
+ else
+ echo "Unrecognized device ABI: $_ABI"
+ exit 1
+ fi
+ eval $_outvar=\$_ARCH
+}
+
+while [[ $# > 0 ]]; do
+ case $1 in
+ --revert)
+ revert=yes
+ ;;
+ --extra-options)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--extra-options requires an argument."
+ exit 1
+ fi
+ extra_options="$1"
+ ;;
+ --lib)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--lib requires an argument."
+ exit 1
+ fi
+ lib="$1"
+ ;;
+ --device)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--device requires an argument."
+ exit 1
+ fi
+ device="$1"
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+ADB=${ADB:-adb}
+if [[ x$device != x ]]; then
+ ADB="$ADB -s $device"
+fi
+
+echo '>> Remounting /system rw'
+$ADB root
+$ADB wait-for-device
+$ADB remount
+$ADB wait-for-device
+
+get_device_arch ARCH
+echo "Target architecture: $ARCH"
+ASAN_RT="libclang_rt.asan-$ARCH-android.so"
+
+if [[ x$revert == xyes ]]; then
+ echo '>> Uninstalling ASan'
+
+ if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then
+ echo '>> Pre-L device detected.'
+ $ADB shell mv /system/bin/app_process.real /system/bin/app_process
+ $ADB shell rm /system/bin/asanwrapper
+ $ADB shell rm /system/lib/$ASAN_RT
+ else
+ $ADB shell rm /system/bin/app_process.wrap
+ $ADB shell rm /system/bin/asanwrapper
+ $ADB shell rm /system/lib/$ASAN_RT
+ $ADB shell rm /system/bin/app_process
+ $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process
+ fi
+
+ echo '>> Restarting shell'
+ $ADB shell stop
+ $ADB shell start
+
+ echo '>> Done'
+ exit 0
+fi
+
+if [[ -d "$lib" ]]; then
+ ASAN_RT_PATH="$lib"
+elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then
+ ASAN_RT_PATH=$(dirname "$lib")
+elif [[ -f "$HERE/$ASAN_RT" ]]; then
+ ASAN_RT_PATH="$HERE"
+elif [[ $(basename "$HERE") == "bin" ]]; then
+ # We could be in the toolchain's base directory.
+ # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux.
+ P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/linux/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
+ if [[ -n "$P" ]]; then
+ ASAN_RT_PATH="$(dirname "$P")"
+ fi
+fi
+
+if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
+ echo ">> ASan runtime library not found"
+ exit 1
+fi
+
+TMPDIRBASE=$(mktemp -d)
+TMPDIROLD="$TMPDIRBASE/old"
+TMPDIR="$TMPDIRBASE/new"
+mkdir "$TMPDIROLD"
+
+RELEASE=$($ADB shell getprop ro.build.version.release)
+PRE_L=0
+if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
+ PRE_L=1
+fi
+
+if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then
+
+ if $ADB pull /system/bin/app_process.real /dev/null >&/dev/null; then
+ echo '>> Old-style ASan installation detected. Reverting.'
+ $ADB shell mv /system/bin/app_process.real /system/bin/app_process
+ fi
+
+ echo '>> Pre-L device detected. Setting up app_process symlink.'
+ $ADB shell mv /system/bin/app_process /system/bin/app_process32
+ $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process
+fi
+
+echo '>> Copying files from the device'
+$ADB pull /system/bin/app_process.wrap "$TMPDIROLD" || true
+$ADB pull /system/bin/asanwrapper "$TMPDIROLD" || true
+$ADB pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
+cp -r "$TMPDIROLD" "$TMPDIR"
+
+if [[ -f "$TMPDIR/app_process.wrap" ]]; then
+ echo ">> Previous installation detected"
+else
+ echo ">> New installation"
+fi
+
+echo '>> Generating wrappers'
+
+cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"
+
+# FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup,
+# which may or may not be a real bug (probably not).
+ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0
+
+# On Android-L not allowing user segv handler breaks some applications.
+if $ADB shell 'echo $LD_PRELOAD' | grep libsigchain.so >&/dev/null; then
+ ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
+fi
+
+if [[ x$extra_options != x ]] ; then
+ ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
+fi
+
+# Zygote wrapper.
+cat <<EOF >"$TMPDIR/app_process.wrap"
+#!/system/bin/sh-from-zygote
+ASAN_OPTIONS=$ASAN_OPTIONS \\
+LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\
+exec /system/bin/app_process32 \$@
+
+EOF
+
+# General command-line tool wrapper (use for anything that's not started as
+# zygote).
+cat <<EOF >"$TMPDIR/asanwrapper"
+#!/system/bin/sh
+LD_PRELOAD=$ASAN_RT \\
+exec \$@
+
+EOF
+
+if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
+ echo '>> Pushing files to the device'
+ $ADB push "$TMPDIR/$ASAN_RT" /system/lib/
+ $ADB push "$TMPDIR/app_process.wrap" /system/bin/app_process.wrap
+ $ADB push "$TMPDIR/asanwrapper" /system/bin/asanwrapper
+
+ $ADB shell rm /system/bin/app_process
+ $ADB shell ln -s /system/bin/app_process.wrap /system/bin/app_process
+
+ $ADB shell chown root.shell \
+ /system/lib/"$ASAN_RT" \
+ /system/bin/app_process.wrap \
+ /system/bin/asanwrapper
+ $ADB shell chmod 644 \
+ /system/lib/"$ASAN_RT"
+ $ADB shell chmod 755 \
+ /system/bin/app_process.wrap \
+ /system/bin/asanwrapper
+
+ # Make SELinux happy by keeping app_process wrapper and the shell
+ # it runs on in zygote domain.
+ ENFORCING=0
+ if $ADB shell getenforce | grep Enforcing >/dev/null; then
+ # Sometimes shell is not allowed to change file contexts.
+ # Temporarily switch to permissive.
+ ENFORCING=1
+ $ADB shell setenforce 0
+ fi
+
+ $ADB shell cp /system/bin/sh /system/bin/sh-from-zygote
+
+ if [[ PRE_L -eq 1 ]]; then
+ CTX=u:object_r:system_file:s0
+ else
+ CTX=u:object_r:zygote_exec:s0
+ fi
+ $ADB shell chcon $CTX \
+ /system/bin/sh-from-zygote \
+ /system/bin/app_process.wrap \
+ /system/bin/app_process32
+
+ if [ $ENFORCING == 1 ]; then
+ $ADB shell setenforce 1
+ fi
+
+ echo '>> Restarting shell (asynchronous)'
+ $ADB shell stop
+ $ADB shell start
+
+ echo '>> Please wait until the device restarts'
+else
+ echo '>> Device is up to date'
+fi
+
+rm -r "$TMPDIRBASE"
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index a398fcf10361..5fca136b6950 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -7,6 +7,7 @@
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
+import argparse
import bisect
import getopt
import os
@@ -16,20 +17,33 @@ import subprocess
import sys
import termios
-llvm_symbolizer = None
symbolizers = {}
DEBUG = False
-demangle = False;
-
+demangle = False
+binutils_prefix = None
+sysroot_path = None
+binary_name_filter = None
+fix_filename_patterns = None
+logfile = sys.stdin
# FIXME: merge the code that calls fix_filename().
def fix_filename(file_name):
- for path_to_cut in sys.argv[1:]:
- file_name = re.sub('.*' + path_to_cut, '', file_name)
+ if fix_filename_patterns:
+ for path_to_cut in fix_filename_patterns:
+ file_name = re.sub('.*' + path_to_cut, '', file_name)
file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name)
file_name = re.sub('.*crtstuff.c:0', '???:0', file_name)
return file_name
+def sysroot_path_filter(binary_name):
+ return sysroot_path + binary_name
+
+def guess_arch(addr):
+ # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
+ if len(addr) > 10:
+ return 'x86_64'
+ else:
+ return 'i386'
class Symbolizer(object):
def __init__(self):
@@ -52,23 +66,32 @@ class Symbolizer(object):
class LLVMSymbolizer(Symbolizer):
- def __init__(self, symbolizer_path):
+ def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]):
super(LLVMSymbolizer, self).__init__()
self.symbolizer_path = symbolizer_path
+ self.default_arch = default_arch
+ self.system = system
+ self.dsym_hints = dsym_hints
self.pipe = self.open_llvm_symbolizer()
def open_llvm_symbolizer(self):
- if not os.path.exists(self.symbolizer_path):
- return None
cmd = [self.symbolizer_path,
'--use-symbol-table=true',
'--demangle=%s' % demangle,
- '--functions=true',
- '--inlining=true']
+ '--functions=short',
+ '--inlining=true',
+ '--default-arch=%s' % self.default_arch]
+ if self.system == 'Darwin':
+ for hint in self.dsym_hints:
+ cmd.append('--dsym-hint=%s' % hint)
if DEBUG:
print ' '.join(cmd)
- return subprocess.Popen(cmd, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
+ try:
+ result = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ except OSError:
+ result = None
+ return result
def symbolize(self, addr, binary, offset):
"""Overrides Symbolizer.symbolize."""
@@ -76,7 +99,7 @@ class LLVMSymbolizer(Symbolizer):
return None
result = []
try:
- symbolizer_input = '%s %s' % (binary, offset)
+ symbolizer_input = '"%s" %s' % (binary, offset)
if DEBUG:
print symbolizer_input
print >> self.pipe.stdin, symbolizer_input
@@ -86,9 +109,9 @@ class LLVMSymbolizer(Symbolizer):
break
file_name = self.pipe.stdout.readline().rstrip()
file_name = fix_filename(file_name)
- if (not function_name.startswith('??') and
+ if (not function_name.startswith('??') or
not file_name.startswith('??')):
- # Append only valid frames.
+ # Append only non-trivial frames.
result.append('%s in %s %s' % (addr, function_name,
file_name))
except Exception:
@@ -98,14 +121,14 @@ class LLVMSymbolizer(Symbolizer):
return result
-def LLVMSymbolizerFactory(system):
+def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]):
symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH')
if not symbolizer_path:
symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH')
if not symbolizer_path:
# Assume llvm-symbolizer is in PATH.
symbolizer_path = 'llvm-symbolizer'
- return LLVMSymbolizer(symbolizer_path)
+ return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints)
class Addr2LineSymbolizer(Symbolizer):
@@ -115,7 +138,10 @@ class Addr2LineSymbolizer(Symbolizer):
self.pipe = self.open_addr2line()
def open_addr2line(self):
- cmd = ['addr2line', '-f']
+ addr2line_tool = 'addr2line'
+ if binutils_prefix:
+ addr2line_tool = binutils_prefix + addr2line_tool
+ cmd = [addr2line_tool, '-f']
if demangle:
cmd += ['--demangle']
cmd += ['-e', self.binary]
@@ -173,11 +199,7 @@ class DarwinSymbolizer(Symbolizer):
def __init__(self, addr, binary):
super(DarwinSymbolizer, self).__init__()
self.binary = binary
- # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
- if len(addr) > 10:
- self.arch = 'x86_64'
- else:
- self.arch = 'i386'
+ self.arch = guess_arch(addr)
self.open_atos()
def open_atos(self):
@@ -318,23 +340,49 @@ class BreakpadSymbolizer(Symbolizer):
class SymbolizationLoop(object):
- def __init__(self, binary_name_filter=None):
+ def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
# Used by clients who may want to supply a different binary name.
# E.g. in Chrome several binaries may share a single .dSYM.
self.binary_name_filter = binary_name_filter
+ self.dsym_hint_producer = dsym_hint_producer
self.system = os.uname()[0]
- if self.system in ['Linux', 'Darwin']:
- self.llvm_symbolizer = LLVMSymbolizerFactory(self.system)
- else:
+ if self.system not in ['Linux', 'Darwin', 'FreeBSD']:
raise Exception('Unknown system')
+ self.llvm_symbolizers = {}
+ self.last_llvm_symbolizer = None
+ self.dsym_hints = set([])
+ self.frame_no = 0
def symbolize_address(self, addr, binary, offset):
+ # On non-Darwin (i.e. on platforms without .dSYM debug info) always use
+ # a single symbolizer binary.
+ # On Darwin, if the dsym hint producer is present:
+ # 1. check whether we've seen this binary already; if so,
+ # use |llvm_symbolizers[binary]|, which has already loaded the debug
+ # info for this binary (might not be the case for
+ # |last_llvm_symbolizer|);
+ # 2. otherwise check if we've seen all the hints for this binary already;
+ # if so, reuse |last_llvm_symbolizer| which has the full set of hints;
+ # 3. otherwise create a new symbolizer and pass all currently known
+ # .dSYM hints to it.
+ if not binary in self.llvm_symbolizers:
+ use_last_symbolizer = True
+ if self.system == 'Darwin' and self.dsym_hint_producer:
+ dsym_hints_for_binary = set(self.dsym_hint_producer(binary))
+ use_last_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints)
+ self.dsym_hints |= dsym_hints_for_binary
+ if self.last_llvm_symbolizer and use_last_symbolizer:
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
+ else:
+ self.last_llvm_symbolizer = LLVMSymbolizerFactory(
+ self.system, guess_arch(addr), self.dsym_hints)
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
# Use the chain of symbolizers:
# Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos
# (fall back to next symbolizer if the previous one fails).
if not binary in symbolizers:
symbolizers[binary] = ChainSymbolizer(
- [BreakpadSymbolizerFactory(binary), self.llvm_symbolizer])
+ [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
result = symbolizers[binary].symbolize(addr, binary, offset)
if result is None:
# Initialize system symbolizer only if other symbolizers failed.
@@ -345,48 +393,77 @@ class SymbolizationLoop(object):
assert result
return result
- def print_symbolized_lines(self, symbolized_lines):
+ def get_symbolized_lines(self, symbolized_lines):
if not symbolized_lines:
- print self.current_line
+ return [self.current_line]
else:
+ result = []
for symbolized_frame in symbolized_lines:
- print ' #' + str(self.frame_no) + ' ' + symbolized_frame.rstrip()
+ result.append(' #%s %s' % (str(self.frame_no), symbolized_frame.rstrip()))
self.frame_no += 1
+ return result
- def process_stdin(self):
+ def process_logfile(self):
self.frame_no = 0
while True:
- line = sys.stdin.readline()
+ line = logfile.readline()
if not line:
break
- self.current_line = line.rstrip()
- #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
- stack_trace_line_format = (
- '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
- match = re.match(stack_trace_line_format, line)
- if not match:
- print self.current_line
- continue
- if DEBUG:
- print line
- _, frameno_str, addr, binary, offset = match.groups()
- if frameno_str == '0':
- # Assume that frame #0 is the first frame of new stack trace.
- self.frame_no = 0
- original_binary = binary
- if self.binary_name_filter:
- binary = self.binary_name_filter(binary)
- symbolized_line = self.symbolize_address(addr, binary, offset)
- if not symbolized_line:
- if original_binary != binary:
- symbolized_line = self.symbolize_address(addr, binary, offset)
- self.print_symbolized_lines(symbolized_line)
+ processed = self.process_line(line)
+ print '\n'.join(processed)
+
+ def process_line(self, line):
+ self.current_line = line.rstrip()
+ #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
+ stack_trace_line_format = (
+ '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
+ match = re.match(stack_trace_line_format, line)
+ if not match:
+ return [self.current_line]
+ if DEBUG:
+ print line
+ _, frameno_str, addr, binary, offset = match.groups()
+ if frameno_str == '0':
+ # Assume that frame #0 is the first frame of new stack trace.
+ self.frame_no = 0
+ original_binary = binary
+ if self.binary_name_filter:
+ binary = self.binary_name_filter(binary)
+ symbolized_line = self.symbolize_address(addr, binary, offset)
+ if not symbolized_line:
+ if original_binary != binary:
+ symbolized_line = self.symbolize_address(addr, binary, offset)
+ return self.get_symbolized_lines(symbolized_line)
if __name__ == '__main__':
- opts, args = getopt.getopt(sys.argv[1:], "d", ["demangle"])
- for o, a in opts:
- if o in ("-d", "--demangle"):
- demangle = True;
- loop = SymbolizationLoop()
- loop.process_stdin()
+ parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='ASan symbolization script',
+ epilog='''Example of use:
+ asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" -s "$HOME/SymbolFiles" < asan.log''')
+ parser.add_argument('path_to_cut', nargs='*',
+ help='pattern to be cut from the result file path ')
+ parser.add_argument('-d','--demangle', action='store_true',
+ help='demangle function names')
+ parser.add_argument('-s', metavar='SYSROOT',
+ help='set path to sysroot for sanitized binaries')
+ parser.add_argument('-c', metavar='CROSS_COMPILE',
+ help='set prefix for binutils')
+ parser.add_argument('-l','--logfile', default=sys.stdin, type=argparse.FileType('r'),
+ help='set log file name to parse, default is stdin')
+ args = parser.parse_args()
+ if args.path_to_cut:
+ fix_filename_patterns = args.path_to_cut
+ if args.demangle:
+ demangle = True
+ if args.s:
+ binary_name_filter = sysroot_path_filter
+ sysroot_path = args.s
+ if args.c:
+ binutils_prefix = args.c
+ if args.logfile:
+ logfile = args.logfile
+ else:
+ logfile = sys.stdin
+ loop = SymbolizationLoop(binary_name_filter)
+ loop.process_logfile()
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index fc0f1788bd35..7b363714e8a5 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -15,32 +15,29 @@ include(CompilerRTCompile)
include_directories(..)
include_directories(../..)
-# Use zero-based shadow on Android.
-if(ANDROID)
- set(ASAN_TESTS_USE_ZERO_BASE_SHADOW TRUE)
-else()
- set(ASAN_TESTS_USE_ZERO_BASE_SHADOW FALSE)
-endif()
-
set(ASAN_UNITTEST_HEADERS
asan_mac_test.h
asan_test_config.h
asan_test_utils.h)
set(ASAN_UNITTEST_COMMON_CFLAGS
- ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ ${COMPILER_RT_TEST_CFLAGS}
+ ${COMPILER_RT_GTEST_CFLAGS}
-I${COMPILER_RT_SOURCE_DIR}/include
-I${COMPILER_RT_SOURCE_DIR}/lib
-I${COMPILER_RT_SOURCE_DIR}/lib/asan
-I${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/tests
- -Wall
+ -fno-rtti
+ -O2
-Wno-format
- -Werror
- -Werror=sign-compare
- -g
- -O2)
-if(SUPPORTS_NO_VARIADIC_MACROS_FLAG)
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -Wno-variadic-macros)
+ -Werror=sign-compare)
+append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
+
+# -gline-tables-only must be enough for ASan, so use it if possible.
+if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gline-tables-only)
+else()
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -g)
endif()
# Use -D instead of definitions to please custom compile command.
@@ -48,79 +45,91 @@ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
-DASAN_HAS_BLACKLIST=1
-DASAN_HAS_EXCEPTIONS=1
-DASAN_UAR=0)
-if(ANDROID)
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
- -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
- -DASAN_NEEDS_SEGV=0)
-else()
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
- -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
- -DASAN_NEEDS_SEGV=1)
-endif()
set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore")
set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
${ASAN_UNITTEST_COMMON_CFLAGS}
-fsanitize=address
"-fsanitize-blacklist=${ASAN_BLACKLIST_FILE}"
- -mllvm -asan-stack=1
- -mllvm -asan-globals=1
- -mllvm -asan-mapping-scale=0 # default will be used
- -mllvm -asan-mapping-offset-log=-1 # default will be used
)
-if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
- list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS
- -fsanitize-address-zero-base-shadow)
+if(CAN_TARGET_x86_64 OR CAN_TARGET_i386)
+ list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS -mllvm -asan-instrument-assembly)
+endif()
+
+if(NOT MSVC)
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS --driver-mode=g++)
+endif()
+
+# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests.
+if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE")
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS "-lc++")
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()
-if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
+if(ANDROID)
list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -pie)
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()
+list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address)
-set(ASAN_UNITTEST_NOINST_LINKFLAGS
- ${ASAN_UNITTEST_COMMON_LINKFLAGS}
- -ldl -lm)
-if(NOT ANDROID)
- list(APPEND ASAN_UNITTEST_NOINST_LINKFLAGS -lpthread)
-endif()
+set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS
+ ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}
+ -shared-libasan)
+
+set(ASAN_UNITTEST_INSTRUMENTED_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic ASAN_UNITTEST_INSTRUMENTED_LIBS)
+
+set(ASAN_UNITTEST_NOINST_LINKFLAGS ${ASAN_UNITTEST_COMMON_LINKFLAGS})
+append_list_if(COMPILER_RT_HAS_LIBM -lm ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread
+ ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS)
+
+# TODO(eugenis): move all -l flags above to _LIBS?
+set(ASAN_UNITTEST_NOINST_LIBS)
+append_list_if(ANDROID log ASAN_UNITTEST_NOINST_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS)
# 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)
+macro(asan_compile obj_list source arch kind)
get_filename_component(basename ${source} NAME)
- set(output_obj "${obj_list}.${basename}.${arch}.o")
+ set(output_obj "${obj_list}.${basename}.${arch}${kind}.o")
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND COMPILE_DEPS gtest asan)
+ endif()
clang_compile(${output_obj} ${source}
CFLAGS ${ARGN} ${TARGET_CFLAGS}
- DEPS gtest asan_runtime_libraries
- ${ASAN_UNITTEST_HEADERS}
- ${ASAN_BLACKLIST_FILE})
+ DEPS ${COMPILE_DEPS})
list(APPEND ${obj_list} ${output_obj})
endmacro()
# Link ASan unit test for a given architecture from a set
# of objects in with given linker flags.
-macro(add_asan_test test_suite test_name arch)
+macro(add_asan_test test_suite test_name arch kind)
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})
+ set(TEST_DEPS ${TEST_OBJECTS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND TEST_DEPS asan)
+ endif()
if(TEST_WITH_TEST_RUNTIME)
list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME})
- list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a)
+ if(NOT MSVC)
+ list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a)
+ else()
+ list(APPEND TEST_OBJECTS ${ASAN_TEST_RUNTIME}.lib)
+ endif()
endif()
add_compiler_rt_test(${test_suite} ${test_name}
OBJECTS ${TEST_OBJECTS}
@@ -144,6 +153,7 @@ set(ASAN_NOINST_TEST_SOURCES
set(ASAN_INST_TEST_SOURCES
${COMPILER_RT_GTEST_SOURCE}
+ asan_asm_test.cc
asan_globals_test.cc
asan_interface_test.cc
asan_test.cc
@@ -157,27 +167,32 @@ endif()
set(ASAN_BENCHMARKS_SOURCES
${COMPILER_RT_GTEST_SOURCE}
- asan_benchmarks_test.cc)
+ asan_benchmarks_test.cc)
# Adds ASan unit tests and benchmarks for architecture.
-macro(add_asan_tests_for_arch arch)
+macro(add_asan_tests_for_arch_and_kind arch kind)
# 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})
+ asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
endforeach()
if (APPLE)
# Add Mac-specific helper.
- asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC)
+ asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${ARGN})
endif()
- add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch}
+ add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test" ${arch} ${kind}
OBJECTS ${ASAN_INST_TEST_OBJECTS}
LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Dynamic-Test" ${arch} ${kind}
+ OBJECTS ${ASAN_INST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ endif()
# Add static ASan runtime that will be linked with uninstrumented tests.
- set(ASAN_TEST_RUNTIME RTAsanTest.${arch})
+ set(ASAN_TEST_RUNTIME RTAsanTest.${arch}${kind})
if(APPLE)
set(ASAN_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTAsan.osx>
@@ -187,10 +202,14 @@ macro(add_asan_tests_for_arch arch)
else()
set(ASAN_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
$<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTLSanCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+ if(NOT WIN32)
+ list(APPEND ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+ endif()
endif()
add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
@@ -198,10 +217,10 @@ macro(add_asan_tests_for_arch arch)
# 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})
+ asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_COMMON_CFLAGS} ${ARGN})
endforeach()
- add_asan_test(AsanUnitTests "Asan-${arch}-Noinst-Test" ${arch}
+ add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Noinst-Test" ${arch} ${kind}
OBJECTS ${ASAN_NOINST_TEST_OBJECTS}
LINKFLAGS ${ASAN_UNITTEST_NOINST_LINKFLAGS}
WITH_TEST_RUNTIME)
@@ -209,45 +228,53 @@ macro(add_asan_tests_for_arch arch)
# Benchmarks.
set(ASAN_BENCHMARKS_OBJECTS)
foreach(src ${ASAN_BENCHMARKS_SOURCES})
- asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
endforeach()
- add_asan_test(AsanBenchmarks "Asan-${arch}-Benchmark" ${arch}
+ add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Benchmark" ${arch} ${kind}
OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Dynamic-Benchmark" ${arch} ${kind}
+ OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
+ LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ endif()
endmacro()
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
foreach(arch ${ASAN_SUPPORTED_ARCH})
- add_asan_tests_for_arch(${arch})
+ add_asan_tests_for_arch_and_kind(${arch} "-inline")
+ add_asan_tests_for_arch_and_kind(${arch} "-with-calls"
+ -mllvm -asan-instrumentation-with-call-threshold=0)
endforeach()
endif()
if(ANDROID)
- # We assume that unit tests on Android are built in a build
- # tree with fresh Clang as a host compiler.
-
- # 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
- ${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(AsanNoinstTest AsanTest PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
- # Add unit test to test suite.
- add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
+ foreach(arch ${ASAN_SUPPORTED_ARCH})
+ # Test w/o ASan instrumentation. Link it with ASan statically.
+ add_executable(AsanNoinstTest # FIXME: .arch?
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ ${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})
+ target_link_libraries(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LIBS})
+
+ # Test with ASan instrumentation. Link with ASan dynamic runtime.
+ add_executable(AsanTest
+ ${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 ${ASAN_UNITTEST_INSTRUMENTED_LIBS})
+
+ # Setup correct output directory and link flags.
+ set_target_properties(AsanNoinstTest AsanTest PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ # Add unit tests to the test suite.
+ add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
+ endforeach()
endif()
diff --git a/lib/asan/tests/asan_asm_test.cc b/lib/asan/tests/asan_asm_test.cc
new file mode 100644
index 000000000000..1d8b04d611bd
--- /dev/null
+++ b/lib/asan/tests/asan_asm_test.cc
@@ -0,0 +1,267 @@
+//===-- asan_asm_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"
+
+#if defined(__linux__)
+
+#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#include <emmintrin.h>
+
+namespace {
+
+template<typename T> void asm_write(T *ptr, T val);
+template<typename T> T asm_read(T *ptr);
+template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);
+
+} // End of anonymous namespace
+
+#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#if defined(__x86_64__)
+
+namespace {
+
+#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
+template<> void asm_write<Type>(Type *ptr, Type val) { \
+ __asm__( \
+ Mov " %[val], (%[ptr]) \n\t" \
+ : \
+ : [ptr] "r" (ptr), [val] Reg (val) \
+ : "memory" \
+ ); \
+}
+
+#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
+template<> Type asm_read<Type>(Type *ptr) { \
+ Type res; \
+ __asm__( \
+ Mov " (%[ptr]), %[res] \n\t" \
+ : [res] Reg (res) \
+ : [ptr] "r" (ptr) \
+ : "memory" \
+ ); \
+ return res; \
+}
+
+#define DECLARE_ASM_REP_MOVS(Type, Movs) \
+ template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
+ __asm__("rep " Movs " \n\t" \
+ : \
+ : "D"(dst), "S"(src), "c"(size) \
+ : "rsi", "rdi", "rcx", "memory"); \
+ }
+
+DECLARE_ASM_WRITE(U8, "8", "movq", "r");
+DECLARE_ASM_READ(U8, "8", "movq", "=r");
+DECLARE_ASM_REP_MOVS(U8, "movsq");
+
+} // End of anonymous namespace
+
+#endif // defined(__x86_64__)
+
+#if defined(__i386__) && defined(__SSE2__)
+
+namespace {
+
+#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
+template<> void asm_write<Type>(Type *ptr, Type val) { \
+ __asm__( \
+ Mov " %[val], (%[ptr]) \n\t" \
+ : \
+ : [ptr] "r" (ptr), [val] Reg (val) \
+ : "memory" \
+ ); \
+}
+
+#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
+template<> Type asm_read<Type>(Type *ptr) { \
+ Type res; \
+ __asm__( \
+ Mov " (%[ptr]), %[res] \n\t" \
+ : [res] Reg (res) \
+ : [ptr] "r" (ptr) \
+ : "memory" \
+ ); \
+ return res; \
+}
+
+#define DECLARE_ASM_REP_MOVS(Type, Movs) \
+ template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
+ __asm__("rep " Movs " \n\t" \
+ : \
+ : "D"(dst), "S"(src), "c"(size) \
+ : "esi", "edi", "ecx", "memory"); \
+ }
+
+} // End of anonymous namespace
+
+#endif // defined(__i386__) && defined(__SSE2__)
+
+#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+namespace {
+
+DECLARE_ASM_WRITE(U1, "1", "movb", "r");
+DECLARE_ASM_WRITE(U2, "2", "movw", "r");
+DECLARE_ASM_WRITE(U4, "4", "movl", "r");
+DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");
+
+DECLARE_ASM_READ(U1, "1", "movb", "=r");
+DECLARE_ASM_READ(U2, "2", "movw", "=r");
+DECLARE_ASM_READ(U4, "4", "movl", "=r");
+DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");
+
+DECLARE_ASM_REP_MOVS(U1, "movsb");
+DECLARE_ASM_REP_MOVS(U2, "movsw");
+DECLARE_ASM_REP_MOVS(U4, "movsl");
+
+template<typename T> void TestAsmWrite(const char *DeathPattern) {
+ T *buf = new T;
+ EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
+ T var = 0x12;
+ asm_write(&var, static_cast<T>(0x21));
+ ASSERT_EQ(static_cast<T>(0x21), var);
+ delete buf;
+}
+
+template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
+ char *buf = new char[16];
+ char *p = buf + 16;
+ if (((uintptr_t) p % 16) != 0)
+ p = buf + 8;
+ assert(((uintptr_t) p % 16) == 0);
+ __m128i val = _mm_set1_epi16(0x1234);
+ EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
+ __m128i var = _mm_set1_epi16(0x4321);
+ asm_write(&var, val);
+ ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
+ delete [] buf;
+}
+
+template<typename T> void TestAsmRead(const char *DeathPattern) {
+ T *buf = new T;
+ EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
+ T var = 0x12;
+ ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
+ delete buf;
+}
+
+template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
+ char *buf = new char[16];
+ char *p = buf + 16;
+ if (((uintptr_t) p % 16) != 0)
+ p = buf + 8;
+ assert(((uintptr_t) p % 16) == 0);
+ EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
+ __m128i val = _mm_set1_epi16(0x1234);
+ ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
+ delete [] buf;
+}
+
+U4 AsmLoad(U4 *a) {
+ U4 r;
+ __asm__("movl (%[a]), %[r] \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
+ return r;
+}
+
+void AsmStore(U4 r, U4 *a) {
+ __asm__("movl %[r], (%[a]) \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
+}
+
+template <typename T>
+void TestAsmRepMovs(const char *DeathPatternRead,
+ const char *DeathPatternWrite) {
+ T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
+ T dst_good[4] = {};
+ asm_rep_movs(dst_good, src_good, 4);
+ ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
+ ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
+ ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
+ ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);
+
+ T dst_bad[3];
+ EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);
+
+ T src_bad[3] = { 0x0, 0x1, 0x2 };
+ EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);
+
+ T* dp = dst_bad + 4;
+ T* sp = src_bad + 4;
+ asm_rep_movs(dp, sp, 0);
+}
+
+} // End of anonymous namespace
+
+TEST(AddressSanitizer, asm_load_store) {
+ U4* buf = new U4[2];
+ EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
+ EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
+ delete [] buf;
+}
+
+TEST(AddressSanitizer, asm_rw) {
+ TestAsmWrite<U1>("WRITE of size 1");
+ TestAsmWrite<U2>("WRITE of size 2");
+ TestAsmWrite<U4>("WRITE of size 4");
+#if defined(__x86_64__)
+ TestAsmWrite<U8>("WRITE of size 8");
+#endif // defined(__x86_64__)
+ TestAsmWrite<__m128i>("WRITE of size 16");
+
+ TestAsmRead<U1>("READ of size 1");
+ TestAsmRead<U2>("READ of size 2");
+ TestAsmRead<U4>("READ of size 4");
+#if defined(__x86_64__)
+ TestAsmRead<U8>("READ of size 8");
+#endif // defined(__x86_64__)
+ TestAsmRead<__m128i>("READ of size 16");
+}
+
+TEST(AddressSanitizer, asm_flags) {
+ long magic = 0x1234;
+ long r = 0x0;
+
+#if defined(__x86_64__)
+ __asm__("xorq %%rax, %%rax \n\t"
+ "movq (%[p]), %%rax \n\t"
+ "sete %%al \n\t"
+ "movzbq %%al, %[r] \n\t"
+ : [r] "=r"(r)
+ : [p] "r"(&magic)
+ : "rax", "memory");
+#else
+ __asm__("xorl %%eax, %%eax \n\t"
+ "movl (%[p]), %%eax \n\t"
+ "sete %%al \n\t"
+ "movzbl %%al, %[r] \n\t"
+ : [r] "=r"(r)
+ : [p] "r"(&magic)
+ : "eax", "memory");
+#endif // defined(__x86_64__)
+
+ ASSERT_EQ(0x1, r);
+}
+
+TEST(AddressSanitizer, asm_rep_movs) {
+ TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
+ TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
+ TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
+#if defined(__x86_64__)
+ TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
+#endif // defined(__x86_64__)
+}
+
+#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#endif // defined(__linux__)
diff --git a/lib/asan/tests/asan_fake_stack_test.cc b/lib/asan/tests/asan_fake_stack_test.cc
index 1c98125eb45e..516142f0c3b7 100644
--- a/lib/asan/tests/asan_fake_stack_test.cc
+++ b/lib/asan/tests/asan_fake_stack_test.cc
@@ -59,14 +59,16 @@ TEST(FakeStack, FlagsOffset) {
}
}
+#if !defined(_WIN32) // FIXME: Fails due to OOM on Windows.
TEST(FakeStack, CreateDestroy) {
for (int i = 0; i < 1000; i++) {
for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) {
FakeStack *fake_stack = FakeStack::Create(stack_size_log);
- fake_stack->Destroy();
+ fake_stack->Destroy(0);
}
}
}
+#endif
TEST(FakeStack, ModuloNumberOfFrames) {
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
@@ -98,7 +100,7 @@ TEST(FakeStack, GetFrame) {
EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
- fs->Destroy();
+ fs->Destroy(0);
}
TEST(FakeStack, Allocate) {
@@ -127,7 +129,7 @@ TEST(FakeStack, Allocate) {
fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
}
}
- fs->Destroy();
+ fs->Destroy(0);
}
static void RecursiveFunction(FakeStack *fs, int depth) {
@@ -144,7 +146,7 @@ TEST(FakeStack, RecursiveStressTest) {
const uptr stack_size_log = 16;
FakeStack *fs = FakeStack::Create(stack_size_log);
RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
- fs->Destroy();
+ fs->Destroy(0);
}
} // namespace __asan
diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc
index f36679012f27..50fdf1119f0b 100644
--- a/lib/asan/tests/asan_interface_test.cc
+++ b/lib/asan/tests/asan_interface_test.cc
@@ -11,18 +11,19 @@
//
//===----------------------------------------------------------------------===//
#include "asan_test_utils.h"
-#include "sanitizer/asan_interface.h"
+#include <sanitizer/allocator_interface.h>
+#include <sanitizer/asan_interface.h>
TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
- EXPECT_EQ(0U, __asan_get_estimated_allocated_size(0));
+ EXPECT_EQ(0U, __sanitizer_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]));
+ EXPECT_EQ(sizes[i], __sanitizer_get_estimated_allocated_size(sizes[i]));
}
}
static const char* kGetAllocatedSizeErrorMsg =
- "attempting to call __asan_get_allocated_size()";
+ "attempting to call __sanitizer_get_allocated_size";
TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
const size_t kArraySize = 100;
@@ -31,38 +32,41 @@ TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
// 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));
+ EXPECT_EQ(true, __sanitizer_get_ownership(array));
+ EXPECT_EQ(kArraySize, __sanitizer_get_allocated_size(array));
+ EXPECT_EQ(true, __sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(int), __sanitizer_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),
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(wild_addr),
+ kGetAllocatedSizeErrorMsg);
+ EXPECT_FALSE(__sanitizer_get_ownership(array + kArraySize / 2));
+ EXPECT_DEATH(__sanitizer_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));
+ // NULL is not owned, but is a valid argument for
+ // __sanitizer_get_allocated_size().
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_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);
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_DEATH(__sanitizer_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));
+ EXPECT_TRUE(__sanitizer_get_ownership(zero_alloc));
// Allocated size is 0 or 1 depending on the allocator used.
- EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U);
+ EXPECT_LT(__sanitizer_get_allocated_size(zero_alloc), 2U);
}
free(zero_alloc);
}
@@ -71,14 +75,14 @@ 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();
+ before_malloc = __sanitizer_get_current_allocated_bytes();
array = Ident((char*)malloc(kMallocSize));
- after_malloc = __asan_get_current_allocated_bytes();
+ after_malloc = __sanitizer_get_current_allocated_bytes();
EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
free(array);
- after_free = __asan_get_current_allocated_bytes();
+ after_free = __sanitizer_get_current_allocated_bytes();
EXPECT_EQ(before_malloc, after_free);
}
@@ -88,11 +92,11 @@ TEST(AddressSanitizerInterface, GetHeapSizeTest) {
// 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();
+ size_t old_heap_size = __sanitizer_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());
+ EXPECT_EQ(old_heap_size, __sanitizer_get_heap_size());
}
}
@@ -116,7 +120,7 @@ static void *ManyThreadsWithStatsWorker(void *arg) {
TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
size_t before_test, after_test, i;
pthread_t threads[kManyThreadsNumThreads];
- before_test = __asan_get_current_allocated_bytes();
+ before_test = __sanitizer_get_current_allocated_bytes();
for (i = 0; i < kManyThreadsNumThreads; i++) {
PTHREAD_CREATE(&threads[i], 0,
(void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
@@ -124,7 +128,7 @@ TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
for (i = 0; i < kManyThreadsNumThreads; i++) {
PTHREAD_JOIN(threads[i], 0);
}
- after_test = __asan_get_current_allocated_bytes();
+ after_test = __sanitizer_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));
@@ -148,6 +152,7 @@ TEST(AddressSanitizerInterface, ExitCode) {
static void MyDeathCallback() {
fprintf(stderr, "MyDeathCallback\n");
+ fflush(0); // On Windows, stderr doesn't flush on crash.
}
TEST(AddressSanitizerInterface, DeathCallbackTest) {
@@ -389,6 +394,7 @@ TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
free(array);
}
+#if !defined(_WIN32) // FIXME: This should really be a lit test.
static void ErrorReportCallbackOneToZ(const char *report) {
int report_len = strlen(report);
ASSERT_EQ(6, write(2, "ABCDEF", 6));
@@ -403,6 +409,7 @@ TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
__asan_set_error_report_callback(NULL);
}
+#endif
TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
std::vector<char *> pointers;
@@ -414,11 +421,11 @@ TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
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));
+ EXPECT_FALSE(__sanitizer_get_ownership(&pointers));
+ EXPECT_FALSE(__sanitizer_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]));
+ EXPECT_TRUE(__sanitizer_get_ownership(pointers[idx]));
+ EXPECT_EQ(sizes[idx], __sanitizer_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_mem_test.cc b/lib/asan/tests/asan_mem_test.cc
index 60f5cd4cf760..4a941faa0430 100644
--- a/lib/asan/tests/asan_mem_test.cc
+++ b/lib/asan/tests/asan_mem_test.cc
@@ -76,17 +76,17 @@ TEST(AddressSanitizer, MemSetOOBTest) {
// Strictly speaking we are not guaranteed to find such two pointers,
// but given the structure of asan's allocator we will.
static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
- vector<char *> v;
+ vector<uintptr_t> v;
bool res = false;
for (size_t i = 0; i < 1000U && !res; i++) {
- v.push_back(new char[size]);
+ v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
if (i == 0) continue;
sort(v.begin(), v.end());
for (size_t j = 1; j < v.size(); j++) {
assert(v[j] > v[j-1]);
if ((size_t)(v[j] - v[j-1]) < size * 2) {
- *x2 = v[j];
- *x1 = v[j-1];
+ *x2 = reinterpret_cast<char*>(v[j]);
+ *x1 = reinterpret_cast<char*>(v[j-1]);
res = true;
break;
}
@@ -94,9 +94,10 @@ static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
}
for (size_t i = 0; i < v.size(); i++) {
- if (res && v[i] == *x1) continue;
- if (res && v[i] == *x2) continue;
- delete [] v[i];
+ char *p = reinterpret_cast<char *>(v[i]);
+ if (res && p == *x1) continue;
+ if (res && p == *x2) continue;
+ delete [] p;
}
return res;
}
diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc
index cb6223c09a46..bb6af45bddf9 100644
--- a/lib/asan/tests/asan_noinst_test.cc
+++ b/lib/asan/tests/asan_noinst_test.cc
@@ -16,6 +16,7 @@
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_test_utils.h"
+#include <sanitizer/allocator_interface.h>
#include <assert.h>
#include <stdio.h>
@@ -25,40 +26,19 @@
#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
+// ATTENTION!
+// Please don't call intercepted functions (including malloc() and friends)
+// in this test. The static runtime library is linked explicitly (without
+// -fsanitize=address), thus the interceptors do not work correctly on OS X.
+#if !defined(_WIN32)
extern "C" {
// Set specific ASan options for uninstrumented unittest.
const char* __asan_default_options() {
return "allow_reexec=0";
}
} // extern "C"
+#endif
// Make sure __asan_init is called before any test case is run.
struct AsanInitCaller {
@@ -72,19 +52,19 @@ TEST(AddressSanitizer, InternalSimpleDeathTest) {
static void MallocStress(size_t n) {
u32 seed = my_rand();
- StackTrace stack1;
- stack1.trace[0] = 0xa123;
- stack1.trace[1] = 0xa456;
+ BufferedStackTrace stack1;
+ stack1.trace_buffer[0] = 0xa123;
+ stack1.trace_buffer[1] = 0xa456;
stack1.size = 2;
- StackTrace stack2;
- stack2.trace[0] = 0xb123;
- stack2.trace[1] = 0xb456;
+ BufferedStackTrace stack2;
+ stack2.trace_buffer[0] = 0xb123;
+ stack2.trace_buffer[1] = 0xb456;
stack2.size = 2;
- StackTrace stack3;
- stack3.trace[0] = 0xc123;
- stack3.trace[1] = 0xc456;
+ BufferedStackTrace stack3;
+ stack3.trace_buffer[0] = 0xc123;
+ stack3.trace_buffer[1] = 0xc456;
stack3.size = 2;
std::vector<void *> vec;
@@ -160,8 +140,8 @@ TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
}
TEST(AddressSanitizer, QuarantineTest) {
- StackTrace stack;
- stack.trace[0] = 0x890;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
stack.size = 1;
const int size = 1024;
@@ -181,8 +161,8 @@ TEST(AddressSanitizer, QuarantineTest) {
void *ThreadedQuarantineTestWorker(void *unused) {
(void)unused;
u32 seed = my_rand();
- StackTrace stack;
- stack.trace[0] = 0x890;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
stack.size = 1;
for (size_t i = 0; i < 1000; i++) {
@@ -196,20 +176,20 @@ void *ThreadedQuarantineTestWorker(void *unused) {
// destroyed.
TEST(AddressSanitizer, ThreadedQuarantineTest) {
const int n_threads = 3000;
- size_t mmaped1 = __asan_get_heap_size();
+ size_t mmaped1 = __sanitizer_get_heap_size();
for (int i = 0; i < n_threads; i++) {
pthread_t t;
PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
PTHREAD_JOIN(t, 0);
- size_t mmaped2 = __asan_get_heap_size();
+ size_t mmaped2 = __sanitizer_get_heap_size();
EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
}
}
void *ThreadedOneSizeMallocStress(void *unused) {
(void)unused;
- StackTrace stack;
- stack.trace[0] = 0x890;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
stack.size = 1;
const size_t kNumMallocs = 1000;
for (int iter = 0; iter < 1000; iter++) {
@@ -245,3 +225,45 @@ TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
ptr = kHighShadowBeg + 200;
EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
}
+
+// Test __asan_load1 & friends.
+TEST(AddressSanitizer, LoadStoreCallbacks) {
+ typedef void (*CB)(uptr p);
+ CB cb[2][5] = {
+ {
+ __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
+ }, {
+ __asan_store1, __asan_store2, __asan_store4, __asan_store8,
+ __asan_store16,
+ }
+ };
+
+ uptr buggy_ptr;
+
+ __asan_test_only_reported_buggy_pointer = &buggy_ptr;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ for (uptr len = 16; len <= 32; len++) {
+ char *ptr = (char*) __asan::asan_malloc(len, &stack);
+ uptr p = reinterpret_cast<uptr>(ptr);
+ for (uptr is_write = 0; is_write <= 1; is_write++) {
+ for (uptr size_log = 0; size_log <= 4; size_log++) {
+ uptr size = 1 << size_log;
+ CB call = cb[is_write][size_log];
+ // Iterate only size-aligned offsets.
+ for (uptr offset = 0; offset <= len; offset += size) {
+ buggy_ptr = 0;
+ call(p + offset);
+ if (offset + size <= len)
+ EXPECT_EQ(buggy_ptr, 0U);
+ else
+ EXPECT_EQ(buggy_ptr, p + offset);
+ }
+ }
+ }
+ __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC);
+ }
+ __asan_test_only_reported_buggy_pointer = 0;
+}
diff --git a/lib/asan/tests/asan_oob_test.cc b/lib/asan/tests/asan_oob_test.cc
index f8343f19cfcb..0c6bea285864 100644
--- a/lib/asan/tests/asan_oob_test.cc
+++ b/lib/asan/tests/asan_oob_test.cc
@@ -75,7 +75,9 @@ TEST(AddressSanitizer, OOB_int) {
}
TEST(AddressSanitizer, OOBRightTest) {
- for (size_t access_size = 1; access_size <= 8; access_size *= 2) {
+ size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
+ for (size_t access_size = 1; access_size <= max_access_size;
+ access_size *= 2) {
for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
for (size_t offset = 0; offset <= 8; offset += access_size) {
void *p = malloc(alloc_size);
diff --git a/lib/asan/tests/asan_racy_double_free_test.cc b/lib/asan/tests/asan_racy_double_free_test.cc
index deeeb4f45e2f..23240e714d56 100644
--- a/lib/asan/tests/asan_racy_double_free_test.cc
+++ b/lib/asan/tests/asan_racy_double_free_test.cc
@@ -7,7 +7,7 @@ void *x[N];
void *Thread1(void *unused) {
for (int i = 0; i < N; i++) {
- fprintf(stderr, "%s %d\n", __FUNCTION__, i);
+ fprintf(stderr, "%s %d\n", __func__, i);
free(x[i]);
}
return NULL;
@@ -15,7 +15,7 @@ void *Thread1(void *unused) {
void *Thread2(void *unused) {
for (int i = 0; i < N; i++) {
- fprintf(stderr, "%s %d\n", __FUNCTION__, i);
+ fprintf(stderr, "%s %d\n", __func__, i);
free(x[i]);
}
return NULL;
diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc
index 178d00d4da86..1cd2a08b9021 100644
--- a/lib/asan/tests/asan_str_test.cc
+++ b/lib/asan/tests/asan_str_test.cc
@@ -77,7 +77,7 @@ TEST(AddressSanitizer, WcsLenTest) {
free(heap_string);
}
-#ifndef __APPLE__
+#if SANITIZER_TEST_HAS_STRNLEN
TEST(AddressSanitizer, StrNLenOOBTest) {
size_t size = Ident(123);
char *str = MallocAndMemsetString(size);
@@ -95,7 +95,7 @@ TEST(AddressSanitizer, StrNLenOOBTest) {
EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
free(str);
}
-#endif
+#endif // SANITIZER_TEST_HAS_STRNLEN
TEST(AddressSanitizer, StrDupOOBTest) {
size_t size = Ident(42);
@@ -186,7 +186,7 @@ TEST(AddressSanitizer, StrNCpyOOBTest) {
typedef char*(*PointerToStrChr1)(const char*, int);
typedef char*(*PointerToStrChr2)(char*, int);
-USED static void RunStrChrTest(PointerToStrChr1 StrChr) {
+UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr) {
size_t size = Ident(100);
char *str = MallocAndMemsetString(size);
str[10] = 'q';
@@ -202,7 +202,7 @@ USED static void RunStrChrTest(PointerToStrChr1 StrChr) {
EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
free(str);
}
-USED static void RunStrChrTest(PointerToStrChr2 StrChr) {
+UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr) {
size_t size = Ident(100);
char *str = MallocAndMemsetString(size);
str[10] = 'q';
@@ -221,7 +221,10 @@ USED static void RunStrChrTest(PointerToStrChr2 StrChr) {
TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
RunStrChrTest(&strchr);
+// No index() on Windows and on Android L.
+#if !defined(_WIN32) && !defined(__ANDROID__)
RunStrChrTest(&index);
+#endif
}
TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
@@ -244,6 +247,7 @@ TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
EXPECT_LT(0, strncmp("baa", "aaa", 1));
EXPECT_LT(0, strncmp("zyx", "", 2));
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
// strcasecmp
EXPECT_EQ(0, strcasecmp("", ""));
EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
@@ -263,6 +267,7 @@ TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
EXPECT_LT(0, strncasecmp("zyx", "", 2));
+#endif
// memcmp
EXPECT_EQ(0, memcmp("a", "b", 0));
@@ -305,9 +310,11 @@ TEST(AddressSanitizer, StrCmpOOBTest) {
RunStrCmpTest(&strcmp);
}
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
TEST(AddressSanitizer, StrCaseCmpOOBTest) {
RunStrCmpTest(&strcasecmp);
}
+#endif
typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
@@ -340,9 +347,12 @@ TEST(AddressSanitizer, StrNCmpOOBTest) {
RunStrNCmpTest(&strncmp);
}
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
RunStrNCmpTest(&strncasecmp);
}
+#endif
+
TEST(AddressSanitizer, StrCatOOBTest) {
// strcat() reads strlen(to) bytes from |to| before concatenating.
size_t to_size = Ident(100);
@@ -489,15 +499,6 @@ TEST(AddressSanitizer, StrArgsOverlapTest) {
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) {
@@ -524,18 +525,23 @@ void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
free(array);
}
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallAtoi(const char *nptr) {
+ Ident(atoi(nptr));
+}
+void CallAtol(const char *nptr) {
+ Ident(atol(nptr));
+}
+void CallAtoll(const char *nptr) {
+ Ident(atoll(nptr));
+}
TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
RunAtoiOOBTest(&CallAtoi);
RunAtoiOOBTest(&CallAtol);
RunAtoiOOBTest(&CallAtoll);
}
+#endif
-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) {
@@ -578,11 +584,19 @@ void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
free(array);
}
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+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));
+}
TEST(AddressSanitizer, StrtollOOBTest) {
RunStrtolOOBTest(&CallStrtoll);
}
TEST(AddressSanitizer, StrtolOOBTest) {
RunStrtolOOBTest(&CallStrtol);
}
+#endif
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 6539ae8af4ea..67bcbaca1e40 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -25,27 +25,10 @@ NOINLINE void *malloc_bbb(size_t size) {
NOINLINE void *malloc_aaa(size_t size) {
void *res = malloc_bbb(size); break_optimization(0); return res;}
-#ifndef __APPLE__
-NOINLINE void *memalign_fff(size_t alignment, size_t size) {
- void *res = memalign/**/(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_eee(size_t alignment, size_t size) {
- void *res = memalign_fff(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_ddd(size_t alignment, size_t size) {
- void *res = memalign_eee(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_ccc(size_t alignment, size_t size) {
- void *res = memalign_ddd(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_bbb(size_t alignment, size_t size) {
- void *res = memalign_ccc(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_aaa(size_t alignment, size_t size) {
- void *res = memalign_bbb(alignment, size); break_optimization(0); return res;}
-#endif // __APPLE__
-
-
NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
-
template<typename T>
NOINLINE void uaf_test(int size, int off) {
char *p = (char *)malloc_aaa(size);
@@ -90,19 +73,19 @@ TEST(AddressSanitizer, VariousMallocsTest) {
*c = 0;
delete c;
-#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__)
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
int *pm;
int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
EXPECT_EQ(0, pm_res);
free(pm);
-#endif
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
-#if !defined(__APPLE__)
+#if SANITIZER_TEST_HAS_MEMALIGN
int *ma = (int*)memalign(kPageSize, kPageSize);
EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
ma[123] = 0;
free(ma);
-#endif // __APPLE__
+#endif // SANITIZER_TEST_HAS_MEMALIGN
}
TEST(AddressSanitizer, CallocTest) {
@@ -124,18 +107,25 @@ TEST(AddressSanitizer, CallocReturnsZeroMem) {
EXPECT_EQ(x[size / 4], 0);
memset(x, 0x42, size);
free(Ident(x));
+#if !defined(_WIN32)
+ // FIXME: OOM on Windows. We should just make this a lit test
+ // with quarantine size set to 1.
free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
+#endif
}
}
}
+// No valloc on Windows or Android.
+#if !defined(_WIN32) && !defined(__ANDROID__)
TEST(AddressSanitizer, VallocTest) {
void *a = valloc(100);
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
free(a);
}
+#endif
-#ifndef __APPLE__
+#if SANITIZER_TEST_HAS_PVALLOC
TEST(AddressSanitizer, PvallocTest) {
char *a = (char*)pvalloc(kPageSize + 100);
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
@@ -147,8 +137,10 @@ TEST(AddressSanitizer, PvallocTest) {
a[101] = 1; // we should not report an error here.
free(a);
}
-#endif // __APPLE__
+#endif // SANITIZER_TEST_HAS_PVALLOC
+#if !defined(_WIN32)
+// FIXME: Use an equivalent of pthread_setspecific on Windows.
void *TSDWorker(void *test_key) {
if (test_key) {
pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
@@ -178,6 +170,7 @@ TEST(AddressSanitizer, DISABLED_TSDTest) {
PTHREAD_JOIN(th, NULL);
pthread_key_delete(test_key);
}
+#endif
TEST(AddressSanitizer, UAF_char) {
const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
@@ -191,18 +184,27 @@ TEST(AddressSanitizer, UAF_char) {
TEST(AddressSanitizer, UAF_long_double) {
if (sizeof(long double) == sizeof(double)) return;
long double *p = Ident(new long double[10]);
- EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[06]");
- EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[06]");
+ EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[026]");
+ EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[026]");
delete [] Ident(p);
}
+#if !defined(_WIN32)
struct Packed5 {
int x;
char c;
} __attribute__((packed));
-
+#else
+# pragma pack(push, 1)
+struct Packed5 {
+ int x;
+ char c;
+};
+# pragma pack(pop)
+#endif
TEST(AddressSanitizer, UAF_Packed5) {
+ static_assert(sizeof(Packed5) == 5, "Please check the keywords used");
Packed5 *p = Ident(new Packed5[2]);
EXPECT_DEATH(p[0] = p[3], "READ of size 5");
EXPECT_DEATH(p[3] = p[0], "WRITE of size 5");
@@ -299,12 +301,14 @@ TEST(AddressSanitizer, LargeMallocTest) {
}
TEST(AddressSanitizer, HugeMallocTest) {
- if (SANITIZER_WORDSIZE != 64) return;
+ if (SANITIZER_WORDSIZE != 64 || ASAN_AVOID_EXPENSIVE_TESTS) return;
size_t n_megs = 4100;
- TestLargeMalloc(n_megs << 20);
+ EXPECT_DEATH(Ident((char*)malloc(n_megs << 20))[-1] = 0,
+ "is located 1 bytes to the left|"
+ "AddressSanitizer failed to allocate");
}
-#ifndef __APPLE__
+#if SANITIZER_TEST_HAS_MEMALIGN
void MemalignRun(size_t align, size_t size, int idx) {
char *p = (char *)memalign(align, size);
Ident(p)[idx] = 0;
@@ -320,7 +324,7 @@ TEST(AddressSanitizer, memalign) {
"is located 1 bytes to the right");
}
}
-#endif
+#endif // SANITIZER_TEST_HAS_MEMALIGN
void *ManyThreadsWorker(void *a) {
for (int iter = 0; iter < 100; iter++) {
@@ -379,12 +383,12 @@ TEST(AddressSanitizer, ZeroSizeMallocTest) {
void *ptr = Ident(malloc(0));
EXPECT_TRUE(NULL != ptr);
free(ptr);
-#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__)
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
int pm_res = posix_memalign(&ptr, 1<<20, 0);
EXPECT_EQ(0, pm_res);
EXPECT_TRUE(NULL != ptr);
free(ptr);
-#endif
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
int *int_ptr = new int[0];
int *int_ptr2 = new int[0];
EXPECT_TRUE(NULL != int_ptr);
@@ -394,7 +398,7 @@ TEST(AddressSanitizer, ZeroSizeMallocTest) {
delete[] int_ptr2;
}
-#ifndef __APPLE__
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
static const char *kMallocUsableSizeErrorMsg =
"AddressSanitizer: attempting to call malloc_usable_size()";
@@ -412,7 +416,7 @@ TEST(AddressSanitizer, MallocUsableSizeTest) {
EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
delete int_ptr;
}
-#endif
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
void WrongFree() {
int *x = (int*)malloc(100 * sizeof(int));
@@ -421,12 +425,14 @@ void WrongFree() {
free(x + 1);
}
+#if !defined(_WIN32) // FIXME: This should be a lit test.
TEST(AddressSanitizer, WrongFreeTest) {
EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
"ERROR: AddressSanitizer: attempting free.*not malloc"
".*is located 4 bytes inside of 400-byte region"
".*allocated by thread");
}
+#endif
void DoubleFree() {
int *x = (int*)malloc(100 * sizeof(int));
@@ -437,6 +443,7 @@ void DoubleFree() {
abort();
}
+#if !defined(_WIN32) // FIXME: This should be a lit test.
TEST(AddressSanitizer, DoubleFreeTest) {
EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
"ERROR: AddressSanitizer: attempting double-free"
@@ -444,20 +451,22 @@ TEST(AddressSanitizer, DoubleFreeTest) {
".*freed by thread T0 here"
".*previously allocated by thread T0 here");
}
+#endif
template<int kSize>
NOINLINE void SizedStackTest() {
char a[kSize];
char *A = Ident((char*)&a);
+ const char *expected_death = "AddressSanitizer: stack-buffer-";
for (size_t i = 0; i < kSize; i++)
A[i] = i;
- EXPECT_DEATH(A[-1] = 0, "");
- EXPECT_DEATH(A[-20] = 0, "");
- EXPECT_DEATH(A[-31] = 0, "");
- EXPECT_DEATH(A[kSize] = 0, "");
- EXPECT_DEATH(A[kSize + 1] = 0, "");
- EXPECT_DEATH(A[kSize + 10] = 0, "");
- EXPECT_DEATH(A[kSize + 31] = 0, "");
+ EXPECT_DEATH(A[-1] = 0, expected_death);
+ EXPECT_DEATH(A[-5] = 0, expected_death);
+ EXPECT_DEATH(A[kSize] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 1] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 5] = 0, expected_death);
+ if (kSize > 16)
+ EXPECT_DEATH(A[kSize + 31] = 0, expected_death);
}
TEST(AddressSanitizer, SimpleStackTest) {
@@ -478,6 +487,9 @@ TEST(AddressSanitizer, SimpleStackTest) {
SizedStackTest<128>();
}
+#if !defined(_WIN32)
+// FIXME: It's a bit hard to write multi-line death test expectations
+// in a portable way. Anyways, this should just be turned into a lit test.
TEST(AddressSanitizer, ManyStackObjectsTest) {
char XXX[10];
char YYY[20];
@@ -486,6 +498,7 @@ TEST(AddressSanitizer, ManyStackObjectsTest) {
Ident(YYY);
EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
}
+#endif
#if 0 // This test requires online symbolizer.
// Moved to lit_tests/stack-oob-frames.cc.
@@ -538,6 +551,24 @@ NOINLINE void LongJmpFunc1(jmp_buf buf) {
longjmp(buf, 1);
}
+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++)
+ A[i] = i*i;
+}
+
+// Test that we handle longjmp and do not report false positives on stack.
+TEST(AddressSanitizer, LongJmpTest) {
+ static jmp_buf buf;
+ if (!setjmp(buf)) {
+ LongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+
+#if !defined(_WIN32) // Only basic longjmp is available on Windows.
NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
// create three red zones for these two stack objects.
int a;
@@ -571,27 +602,9 @@ NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
siglongjmp(buf, 1);
}
-
-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++)
- A[i] = i*i;
-}
-
-// Test that we handle longjmp and do not report fals positives on stack.
-TEST(AddressSanitizer, LongJmpTest) {
- static jmp_buf buf;
- if (!setjmp(buf)) {
- LongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-
-#if !defined(__ANDROID__) && \
+#if !defined(__ANDROID__) && !defined(__arm__) && \
!defined(__powerpc64__) && !defined(__powerpc__)
-// Does not work on Power:
+// Does not work on Power and ARM:
// https://code.google.com/p/address-sanitizer/issues/detail?id=185
TEST(AddressSanitizer, BuiltinLongJmpTest) {
static jmp_buf buf;
@@ -601,7 +614,8 @@ TEST(AddressSanitizer, BuiltinLongJmpTest) {
TouchStackFunc();
}
}
-#endif // not defined(__ANDROID__)
+#endif // !defined(__ANDROID__) && !defined(__powerpc64__) &&
+ // !defined(__powerpc__) && !defined(__arm__)
TEST(AddressSanitizer, UnderscopeLongJmpTest) {
static jmp_buf buf;
@@ -620,8 +634,10 @@ TEST(AddressSanitizer, SigLongJmpTest) {
TouchStackFunc();
}
}
+#endif
-#ifdef __EXCEPTIONS
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
NOINLINE void ThrowFunc() {
// create three red zones for these two stack objects.
int a;
@@ -688,12 +704,19 @@ TEST(AddressSanitizer, Store128Test) {
}
#endif
+// FIXME: All tests that use this function should be turned into lit tests.
string RightOOBErrorMessage(int oob_distance, bool is_write) {
assert(oob_distance >= 0);
char expected_str[100];
sprintf(expected_str, ASAN_PCRE_DOTALL
- "buffer-overflow.*%s.*located %d bytes to the right",
- is_write ? "WRITE" : "READ", oob_distance);
+#if !GTEST_USES_SIMPLE_RE
+ "buffer-overflow.*%s.*"
+#endif
+ "located %d bytes to the right",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
return string(expected_str);
}
@@ -705,11 +728,19 @@ string RightOOBReadMessage(int oob_distance) {
return RightOOBErrorMessage(oob_distance, /*is_write*/false);
}
+// FIXME: All tests that use this function should be turned into lit tests.
string LeftOOBErrorMessage(int oob_distance, bool is_write) {
assert(oob_distance > 0);
char expected_str[100];
- sprintf(expected_str, ASAN_PCRE_DOTALL "%s.*located %d bytes to the left",
- is_write ? "WRITE" : "READ", oob_distance);
+ sprintf(expected_str,
+#if !GTEST_USES_SIMPLE_RE
+ ASAN_PCRE_DOTALL "%s.*"
+#endif
+ "located %d bytes to the left",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
return string(expected_str);
}
@@ -738,7 +769,7 @@ char* MallocAndMemsetString(size_t size) {
return MallocAndMemsetString(size, 'z');
}
-#if defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__)
+#if defined(__linux__) && !defined(__ANDROID__)
#define READ_TEST(READ_N_BYTES) \
char *x = new char[10]; \
int fd = open("/proc/self/stat", O_RDONLY); \
@@ -761,7 +792,7 @@ TEST(AddressSanitizer, pread64) {
TEST(AddressSanitizer, read) {
READ_TEST(read(fd, x, 15));
}
-#endif // defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__)
+#endif // defined(__linux__) && !defined(__ANDROID__)
// This test case fails
// Clang optimizes memcpy/memset calls which lead to unaligned access
@@ -801,7 +832,7 @@ NOINLINE static int LargeFunction(bool do_bad_access) {
x[18]++;
x[19]++;
- delete x;
+ delete[] x;
return res;
}
@@ -863,6 +894,7 @@ void ThreadedTestSpawn() {
PTHREAD_JOIN(t, 0);
}
+#if !defined(_WIN32) // FIXME: This should be a lit test.
TEST(AddressSanitizer, ThreadedTest) {
EXPECT_DEATH(ThreadedTestSpawn(),
ASAN_PCRE_DOTALL
@@ -870,6 +902,7 @@ TEST(AddressSanitizer, ThreadedTest) {
".*Thread T.*created"
".*Thread T.*created");
}
+#endif
void *ThreadedTestFunc(void *unused) {
// Check if prctl(PR_SET_NAME) is supported. Return if not.
@@ -1064,7 +1097,8 @@ TEST(AddressSanitizer, PthreadExitTest) {
}
}
-#ifdef __EXCEPTIONS
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
NOINLINE static void StackReuseAndException() {
int large_stack[1000];
Ident(large_stack);
@@ -1082,12 +1116,14 @@ TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
}
#endif
+#if !defined(_WIN32)
TEST(AddressSanitizer, MlockTest) {
EXPECT_EQ(0, mlockall(MCL_CURRENT));
EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
EXPECT_EQ(0, munlockall());
EXPECT_EQ(0, munlock((void*)0x987, 0x654));
}
+#endif
struct LargeStruct {
int foo[100];
@@ -1111,10 +1147,15 @@ TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
Ident(NoSanitizeAddress)();
}
-// It doesn't work on Android, as calls to new/delete go through malloc/free.
-// Neither it does on OS X, see
-// https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__APPLE__)
+// The new/delete/etc mismatch checks don't work on Android,
+// as calls to new/delete go through malloc/free.
+// OS X support is tracked here:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=131
+// Windows support is tracked here:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=309
+#if !defined(__ANDROID__) && \
+ !defined(__APPLE__) && \
+ !defined(_WIN32)
static string MismatchStr(const string &str) {
return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
}
@@ -1229,6 +1270,7 @@ TEST(AddressSanitizer, LongDoubleNegativeTest) {
memcpy(Ident(&c), Ident(&b), sizeof(long double));
}
+#if !defined(_WIN32)
TEST(AddressSanitizer, pthread_getschedparam) {
int policy;
struct sched_param param;
@@ -1241,3 +1283,4 @@ TEST(AddressSanitizer, pthread_getschedparam) {
int res = pthread_getschedparam(pthread_self(), &policy, &param);
ASSERT_EQ(0, res);
}
+#endif
diff --git a/lib/asan/tests/asan_test_config.h b/lib/asan/tests/asan_test_config.h
index 6eb33ce4431b..92f276307481 100644
--- a/lib/asan/tests/asan_test_config.h
+++ b/lib/asan/tests/asan_test_config.h
@@ -21,12 +21,6 @@
#include <string>
#include <map>
-#if ASAN_USE_DEJAGNU_GTEST
-# include "dejagnu-gtest.h"
-#else
-# include "gtest/gtest.h"
-#endif
-
using std::string;
using std::vector;
using std::map;
@@ -44,7 +38,11 @@ using std::map;
#endif
#ifndef ASAN_NEEDS_SEGV
-# error "please define ASAN_NEEDS_SEGV"
+# if defined(_WIN32)
+# define ASAN_NEEDS_SEGV 0
+# else
+# define ASAN_NEEDS_SEGV 1
+# endif
#endif
#ifndef ASAN_AVOID_EXPENSIVE_TESTS
diff --git a/lib/asan/tests/asan_test_utils.h b/lib/asan/tests/asan_test_utils.h
index b6bf6b82066d..03d17cfb26a7 100644
--- a/lib/asan/tests/asan_test_utils.h
+++ b/lib/asan/tests/asan_test_utils.h
@@ -14,24 +14,28 @@
#ifndef ASAN_TEST_UTILS_H
#define ASAN_TEST_UTILS_H
-#if !defined(ASAN_EXTERNAL_TEST_CONFIG)
+#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
# define INCLUDED_FROM_ASAN_TEST_UTILS_H
# include "asan_test_config.h"
# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
#endif
#include "sanitizer_test_utils.h"
+#include "sanitizer_pthread_wrappers.h"
+
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
-#include <strings.h>
-#include <pthread.h>
#include <stdint.h>
-#include <setjmp.h>
#include <assert.h>
#include <algorithm>
-#include <sys/mman.h>
+
+#if !defined(_WIN32)
+# include <strings.h>
+# include <sys/mman.h>
+# include <setjmp.h>
+#endif
#ifdef __linux__
# include <sys/prctl.h>
@@ -41,14 +45,10 @@
#include <unistd.h>
#endif
-#ifndef __APPLE__
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
#include <malloc.h>
#endif
-// Check that pthread_create/pthread_join return success.
-#define PTHREAD_CREATE(a, b, c, d) ASSERT_EQ(0, pthread_create(a, b, c, d))
-#define PTHREAD_JOIN(a, b) ASSERT_EQ(0, pthread_join(a, b))
-
#if ASAN_HAS_EXCEPTIONS
# define ASAN_THROW(x) throw (x)
#else