diff options
Diffstat (limited to 'lib/asan')
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(¶m->t, memory_order_acquire))) == 0) + internal_sched_yield(); SetCurrentThread(t); - return t->ThreadStart(GetTid()); + return t->ThreadStart(GetTid(), ¶m->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(¶m.t, 0, memory_order_relaxed); + atomic_store(¶m.is_registered, 0, memory_order_relaxed); + int result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m); + if (result == 0) { + u32 current_tid = GetCurrentTidOrInvalid(); + AsanThread *t = + AsanThread::Create(start_routine, arg, current_tid, &stack, detached); + atomic_store(¶m.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(¶m.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(¶m.t, 0, memory_order_relaxed); + atomic_store(¶m.is_registered, 0, memory_order_relaxed); + DWORD result = REAL(CreateThread)(security, stack_size, asan_thread_start, + ¶m, thr_flags, tid); + if (result) { + u32 current_tid = GetCurrentTidOrInvalid(); + AsanThread *t = + AsanThread::Create(start_routine, arg, current_tid, &stack, detached); + atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release); + // The pthread_create interceptor waits here, so we do the same for + // consistency. + while (atomic_load(¶m.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 = ®s; -#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, ¶m); 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 |