diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:52:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:52:19 +0000 |
commit | 5c909fa013fc285f010a95e8d387e0ef3412da9c (patch) | |
tree | 1059d068ad281f4776ff44cd414574f99a460023 /lib/asan | |
parent | f31bcc68c72371a2bf63aead9f3373a1ff2053b6 (diff) | |
download | src-5c909fa013fc285f010a95e8d387e0ef3412da9c.tar.gz src-5c909fa013fc285f010a95e8d387e0ef3412da9c.zip |
Notes
Diffstat (limited to 'lib/asan')
42 files changed, 818 insertions, 1066 deletions
diff --git a/lib/asan/.clang-format b/lib/asan/.clang-format new file mode 100644 index 000000000000..f6cb8ad931f5 --- /dev/null +++ b/lib/asan/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: Google diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 28611a8a4659..6716f48b22bd 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -70,18 +70,18 @@ append_list_if(COMPILER_RT_HAS_LIBRT rt 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) +append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS) # Compile ASan sources into an object library. -if(APPLE) - add_compiler_rt_object_libraries(RTAsan - OS ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${ASAN_SUPPORTED_ARCH} - SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES} - CFLAGS ${ASAN_DYNAMIC_CFLAGS} - DEFS ${ASAN_DYNAMIC_DEFINITIONS}) -else() + +add_compiler_rt_object_libraries(RTAsan_dynamic + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${ASAN_SUPPORTED_ARCH} + SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES} + CFLAGS ${ASAN_DYNAMIC_CFLAGS} + DEFS ${ASAN_DYNAMIC_DEFINITIONS}) + +if(NOT APPLE) add_compiler_rt_object_libraries(RTAsan ARCHS ${ASAN_SUPPORTED_ARCH} SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS} @@ -94,11 +94,6 @@ else() ARCHS ${ASAN_SUPPORTED_ARCH} SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS}) - add_compiler_rt_object_libraries(RTAsan_dynamic - ARCHS ${ASAN_SUPPORTED_ARCH} - SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES} - CFLAGS ${ASAN_DYNAMIC_CFLAGS} - DEFS ${ASAN_DYNAMIC_DEFINITIONS}) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "") add_compiler_rt_object_libraries(RTAsan_dynamic_version_script_dummy @@ -111,49 +106,57 @@ endif() # Build ASan runtimes shipped with Clang. add_custom_target(asan) if(APPLE) - foreach (os ${SANITIZER_COMMON_SUPPORTED_OS}) - add_compiler_rt_darwin_dynamic_runtime(clang_rt.asan_${os}_dynamic ${os} - ARCHS ${ASAN_SUPPORTED_ARCH} - SOURCES $<TARGET_OBJECTS:RTAsan.${os}> - $<TARGET_OBJECTS:RTInterception.${os}> - $<TARGET_OBJECTS:RTSanitizerCommon.${os}> - $<TARGET_OBJECTS:RTLSanCommon.${os}> - $<TARGET_OBJECTS:RTUbsan.${os}> - CFLAGS ${ASAN_DYNAMIC_CFLAGS} - DEFS ${ASAN_DYNAMIC_DEFINITIONS}) - add_dependencies(asan clang_rt.asan_${os}_dynamic) - endforeach() + add_compiler_rt_runtime(clang_rt.asan + SHARED + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${ASAN_SUPPORTED_ARCH} + OBJECT_LIBS RTAsan_dynamic + RTInterception + RTSanitizerCommon + RTSanitizerCommonLibc + RTLSanCommon + RTUbsan + CFLAGS ${ASAN_DYNAMIC_CFLAGS} + DEFS ${ASAN_DYNAMIC_DEFINITIONS} + PARENT_TARGET asan) else() # Build separate libraries for each target. - foreach(arch ${ASAN_SUPPORTED_ARCH}) - set(ASAN_COMMON_RUNTIME_OBJECTS - $<TARGET_OBJECTS:RTInterception.${arch}> - $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> - $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> - $<TARGET_OBJECTS:RTLSanCommon.${arch}> - $<TARGET_OBJECTS:RTUbsan.${arch}>) - - add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC - SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}> - $<TARGET_OBJECTS:RTAsan.${arch}> - ${ASAN_COMMON_RUNTIME_OBJECTS} + + set(ASAN_COMMON_RUNTIME_OBJECT_LIBS + RTInterception + RTSanitizerCommon + RTSanitizerCommonLibc + RTLSanCommon + RTUbsan) + + add_compiler_rt_runtime(clang_rt.asan + STATIC + ARCHS ${ASAN_SUPPORTED_ARCH} + OBJECT_LIBS RTAsan_preinit + RTAsan + ${ASAN_COMMON_RUNTIME_OBJECT_LIBS} CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS}) - add_dependencies(asan clang_rt.asan-${arch}) + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) - add_compiler_rt_runtime(clang_rt.asan_cxx-${arch} ${arch} STATIC - SOURCES $<TARGET_OBJECTS:RTAsan_cxx.${arch}> - $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> + add_compiler_rt_runtime(clang_rt.asan_cxx + STATIC + ARCHS ${ASAN_SUPPORTED_ARCH} + OBJECT_LIBS RTAsan_cxx + RTUbsan_cxx CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS}) - add_dependencies(asan clang_rt.asan_cxx-${arch}) + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) - add_compiler_rt_runtime(clang_rt.asan-preinit-${arch} ${arch} STATIC - SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}> + add_compiler_rt_runtime(clang_rt.asan-preinit + STATIC + ARCHS ${ASAN_SUPPORTED_ARCH} + OBJECT_LIBS RTAsan_preinit CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS}) - add_dependencies(asan clang_rt.asan-preinit-${arch}) + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) + foreach(arch ${ASAN_SUPPORTED_ARCH}) if (UNIX AND NOT ${arch} MATCHES "i386|i686") add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch} LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch} @@ -168,48 +171,50 @@ else() set(VERSION_SCRIPT_FLAG) endif() - 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}> + add_compiler_rt_runtime(clang_rt.asan + SHARED + ARCHS ${arch} + OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS} + RTAsan_dynamic # The only purpose of RTAsan_dynamic_version_script_dummy is to carry # a dependency of the shared runtime on the version script. With CMake # 3.1 or later it can be replaced with a straightforward # add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list) - $<TARGET_OBJECTS:RTAsan_dynamic_version_script_dummy.${arch}> - $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> - ${ASAN_COMMON_RUNTIME_OBJECTS} + RTAsan_dynamic_version_script_dummy + RTUbsan_cxx CFLAGS ${ASAN_DYNAMIC_CFLAGS} LINKFLAGS ${ASAN_DYNAMIC_LINK_FLAGS} ${VERSION_SCRIPT_FLAG} - DEFS ${ASAN_DYNAMIC_DEFINITIONS}) - target_link_libraries(clang_rt.asan-dynamic-${arch} ${ASAN_DYNAMIC_LIBS}) - add_dependencies(asan clang_rt.asan-dynamic-${arch}) + LINK_LIBS ${ASAN_DYNAMIC_LIBS} + DEFS ${ASAN_DYNAMIC_DEFINITIONS} + PARENT_TARGET asan) if (UNIX AND NOT ${arch} MATCHES "i386|i686") - add_sanitizer_rt_symbols(clang_rt.asan_cxx-${arch}) + add_sanitizer_rt_symbols(clang_rt.asan_cxx + ARCHS ${arch}) add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols) - add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra) + add_sanitizer_rt_symbols(clang_rt.asan + ARCHS ${arch} + EXTRA asan.syms.extra) add_dependencies(asan clang_rt.asan-${arch}-symbols) endif() if (WIN32) - add_compiler_rt_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} STATIC + add_compiler_rt_runtime(clang_rt.asan_dll_thunk + STATIC + ARCHS ${arch} 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} + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) + add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk STATIC + ARCHS ${arch} 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}) + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) endif() endforeach() endif() diff --git a/lib/asan/README.txt b/lib/asan/README.txt index 8cc9bb17b59d..bb6ff42c5cde 100644 --- a/lib/asan/README.txt +++ b/lib/asan/README.txt @@ -23,4 +23,4 @@ from the root of your CMake build tree: make check-asan For more instructions see: -http://code.google.com/p/address-sanitizer/wiki/HowToBuild +https://github.com/google/sanitizers/wiki/AddressSanitizerHowToBuild diff --git a/lib/asan/asan_activation.cc b/lib/asan/asan_activation.cc index 3bc01984898d..9df3b977ea1b 100644 --- a/lib/asan/asan_activation.cc +++ b/lib/asan/asan_activation.cc @@ -38,7 +38,7 @@ static struct AsanDeactivatedFlags { #undef ASAN_ACTIVATION_FLAG #undef COMMON_ACTIVATION_FLAG - RegisterIncludeFlag(parser, cf); + RegisterIncludeFlags(parser, cf); } void OverrideFromActivationFlags() { @@ -61,11 +61,6 @@ static struct AsanDeactivatedFlags { parser.ParseString(env); } - // Override from getprop asan.options. - char buf[100]; - GetExtraActivationFlags(buf, sizeof(buf)); - parser.ParseString(buf); - SetVerbosity(cf.verbosity); if (Verbosity()) ReportUnrecognizedFlags(); @@ -124,6 +119,8 @@ void AsanActivate() { if (!asan_is_deactivated) return; VReport(1, "Activating ASan\n"); + UpdateProcessName(); + asan_deactivated_flags.OverrideFromActivationFlags(); SetCanPoisonMemory(asan_deactivated_flags.poison_heap); diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 2df9a510bd9a..56f184a36651 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -14,8 +14,8 @@ // with ThreadSanitizer and MemorySanitizer. // //===----------------------------------------------------------------------===// -#include "asan_allocator.h" +#include "asan_allocator.h" #include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_report.h" @@ -541,7 +541,7 @@ struct Allocator { u8 chunk_state = m->chunk_state; if (chunk_state != CHUNK_ALLOCATED) ReportInvalidFree(old_ptr, chunk_state, stack); - CHECK_NE(REAL(memcpy), (void*)0); + CHECK_NE(REAL(memcpy), nullptr); uptr memcpy_size = Min(new_size, m->UsedSize()); // If realloc() races with free(), we may start copying freed memory. // However, we will report racy double-free later anyway. @@ -579,7 +579,7 @@ struct Allocator { // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg). AsanChunk *GetAsanChunk(void *alloc_beg) { - if (!alloc_beg) return 0; + if (!alloc_beg) return nullptr; if (!allocator.FromPrimary(alloc_beg)) { uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg)); AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]); @@ -619,7 +619,7 @@ struct Allocator { // The address is in the chunk's left redzone, so maybe it is actually // a right buffer overflow from the other chunk to the left. // Search a bit to the left to see if there is another chunk. - AsanChunk *m2 = 0; + AsanChunk *m2 = nullptr; for (uptr l = 1; l < GetPageSizeCached(); l++) { m2 = GetAsanChunkByAddr(addr - l); if (m2 == m1) continue; // Still the same chunk. @@ -653,7 +653,7 @@ static AsanAllocator &get_allocator() { } bool AsanChunkView::IsValid() { - return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE; + return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE; } uptr AsanChunkView::Beg() { return chunk_->Beg(); } uptr AsanChunkView::End() { return Beg() + UsedSize(); } @@ -723,11 +723,11 @@ void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { } void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { - if (p == 0) + if (!p) return instance.Allocate(size, 8, stack, FROM_MALLOC, true); if (size == 0) { instance.Deallocate(p, 0, stack, FROM_MALLOC); - return 0; + return nullptr; } return instance.Reallocate(p, size, stack); } @@ -755,7 +755,7 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size, } uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) { - if (ptr == 0) return 0; + if (!ptr) return 0; uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr)); if (flags()->check_malloc_usable_size && (usable_size == 0)) { GET_STACK_TRACE_FATAL(pc, bp); @@ -780,7 +780,7 @@ void AsanSoftRssLimitExceededCallback(bool exceeded) { instance.allocator.SetRssLimitIsExceeded(exceeded); } -} // namespace __asan +} // namespace __asan // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { @@ -881,7 +881,7 @@ int __sanitizer_get_ownership(const void *p) { } uptr __sanitizer_get_allocated_size(const void *p) { - if (p == 0) return 0; + if (!p) return 0; uptr ptr = reinterpret_cast<uptr>(p); uptr allocated_size = instance.AllocationSize(ptr); // Die if p is not malloced or if it is already freed. @@ -904,5 +904,5 @@ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_free_hook(void *ptr) { (void)ptr; } -} // extern "C" +} // extern "C" #endif diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index 5ccd00c97bab..e3d53330cd2f 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -114,6 +114,11 @@ struct AsanMapUnmapCallback { # if defined(__powerpc64__) const uptr kAllocatorSpace = 0xa0000000000ULL; const uptr kAllocatorSize = 0x20000000000ULL; // 2T. +# elif defined(__aarch64__) +// AArch64/SANITIZIER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA +// so no need to different values for different VMA. +const uptr kAllocatorSpace = 0x10000000000ULL; +const uptr kAllocatorSize = 0x10000000000ULL; // 3T. # else const uptr kAllocatorSpace = 0x600000000000ULL; const uptr kAllocatorSize = 0x40000000000ULL; // 4T. diff --git a/lib/asan/asan_debugging.cc b/lib/asan/asan_debugging.cc index 6fc5b690de99..7c3a8a73bd4e 100644 --- a/lib/asan/asan_debugging.cc +++ b/lib/asan/asan_debugging.cc @@ -108,14 +108,14 @@ static uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id, return 0; } -} // namespace __asan +} // 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 }; + AddressDescription descr = { name, name_size, 0, 0, nullptr }; AsanLocateAddress(addr, &descr); if (region_address) *region_address = descr.region_address; if (region_size) *region_size = descr.region_size; diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc index d20641155b88..91fdf0aa1dca 100644 --- a/lib/asan/asan_fake_stack.cc +++ b/lib/asan/asan_fake_stack.cc @@ -11,6 +11,7 @@ // // FakeStack is used to detect use-after-return bugs. //===----------------------------------------------------------------------===// + #include "asan_allocator.h" #include "asan_poisoning.h" #include "asan_thread.h" @@ -32,7 +33,8 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { if (class_id <= 6) { for (uptr i = 0; i < (1U << class_id); i++) { shadow[i] = magic; - SanitizerBreakOptimization(0); // Make sure this does not become memset. + // Make sure this does not become memset. + SanitizerBreakOptimization(nullptr); } } else { // The size class is too big, it's cheaper to poison only size bytes. @@ -80,7 +82,9 @@ void FakeStack::PoisonAll(u8 magic) { magic); } +#if !defined(_MSC_VER) || defined(__clang__) ALWAYS_INLINE USED +#endif FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, uptr real_stack) { CHECK_LT(class_id, kNumberOfSizeClasses); @@ -106,7 +110,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, *SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos]; return res; } - return 0; // We are out of fake stack. + return nullptr; // We are out of fake stack. } uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) { @@ -183,7 +187,7 @@ void SetTLSFakeStack(FakeStack *fs) { } static FakeStack *GetFakeStack() { AsanThread *t = GetCurrentThread(); - if (!t) return 0; + if (!t) return nullptr; return t->fake_stack(); } @@ -191,7 +195,7 @@ static FakeStack *GetFakeStackFast() { if (FakeStack *fs = GetTLSFakeStack()) return fs; if (!__asan_option_detect_stack_use_after_return) - return 0; + return nullptr; return GetFakeStack(); } @@ -212,7 +216,7 @@ ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) { SetShadow(ptr, size, class_id, kMagic8); } -} // namespace __asan +} // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; @@ -245,13 +249,13 @@ 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; + if (!fs) return nullptr; 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) return nullptr; if (frame->magic != kCurrentStackFrameMagic) - return 0; + return nullptr; if (beg) *beg = reinterpret_cast<void*>(frame_beg); if (end) *end = reinterpret_cast<void*>(frame_end); return reinterpret_cast<void*>(frame->real_stack); @@ -276,4 +280,4 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) { REAL(memset)(reinterpret_cast<void*>(MemToShadow(top)), 0, (bottom - top) / SHADOW_GRANULARITY); } -} // extern "C" +} // extern "C" diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index e8ea549b62e3..363ee67e77c6 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -65,6 +65,7 @@ void InitializeFlags() { cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); cf.malloc_context_size = kDefaultMallocContextSize; cf.intercept_tls_get_addr = true; + cf.exitcode = 1; OverrideCommonFlags(cf); } Flags *f = flags(); @@ -115,14 +116,6 @@ void InitializeFlags() { ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); #endif - // Let activation flags override current settings. On Android they come - // from a system property. On other platforms this is no-op. - if (!flags()->start_deactivated) { - char buf[100]; - GetExtraActivationFlags(buf, sizeof(buf)); - asan_parser.ParseString(buf); - } - SetVerbosity(common_flags()->verbosity); // TODO(eugenis): dump all flags at verbosity>=2? diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index 53a8a4039e7e..5e69242fb8e9 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -44,9 +44,6 @@ ASAN_FLAG( "to find more errors.") ASAN_FLAG(bool, replace_intrin, true, "If set, uses custom wrappers for memset/memcpy/memmove intinsics.") -ASAN_FLAG(bool, mac_ignore_invalid_free, false, - "Ignore invalid free() calls to work around some bugs. Used on OS X " - "only.") ASAN_FLAG(bool, detect_stack_use_after_return, false, "Enables stack-use-after-return checking at run-time.") ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway. @@ -62,8 +59,6 @@ ASAN_FLAG( "bytes that will be filled with malloc_fill_byte on malloc.") ASAN_FLAG(int, malloc_fill_byte, 0xbe, "Value used to fill the newly allocated memory.") -ASAN_FLAG(int, exitcode, ASAN_DEFAULT_FAILURE_EXITCODE, - "Override the program exit status if the tool found an error.") ASAN_FLAG(bool, allow_user_poisoning, true, "If set, user may manually mark memory regions as poisoned or " "unpoisoned.") @@ -77,10 +72,7 @@ ASAN_FLAG(bool, check_malloc_usable_size, true, "295.*.") ASAN_FLAG(bool, unmap_shadow_on_exit, false, "If set, explicitly unmaps the (huge) shadow at exit.") -ASAN_FLAG( - bool, abort_on_error, false, - "If set, the tool calls abort() instead of _exit() after printing the " - "error report.") +ASAN_FLAG(bool, protect_shadow_gap, true, "If set, mprotect the shadow gap") ASAN_FLAG(bool, print_stats, false, "Print various statistics after printing an error message or if " "atexit=1.") @@ -104,8 +96,8 @@ ASAN_FLAG(bool, poison_array_cookie, true, "Poison (or not) the array cookie after operator new[].") // 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 +// https://github.com/google/sanitizers/issues/131 +// https://github.com/google/sanitizers/issues/309 // TODO(glider,timurrrr): Fix known issues and enable this back. ASAN_FLAG(bool, alloc_dealloc_mismatch, (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0), @@ -113,9 +105,6 @@ ASAN_FLAG(bool, alloc_dealloc_mismatch, ASAN_FLAG(bool, new_delete_type_mismatch, true, "Report errors on mismatch betwen size of new and delete.") -ASAN_FLAG(bool, strict_memcmp, true, - "If true, assume that memcmp(p1, p2, n) always reads n bytes before " - "comparing p1 and p2.") ASAN_FLAG( bool, strict_init_order, false, "If true, assume that dynamic initializers can never access globals from " @@ -134,8 +123,8 @@ ASAN_FLAG( "The bigger the value the harder we try.") ASAN_FLAG( bool, detect_container_overflow, true, - "If true, honor the container overflow annotations. " - "See https://code.google.com/p/address-sanitizer/wiki/ContainerOverflow") + "If true, honor the container overflow annotations. See " + "https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow") ASAN_FLAG(int, detect_odr_violation, 2, "If >=2, detect violation of One-Definition-Rule (ODR); " "If ==1, detect ODR-violation only if the two variables " @@ -143,3 +132,6 @@ ASAN_FLAG(int, detect_odr_violation, 2, ASAN_FLAG(bool, dump_instruction_bytes, false, "If true, dump 16 bytes starting at the instruction that caused SEGV") ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.") +ASAN_FLAG(bool, halt_on_error, true, + "Crash the program after printing the first error report " + "(WARNING: USE AT YOUR OWN RISK!)") diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index c34b1d3cedf2..eb9f1bfefec2 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -11,6 +11,7 @@ // // Handle globals. //===----------------------------------------------------------------------===// + #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_mapping.h" @@ -167,7 +168,7 @@ static void RegisterGlobal(const Global *g) { l->next = list_of_all_globals; list_of_all_globals = l; if (g->has_dynamic_init) { - if (dynamic_init_globals == 0) { + if (!dynamic_init_globals) { dynamic_init_globals = new(allocator_for_globals) VectorOfGlobals(kDynamicInitGlobalsInitialCapacity); } @@ -206,7 +207,7 @@ void StopInitOrderChecking() { } } -} // namespace __asan +} // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT diff --git a/lib/asan/asan_init_version.h b/lib/asan/asan_init_version.h index 6cf57c4aa2a8..bc8a622f5bb1 100644 --- a/lib/asan/asan_init_version.h +++ b/lib/asan/asan_init_version.h @@ -27,8 +27,8 @@ extern "C" { // v3=>v4: added '__asan_global_source_location' to __asan_global. // v4=>v5: changed the semantics and format of __asan_stack_malloc_ and // __asan_stack_free_ functions. - #define __asan_init __asan_init_v5 - #define __asan_init_name "__asan_init_v5" + // v5=>v6: changed the name of the version check symbol + #define __asan_version_mismatch_check __asan_version_mismatch_check_v6 } #endif // ASAN_INIT_VERSION_H diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index d8b48d391ab8..d9a0c71a002d 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -11,8 +11,8 @@ // // Intercept various libc functions. //===----------------------------------------------------------------------===// -#include "asan_interceptors.h" +#include "asan_interceptors.h" #include "asan_allocator.h" #include "asan_internal.h" #include "asan_mapping.h" @@ -27,6 +27,12 @@ #include "sanitizer_common/sanitizer_posix.h" #endif +#if defined(__i386) && SANITIZER_LINUX +#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1" +#elif defined(__mips__) && SANITIZER_LINUX +#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2" +#endif + namespace __asan { // Return true if we can quickly decide that the region is unpoisoned. @@ -69,7 +75,7 @@ struct AsanInterceptorContext { } \ if (!suppressed) { \ GET_CURRENT_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0); \ + ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\ } \ } \ } while (0) @@ -105,7 +111,7 @@ static inline bool RangesOverlap(const char *offset1, uptr length1, static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { #if ASAN_INTERCEPT_STRNLEN - if (REAL(strnlen) != 0) { + if (REAL(strnlen)) { return REAL(strnlen)(s, maxlen); } #endif @@ -123,7 +129,7 @@ int OnExit() { return 0; } -} // namespace __asan +} // namespace __asan // ---------------------- Wrappers ---------------- {{{1 using namespace __asan; // NOLINT @@ -172,7 +178,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) } while (false) #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) // Strict init-order checking is dlopen-hostile: -// https://code.google.com/p/address-sanitizer/issues/detail?id=178 +// https://github.com/google/sanitizers/issues/178 #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ if (flags()->strict_init_order) { \ StopInitOrderChecking(); \ @@ -216,7 +222,7 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg); AsanThread *t = nullptr; while ((t = reinterpret_cast<AsanThread *>( - atomic_load(¶m->t, memory_order_acquire))) == 0) + atomic_load(¶m->t, memory_order_acquire))) == nullptr) internal_sched_yield(); SetCurrentThread(t); return t->ThreadStart(GetTid(), ¶m->is_registered); @@ -231,7 +237,7 @@ INTERCEPTOR(int, pthread_create, void *thread, StopInitOrderChecking(); GET_STACK_TRACE_THREAD; int detached = 0; - if (attr != 0) + if (attr) REAL(pthread_attr_getdetachstate)(attr, &detached); ThreadStartParam param; atomic_store(¶m.t, 0, memory_order_relaxed); @@ -270,14 +276,14 @@ INTERCEPTOR(void*, bsd_signal, int signum, void *handler) { } return 0; } -#else +#endif + INTERCEPTOR(void*, signal, int signum, void *handler) { if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) { return REAL(signal)(signum, handler); } - return 0; + return nullptr; } -#endif INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) { @@ -292,7 +298,7 @@ int real_sigaction(int signum, const void *act, void *oldact) { return REAL(sigaction)(signum, (const struct sigaction *)act, (struct sigaction *)oldact); } -} // namespace __sanitizer +} // namespace __sanitizer #elif SANITIZER_POSIX // We need to have defined REAL(sigaction) on posix systems. @@ -363,40 +369,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { } #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) { - 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(ctx, a1, size); - ASAN_READ_RANGE(ctx, a2, size); - // Fallthrough to REAL(memcmp) below. - } else { - unsigned char c1 = 0, c2 = 0; - const unsigned char *s1 = (const unsigned char*)a1; - const unsigned char *s2 = (const unsigned char*)a2; - uptr i; - for (i = 0; i < size; i++) { - c1 = s1[i]; - c2 = s2[i]; - if (c1 != c2) break; - } - 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)); -} - // 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. @@ -743,7 +715,7 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, #endif ENSURE_ASAN_INITED(); int res = REAL(__cxa_atexit)(func, arg, dso_handle); - REAL(__cxa_atexit)(AtCxaAtexit, 0, 0); + REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); return res; } #endif // ASAN_INTERCEPT___CXA_ATEXIT @@ -767,7 +739,6 @@ void InitializeAsanInterceptors() { InitializeCommonInterceptors(); // Intercept mem* functions. - ASAN_INTERCEPT_FUNC(memcmp); ASAN_INTERCEPT_FUNC(memmove); ASAN_INTERCEPT_FUNC(memset); if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { @@ -806,9 +777,8 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(sigaction); #if SANITIZER_ANDROID ASAN_INTERCEPT_FUNC(bsd_signal); -#else - ASAN_INTERCEPT_FUNC(signal); #endif + ASAN_INTERCEPT_FUNC(signal); #endif #if ASAN_INTERCEPT_SWAPCONTEXT ASAN_INTERCEPT_FUNC(swapcontext); @@ -827,7 +797,11 @@ void InitializeAsanInterceptors() { // Intercept threading-related functions #if ASAN_INTERCEPT_PTHREAD_CREATE +#if defined(ASAN_PTHREAD_CREATE_VERSION) + ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION); +#else ASAN_INTERCEPT_FUNC(pthread_create); +#endif ASAN_INTERCEPT_FUNC(pthread_join); #endif @@ -845,4 +819,4 @@ void InitializeAsanInterceptors() { VReport(1, "AddressSanitizer: libc interceptors initialized\n"); } -} // namespace __asan +} // namespace __asan diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index 488ada78ab8b..279c5f38451f 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -98,6 +98,12 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \ VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \ } while (0) +#define ASAN_INTERCEPT_FUNC_VER(name, ver) \ + do { \ + if ((!INTERCEPT_FUNCTION_VER(name, ver) || !REAL(name))) \ + VReport( \ + 1, "AddressSanitizer: failed to intercept '" #name "@@" #ver "'\n"); \ + } while (0) #else // OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. #define ASAN_INTERCEPT_FUNC(name) diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index ad8ebcd91ad9..9efddcbd42b2 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -27,10 +27,14 @@ 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. - // 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 function exists purely to get a linker/loader error when using + // incompatible versions of instrumentation and runtime library. Please note + // that __asan_version_mismatch_check is a macro that is replaced with + // __asan_version_mismatch_check_vXXX at compile-time. + SANITIZER_INTERFACE_ATTRIBUTE void __asan_version_mismatch_check(); + // This structure is used to describe the source location of a place where // global was defined. struct __asan_global_source_location { @@ -131,8 +135,6 @@ extern "C" { uptr addr, int is_write, uptr access_size, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE - int __asan_set_error_exit_code(int exit_code); - SANITIZER_INTERFACE_ATTRIBUTE void __asan_set_death_callback(void (*callback)(void)); SANITIZER_INTERFACE_ATTRIBUTE void __asan_set_error_report_callback(void (*callback)(const char*)); @@ -165,6 +167,19 @@ extern "C" { 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_load1_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16_noabort(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN_noabort(uptr p, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN_noabort(uptr p, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp); diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index 107e16ee31b9..0ef0d0eb5263 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -21,8 +21,6 @@ #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_libc.h" -#define ASAN_DEFAULT_FAILURE_EXITCODE 1 - #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) # error "The AddressSanitizer run-time should not be" " instrumented by AddressSanitizer" @@ -75,12 +73,9 @@ void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); -void AsanOnSIGSEGV(int, void *siginfo, void *context); +void AsanOnDeadlySignal(int, void *siginfo, void *context); -void DisableReexec(); -void MaybeReexec(); void ReadContextStack(void *context, uptr *stack, uptr *ssize); -void AsanPlatformThreadInit(); void StopInitOrderChecking(); // Wrapper for TLS/TSD. diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 9580fc7c06d4..e26b400562df 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -70,14 +70,6 @@ namespace __asan { void InitializePlatformInterceptors() {} -void DisableReexec() { - // No need to re-exec on Linux. -} - -void MaybeReexec() { - // No need to re-exec on Linux. -} - void *AsanDoesNotSupportStaticLinkage() { // This will fail to link with -static. return &_DYNAMIC; // defined in link.h @@ -117,7 +109,7 @@ void AsanCheckDynamicRTPrereqs() { return; // Ensure that dynamic RT is the first DSO in the list - const char *first_dso_name = 0; + const char *first_dso_name = nullptr; 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; " @@ -142,7 +134,8 @@ void AsanCheckIncompatibleRT() { // 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)) { + while (proc_maps.Next(nullptr, nullptr, nullptr, filename, + sizeof(filename), nullptr)) { if (IsDynamicRTName(filename)) { Report("Your application is linked against " "incompatible ASan runtimes.\n"); @@ -155,11 +148,7 @@ void AsanCheckIncompatibleRT() { } } } -#endif // SANITIZER_ANDROID - -void AsanPlatformThreadInit() { - // Nothing here for now. -} +#endif // SANITIZER_ANDROID #if !SANITIZER_ANDROID void ReadContextStack(void *context, uptr *stack, uptr *ssize) { @@ -177,6 +166,6 @@ void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); } -} // namespace __asan +} // namespace __asan -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index 3e028378df28..f00d98f8e5e6 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -24,26 +24,17 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mac.h" -#if !SANITIZER_IOS -#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron -#else -extern "C" { - extern char ***_NSGetArgv(void); -} -#endif - -#include <dlfcn.h> // for dladdr() +#include <fcntl.h> +#include <libkern/OSAtomic.h> #include <mach-o/dyld.h> #include <mach-o/loader.h> +#include <pthread.h> +#include <stdlib.h> // for free() #include <sys/mman.h> #include <sys/resource.h> #include <sys/sysctl.h> #include <sys/ucontext.h> -#include <fcntl.h> -#include <pthread.h> -#include <stdlib.h> // for free() #include <unistd.h> -#include <libkern/OSAtomic.h> namespace __asan { @@ -52,187 +43,12 @@ void InitializePlatformInterceptors() {} bool PlatformHasDifferentMemcpyAndMemmove() { // On OS X 10.7 memcpy() and memmove() are both resolved // into memmove$VARIANT$sse42. - // See also http://code.google.com/p/address-sanitizer/issues/detail?id=34. + // See also https://github.com/google/sanitizers/issues/34. // TODO(glider): need to check dynamically that memcpy() and memmove() are // actually the same function. return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; } -extern "C" -void __asan_init(); - -static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; -LowLevelAllocator allocator_for_env; - -// Change the value of the env var |name|, leaking the original value. -// If |name_value| is NULL, the variable is deleted from the environment, -// otherwise the corresponding "NAME=value" string is replaced with -// |name_value|. -void LeakyResetEnv(const char *name, const char *name_value) { - char **env = GetEnviron(); - uptr name_len = internal_strlen(name); - while (*env != 0) { - uptr len = internal_strlen(*env); - if (len > name_len) { - const char *p = *env; - if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { - // Match. - if (name_value) { - // Replace the old value with the new one. - *env = const_cast<char*>(name_value); - } else { - // Shift the subsequent pointers back. - char **del = env; - do { - del[0] = del[1]; - } while (*del++); - } - } - } - env++; - } -} - -static bool reexec_disabled = false; - -void DisableReexec() { - reexec_disabled = true; -} - -bool DyldNeedsEnvVariable() { -// If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if -// DYLD_INSERT_LIBRARIES is not set. - -#if SANITIZER_IOSSIM - // GetMacosVersion will not work for the simulator, whose kernel version - // is tied to the host. Use a weak linking hack for the simulator. - // This API was introduced in the same version of the OS as the dyld - // optimization. - - // Check for presence of a symbol that is available on OS X 10.11+, iOS 9.0+. - return (dlsym(RTLD_NEXT, "mach_memory_info") == nullptr); -#else - return (GetMacosVersion() <= MACOS_VERSION_YOSEMITE); -#endif -} - -void MaybeReexec() { - if (reexec_disabled) return; - - // Make sure the dynamic ASan runtime library is preloaded so that the - // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec - // ourselves. - Dl_info info; - CHECK(dladdr((void*)((uptr)__asan_init), &info)); - char *dyld_insert_libraries = - const_cast<char*>(GetEnv(kDyldInsertLibraries)); - uptr old_env_len = dyld_insert_libraries ? - internal_strlen(dyld_insert_libraries) : 0; - uptr fname_len = internal_strlen(info.dli_fname); - const char *dylib_name = StripModuleName(info.dli_fname); - uptr dylib_name_len = internal_strlen(dylib_name); - - bool lib_is_in_env = - dyld_insert_libraries && REAL(strstr)(dyld_insert_libraries, dylib_name); - if (DyldNeedsEnvVariable() && !lib_is_in_env) { - // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime - // library. - char program_name[1024]; - uint32_t buf_size = sizeof(program_name); - _NSGetExecutablePath(program_name, &buf_size); - char *new_env = const_cast<char*>(info.dli_fname); - if (dyld_insert_libraries) { - // Append the runtime dylib name to the existing value of - // DYLD_INSERT_LIBRARIES. - new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); - internal_strncpy(new_env, dyld_insert_libraries, old_env_len); - new_env[old_env_len] = ':'; - // Copy fname_len and add a trailing zero. - internal_strncpy(new_env + old_env_len + 1, info.dli_fname, - fname_len + 1); - // Ok to use setenv() since the wrappers don't depend on the value of - // asan_inited. - setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); - } else { - // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. - setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); - } - VReport(1, "exec()-ing the program with\n"); - VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); - VReport(1, "to enable ASan wrappers.\n"); - execv(program_name, *_NSGetArgv()); - - // We get here only if execv() failed. - Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " - "which is required for ASan to work. ASan tried to set the " - "environment variable and re-execute itself, but execv() failed, " - "possibly because of sandbox restrictions. Make sure to launch the " - "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); - CHECK("execv failed" && 0); - } - - if (!lib_is_in_env) - return; - - // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove - // the dylib from the environment variable, because interceptors are installed - // and we don't want our children to inherit the variable. - - uptr env_name_len = internal_strlen(kDyldInsertLibraries); - // Allocate memory to hold the previous env var name, its value, the '=' - // sign and the '\0' char. - char *new_env = (char*)allocator_for_env.Allocate( - old_env_len + 2 + env_name_len); - CHECK(new_env); - internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); - internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); - new_env[env_name_len] = '='; - char *new_env_pos = new_env + env_name_len + 1; - - // Iterate over colon-separated pieces of |dyld_insert_libraries|. - char *piece_start = dyld_insert_libraries; - char *piece_end = NULL; - char *old_env_end = dyld_insert_libraries + old_env_len; - do { - if (piece_start[0] == ':') piece_start++; - piece_end = REAL(strchr)(piece_start, ':'); - if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; - if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; - uptr piece_len = piece_end - piece_start; - - char *filename_start = - (char *)internal_memrchr(piece_start, '/', piece_len); - uptr filename_len = piece_len; - if (filename_start) { - filename_start += 1; - filename_len = piece_len - (filename_start - piece_start); - } else { - filename_start = piece_start; - } - - // If the current piece isn't the runtime library name, - // append it to new_env. - if ((dylib_name_len != filename_len) || - (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { - if (new_env_pos != new_env + env_name_len + 1) { - new_env_pos[0] = ':'; - new_env_pos++; - } - internal_strncpy(new_env_pos, piece_start, piece_len); - new_env_pos += piece_len; - } - // Move on to the next piece. - piece_start = piece_end; - } while (piece_start < old_env_end); - - // Can't use setenv() here, because it requires the allocator to be - // initialized. - // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in - // a separate function called after InitializeAllocator(). - if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; - LeakyResetEnv(kDyldInsertLibraries, new_env); -} - // No-op. Mac does not support static linkage anyway. void *AsanDoesNotSupportStaticLinkage() { return 0; @@ -244,9 +60,6 @@ void AsanCheckDynamicRTPrereqs() {} // No-op. Mac does not support static linkage anyway. void AsanCheckIncompatibleRT() {} -void AsanPlatformThreadInit() { -} - void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index 46a6a9db4a81..d5089f9f7b36 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -26,13 +26,25 @@ // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT +static const uptr kCallocPoolSize = 1024; +static uptr calloc_memory_for_dlsym[kCallocPoolSize]; + +static bool IsInCallocPool(const void *ptr) { + sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym; + return 0 <= off && off < (sptr)kCallocPoolSize; +} + INTERCEPTOR(void, free, void *ptr) { GET_STACK_TRACE_FREE; + if (UNLIKELY(IsInCallocPool(ptr))) + return; asan_free(ptr, &stack, FROM_MALLOC); } INTERCEPTOR(void, cfree, void *ptr) { GET_STACK_TRACE_FREE; + if (UNLIKELY(IsInCallocPool(ptr))) + return; asan_free(ptr, &stack, FROM_MALLOC); } @@ -44,8 +56,6 @@ INTERCEPTOR(void*, malloc, uptr size) { INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { 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]; static uptr allocated; uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; void *mem = (void*)&calloc_memory_for_dlsym[allocated]; @@ -59,6 +69,13 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { INTERCEPTOR(void*, realloc, void *ptr, uptr size) { GET_STACK_TRACE_MALLOC; + if (UNLIKELY(IsInCallocPool(ptr))) { + uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym; + uptr copy_size = Min(size, kCallocPoolSize - offset); + void *new_ptr = asan_malloc(size, &stack); + internal_memcpy(new_ptr, ptr, copy_size); + return new_ptr; + } return asan_realloc(ptr, size, &stack); } diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc index d7a6307c9bdc..744728d40df5 100644 --- a/lib/asan/asan_malloc_mac.cc +++ b/lib/asan/asan_malloc_mac.cc @@ -15,348 +15,47 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_MAC -#include <AvailabilityMacros.h> -#include <CoreFoundation/CFBase.h> -#include <dlfcn.h> -#include <malloc/malloc.h> -#include <sys/mman.h> - -#include "asan_allocator.h" #include "asan_interceptors.h" -#include "asan_internal.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. - -// ---------------------- Replacement functions ---------------- {{{1 -using namespace __asan; // NOLINT - -// TODO(glider): do we need both zones? -static malloc_zone_t *system_malloc_zone = 0; -static malloc_zone_t asan_zone; - -INTERCEPTOR(malloc_zone_t *, malloc_create_zone, - vm_size_t start_size, unsigned zone_flags) { - ENSURE_ASAN_INITED(); - GET_STACK_TRACE_MALLOC; - uptr page_size = GetPageSizeCached(); - uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size); - malloc_zone_t *new_zone = - (malloc_zone_t*)asan_memalign(page_size, allocated_size, - &stack, FROM_MALLOC); - internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone)); - new_zone->zone_name = NULL; // The name will be changed anyway. - if (GetMacosVersion() >= MACOS_VERSION_LION) { - // Prevent the client app from overwriting the zone contents. - // Library functions that need to modify the zone will set PROT_WRITE on it. - // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. - mprotect(new_zone, allocated_size, PROT_READ); - } - return new_zone; -} - -INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) { - 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 - 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. - ENSURE_ASAN_INITED(); -} - -INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) { - // FIXME: ASan should support purgeable allocations. Ignoring them is fine - // for now. - 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) { - ENSURE_ASAN_INITED(); - // Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes. - size_t buflen = 6 + (name ? internal_strlen(name) : 0); - InternalScopedString new_name(buflen); - if (name && zone->introspect == asan_zone.introspect) { - new_name.append("asan-%s", name); - name = new_name.data(); - } - - // Call the system malloc's implementation for both external and our zones, - // since that appropriately changes VM region protections on the zone. - REAL(malloc_set_zone_name)(zone, name); -} - -INTERCEPTOR(void *, malloc, size_t size) { - ENSURE_ASAN_INITED(); - GET_STACK_TRACE_MALLOC; - void *res = asan_malloc(size, &stack); - return res; -} -INTERCEPTOR(void, free, void *ptr) { - ENSURE_ASAN_INITED(); - if (!ptr) return; - GET_STACK_TRACE_FREE; +using namespace __asan; +#define COMMON_MALLOC_ZONE_NAME "asan" +#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED() +#define COMMON_MALLOC_SANITIZER_INITIALIZED asan_inited +#define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock() +#define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock() +#define COMMON_MALLOC_MEMALIGN(alignment, size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = asan_memalign(alignment, size, &stack, FROM_MALLOC) +#define COMMON_MALLOC_MALLOC(size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = asan_malloc(size, &stack) +#define COMMON_MALLOC_REALLOC(ptr, size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = asan_realloc(ptr, size, &stack); +#define COMMON_MALLOC_CALLOC(count, size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = asan_calloc(count, size, &stack); +#define COMMON_MALLOC_VALLOC(size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC); +#define COMMON_MALLOC_FREE(ptr) \ + GET_STACK_TRACE_FREE; \ asan_free(ptr, &stack, FROM_MALLOC); -} - -INTERCEPTOR(void *, realloc, void *ptr, size_t size) { - ENSURE_ASAN_INITED(); - GET_STACK_TRACE_MALLOC; - return asan_realloc(ptr, size, &stack); -} - -INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) { - ENSURE_ASAN_INITED(); - GET_STACK_TRACE_MALLOC; - return asan_calloc(nmemb, size, &stack); -} - -INTERCEPTOR(void *, valloc, size_t size) { - ENSURE_ASAN_INITED(); - GET_STACK_TRACE_MALLOC; - return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC); -} - -INTERCEPTOR(size_t, malloc_good_size, size_t size) { - ENSURE_ASAN_INITED(); - return asan_zone.introspect->good_size(&asan_zone, size); -} - -INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) { - ENSURE_ASAN_INITED(); - CHECK(memptr); - GET_STACK_TRACE_MALLOC; - void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC); - if (result) { - *memptr = result; - return 0; - } - return -1; -} - -namespace { - -// TODO(glider): the __asan_mz_* functions should be united with the Linux -// wrappers, as they are basically copied from there. -extern "C" -SANITIZER_INTERFACE_ATTRIBUTE -size_t __asan_mz_size(malloc_zone_t* zone, const void* ptr) { - return asan_mz_size(ptr); -} - -extern "C" -SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_mz_malloc(malloc_zone_t *zone, uptr size) { - if (UNLIKELY(!asan_inited)) { - CHECK(system_malloc_zone); - return malloc_zone_malloc(system_malloc_zone, size); - } - GET_STACK_TRACE_MALLOC; - return asan_malloc(size, &stack); -} - -extern "C" -SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) { - 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]; - static size_t allocated; - size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; - void *mem = (void*)&calloc_memory_for_dlsym[allocated]; - allocated += size_in_words; - CHECK(allocated < kCallocPoolSize); - return mem; - } - GET_STACK_TRACE_MALLOC; - return asan_calloc(nmemb, size, &stack); -} - -extern "C" -SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_mz_valloc(malloc_zone_t *zone, size_t size) { - if (UNLIKELY(!asan_inited)) { - CHECK(system_malloc_zone); - return malloc_zone_valloc(system_malloc_zone, size); - } - GET_STACK_TRACE_MALLOC; - return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC); -} - -#define GET_ZONE_FOR_PTR(ptr) \ - malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \ - const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name - -void ALWAYS_INLINE free_common(void *context, void *ptr) { - if (!ptr) return; - GET_STACK_TRACE_FREE; - // FIXME: need to retire this flag. - if (!flags()->mac_ignore_invalid_free) { - asan_free(ptr, &stack, FROM_MALLOC); - } else { - GET_ZONE_FOR_PTR(ptr); - WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack); - return; - } -} - -// TODO(glider): the allocation callbacks need to be refactored. -extern "C" -SANITIZER_INTERFACE_ATTRIBUTE -void __asan_mz_free(malloc_zone_t *zone, void *ptr) { - free_common(zone, ptr); -} - -extern "C" -SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) { - if (!ptr) { - GET_STACK_TRACE_MALLOC; - return asan_malloc(size, &stack); - } else { - if (asan_mz_size(ptr)) { - GET_STACK_TRACE_MALLOC; - return asan_realloc(ptr, size, &stack); - } else { - // We can't recover from reallocating an unknown address, because - // this would require reading at most |size| bytes from - // potentially unaccessible memory. - GET_STACK_TRACE_FREE; - GET_ZONE_FOR_PTR(ptr); - ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack); - } - } -} - -extern "C" -SANITIZER_INTERFACE_ATTRIBUTE -void __asan_mz_destroy(malloc_zone_t* zone) { - // A no-op -- we will not be destroyed! - Report("__asan_mz_destroy() called -- ignoring\n"); -} - -extern "C" -SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) { - if (UNLIKELY(!asan_inited)) { - CHECK(system_malloc_zone); - return malloc_zone_memalign(system_malloc_zone, align, size); - } - GET_STACK_TRACE_MALLOC; - return asan_memalign(align, size, &stack, FROM_MALLOC); -} - -// This function is currently unused, and we build with -Werror. -#if 0 -void __asan_mz_free_definite_size( - malloc_zone_t* zone, void *ptr, size_t size) { - // TODO(glider): check that |size| is valid. - UNIMPLEMENTED(); -} -#endif - -kern_return_t mi_enumerator(task_t task, void *, - unsigned type_mask, vm_address_t zone_address, - memory_reader_t reader, - vm_range_recorder_t recorder) { - // Should enumerate all the pointers we have. Seems like a lot of work. - return KERN_FAILURE; -} - -size_t mi_good_size(malloc_zone_t *zone, size_t size) { - // I think it's always safe to return size, but we maybe could do better. - return size; -} - -boolean_t mi_check(malloc_zone_t *zone) { - UNIMPLEMENTED(); -} - -void mi_print(malloc_zone_t *zone, boolean_t verbose) { - UNIMPLEMENTED(); -} - -void mi_log(malloc_zone_t *zone, void *address) { - // I don't think we support anything like this -} - -void mi_force_lock(malloc_zone_t *zone) { - asan_mz_force_lock(); -} - -void mi_force_unlock(malloc_zone_t *zone) { - asan_mz_force_unlock(); -} - -void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) { - AsanMallocStats malloc_stats; - FillMallocStatistics(&malloc_stats); - CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats)); +#define COMMON_MALLOC_SIZE(ptr) \ + uptr size = asan_mz_size(ptr); +#define COMMON_MALLOC_FILL_STATS(zone, stats) \ + AsanMallocStats malloc_stats; \ + FillMallocStatistics(&malloc_stats); \ + CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats)); \ internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t)); -} - -boolean_t mi_zone_locked(malloc_zone_t *zone) { - // UNIMPLEMENTED(); - return false; -} - -} // unnamed namespace - -namespace __asan { +#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \ + GET_STACK_TRACE_FREE; \ + ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack); +#define COMMON_MALLOC_NAMESPACE __asan -void ReplaceSystemMalloc() { - static malloc_introspection_t asan_introspection; - // Ok to use internal_memset, these places are not performance-critical. - internal_memset(&asan_introspection, 0, sizeof(asan_introspection)); +#include "sanitizer_common/sanitizer_malloc_mac.inc" - asan_introspection.enumerator = &mi_enumerator; - asan_introspection.good_size = &mi_good_size; - asan_introspection.check = &mi_check; - asan_introspection.print = &mi_print; - asan_introspection.log = &mi_log; - asan_introspection.force_lock = &mi_force_lock; - asan_introspection.force_unlock = &mi_force_unlock; - asan_introspection.statistics = &mi_statistics; - asan_introspection.zone_locked = &mi_zone_locked; - - internal_memset(&asan_zone, 0, sizeof(malloc_zone_t)); - - // Use version 6 for OSX >= 10.6. - asan_zone.version = 6; - asan_zone.zone_name = "asan"; - asan_zone.size = &__asan_mz_size; - asan_zone.malloc = &__asan_mz_malloc; - asan_zone.calloc = &__asan_mz_calloc; - asan_zone.valloc = &__asan_mz_valloc; - asan_zone.free = &__asan_mz_free; - asan_zone.realloc = &__asan_mz_realloc; - asan_zone.destroy = &__asan_mz_destroy; - asan_zone.batch_malloc = 0; - asan_zone.batch_free = 0; - asan_zone.free_definite_size = 0; - asan_zone.memalign = &__asan_mz_memalign; - asan_zone.introspect = &asan_introspection; - - // Register the ASan zone. - malloc_zone_register(&asan_zone); -} -} // namespace __asan - -#endif // SANITIZER_MAC +#endif diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index f9e1a527de18..8fe347c8bad0 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -17,7 +17,7 @@ #include "asan_internal.h" // The full explanation of the memory mapping could be found here: -// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm +// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm // // Typical shadow mapping on Linux/x86_64 with SHADOW_OFFSET == 0x00007fff8000: // || `[0x10007fff8000, 0x7fffffffffff]` || HighMem || @@ -73,6 +73,20 @@ // || `[0x2000000000, 0x23ffffffff]` || LowShadow || // || `[0x0000000000, 0x1fffffffff]` || LowMem || // +// Default Linux/AArch64 (39-bit VMA) mapping: +// || `[0x2000000000, 0x7fffffffff]` || highmem || +// || `[0x1400000000, 0x1fffffffff]` || highshadow || +// || `[0x1200000000, 0x13ffffffff]` || shadowgap || +// || `[0x1000000000, 0x11ffffffff]` || lowshadow || +// || `[0x0000000000, 0x0fffffffff]` || lowmem || +// +// Default Linux/AArch64 (42-bit VMA) mapping: +// || `[0x10000000000, 0x3ffffffffff]` || highmem || +// || `[0x0a000000000, 0x0ffffffffff]` || highshadow || +// || `[0x09000000000, 0x09fffffffff]` || shadowgap || +// || `[0x08000000000, 0x08fffffffff]` || lowshadow || +// || `[0x00000000000, 0x07fffffffff]` || lowmem || +// // Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000: // || `[0x500000000000, 0x7fffffffffff]` || HighMem || // || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow || @@ -113,11 +127,12 @@ static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 #define SHADOW_SCALE kDefaultShadowScale -#if SANITIZER_ANDROID -# define SHADOW_OFFSET (0) -#else -# if SANITIZER_WORDSIZE == 32 -# if defined(__mips__) + + +#if SANITIZER_WORDSIZE == 32 +# if SANITIZER_ANDROID +# define SHADOW_OFFSET (0) +# elif defined(__mips__) # define SHADOW_OFFSET kMIPS32_ShadowOffset32 # elif SANITIZER_FREEBSD # define SHADOW_OFFSET kFreeBSD_ShadowOffset32 @@ -130,7 +145,7 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # else # define SHADOW_OFFSET kDefaultShadowOffset32 # endif -# else +#else # if defined(__aarch64__) # define SHADOW_OFFSET kAArch64_ShadowOffset64 # elif defined(__powerpc64__) @@ -148,7 +163,6 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # else # define SHADOW_OFFSET kDefaultShort64bitShadowOffset # endif -# endif #endif #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE) @@ -171,7 +185,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 // With the zero shadow base we can not actually map pages starting from 0. // This constant is somewhat arbitrary. -#define kZeroBaseShadowStart (1 << 18) +#define kZeroBaseShadowStart 0 +#define kZeroBaseMaxShadowStart (1 << 18) #define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 \ : kZeroBaseShadowStart) diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc index e48bdaf03dd3..b5ba13ef4055 100644 --- a/lib/asan/asan_new_delete.cc +++ b/lib/asan/asan_new_delete.cc @@ -30,7 +30,7 @@ using namespace __asan; // NOLINT // This code has issues on OSX. -// See https://code.google.com/p/address-sanitizer/issues/detail?id=131. +// See https://github.com/google/sanitizers/issues/131. // Fake std::nothrow_t to avoid including <new>. namespace std { @@ -90,11 +90,11 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { #if !SANITIZER_MAC CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr) throw() { +void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr) throw() { +void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE @@ -106,12 +106,12 @@ 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() { +void operator delete(void *ptr, size_t size) NOEXCEPT { GET_STACK_TRACE_FREE; asan_sized_free(ptr, size, &stack, FROM_NEW); } CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr, size_t size) throw() { +void operator delete[](void *ptr, size_t size) NOEXCEPT { GET_STACK_TRACE_FREE; asan_sized_free(ptr, size, &stack, FROM_NEW_BR); } diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc index 569d359aa425..f77ab8780bb7 100644 --- a/lib/asan/asan_poisoning.cc +++ b/lib/asan/asan_poisoning.cc @@ -102,7 +102,7 @@ using namespace __asan; // NOLINT // that user program (un)poisons the memory it owns. It poisons memory // conservatively, and unpoisons progressively to make sure asan shadow // mapping invariant is preserved (see detailed mapping description here: -// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm). +// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm). // // * if user asks to poison region [left, right), the program poisons // at least [left, AlignDown(right)). @@ -354,7 +354,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p, // Make a quick sanity check that we are indeed in this state. // // FIXME: Two of these three checks are disabled until we fix - // https://code.google.com/p/address-sanitizer/issues/detail?id=258. + // https://github.com/google/sanitizers/issues/258. // if (d1 != d2) // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1); if (a + granularity <= d1) @@ -375,10 +375,10 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p, } } -int __sanitizer_verify_contiguous_container(const void *beg_p, - const void *mid_p, - const void *end_p) { - if (!flags()->detect_container_overflow) return 1; +const void *__sanitizer_contiguous_container_find_bad_address( + const void *beg_p, const void *mid_p, const void *end_p) { + if (!flags()->detect_container_overflow) + return nullptr; uptr beg = reinterpret_cast<uptr>(beg_p); uptr end = reinterpret_cast<uptr>(end_p); uptr mid = reinterpret_cast<uptr>(mid_p); @@ -395,17 +395,24 @@ int __sanitizer_verify_contiguous_container(const void *beg_p, uptr r3_end = end; for (uptr i = r1_beg; i < r1_end; i++) if (AddressIsPoisoned(i)) - return 0; + return reinterpret_cast<const void *>(i); for (uptr i = r2_beg; i < mid; i++) if (AddressIsPoisoned(i)) - return 0; + return reinterpret_cast<const void *>(i); for (uptr i = mid; i < r2_end; i++) if (!AddressIsPoisoned(i)) - return 0; + return reinterpret_cast<const void *>(i); for (uptr i = r3_beg; i < r3_end; i++) if (!AddressIsPoisoned(i)) - return 0; - return 1; + return reinterpret_cast<const void *>(i); + return nullptr; +} + +int __sanitizer_verify_contiguous_container(const void *beg_p, + const void *mid_p, + const void *end_p) { + return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p, + end_p) == nullptr; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index 2e857f6f624c..9e01bcd091bf 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -33,11 +33,11 @@ namespace __asan { -void AsanOnSIGSEGV(int, void *siginfo, void *context) { +void AsanOnDeadlySignal(int signo, 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(); + if (18 != internal_write(2, "ASAN:DEADLYSIGNAL\n", 18)) Die(); SignalContext sig = SignalContext::Create(siginfo, context); // Access at a reasonable offset above SP, or slightly below it (to account @@ -75,8 +75,12 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) { // unaligned memory access. if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) ReportStackOverflow(sig); + else if (signo == SIGFPE) + ReportDeadlySignal("FPE", sig); + else if (signo == SIGILL) + ReportDeadlySignal("ILL", sig); else - ReportSIGSEGV("SEGV", sig); + ReportDeadlySignal("SEGV", sig); } // ---------------------- TSD ---------------- {{{1 diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index c1681e644464..0fb60846c3b4 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -11,6 +11,7 @@ // // This file contains error reporting code. //===----------------------------------------------------------------------===// + #include "asan_flags.h" #include "asan_internal.h" #include "asan_mapping.h" @@ -27,9 +28,11 @@ namespace __asan { // -------------------- User-specified callbacks ----------------- {{{1 static void (*error_report_callback)(const char*); -static char *error_message_buffer = 0; +static char *error_message_buffer = nullptr; static uptr error_message_buffer_pos = 0; -static uptr error_message_buffer_size = 0; +static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED); +static const unsigned kAsanBuggyPcPoolSize = 25; +static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize]; struct ReportData { uptr pc; @@ -45,16 +48,20 @@ static bool report_happened = false; static ReportData report_data = {}; void AppendToErrorMessageBuffer(const char *buffer) { - if (error_message_buffer) { - uptr length = internal_strlen(buffer); - CHECK_GE(error_message_buffer_size, error_message_buffer_pos); - uptr remaining = error_message_buffer_size - error_message_buffer_pos; - internal_strncpy(error_message_buffer + error_message_buffer_pos, - buffer, remaining); - error_message_buffer[error_message_buffer_size - 1] = '\0'; - // FIXME: reallocate the buffer instead of truncating the message. - error_message_buffer_pos += Min(remaining, length); + BlockingMutexLock l(&error_message_buf_mutex); + if (!error_message_buffer) { + error_message_buffer = + (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__); + error_message_buffer_pos = 0; } + uptr length = internal_strlen(buffer); + RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos); + uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos; + internal_strncpy(error_message_buffer + error_message_buffer_pos, + buffer, remaining); + error_message_buffer[kErrorMessageBufferSize - 1] = '\0'; + // FIXME: reallocate the buffer instead of truncating the message. + error_message_buffer_pos += Min(remaining, length); } // ---------------------- Decorator ------------------------------ {{{1 @@ -373,7 +380,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, uptr next_var_beg) { uptr var_end = var.beg + var.size; uptr addr_end = addr + access_size; - const char *pos_descr = 0; + const char *pos_descr = nullptr; // 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) { @@ -544,7 +551,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { StackTrace alloc_stack = chunk.GetAllocStack(); char tname[128]; Decorator d; - AsanThreadContext *free_thread = 0; + AsanThreadContext *free_thread = nullptr; if (chunk.FreeTid() != kInvalidTid) { free_thread = GetThreadContextByTidLocked(chunk.FreeTid()); Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), @@ -621,26 +628,93 @@ void DescribeThread(AsanThreadContext *context) { // immediately after printing error report. class ScopedInErrorReport { public: - 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) { + explicit ScopedInErrorReport(ReportData *report = nullptr, + bool fatal = false) { + halt_on_error_ = fatal || flags()->halt_on_error; + + if (lock_.TryLock()) { + StartReporting(report); + return; + } + + // ASan found two bugs in different threads simultaneously. + + u32 current_tid = GetCurrentTidOrInvalid(); + if (reporting_thread_tid_ == current_tid || + reporting_thread_tid_ == kInvalidTid) { + // This is either asynch signal or nested error during error reporting. + // Fail simple to avoid deadlocks in Report(). + + // Can't use Report() here because of potential deadlocks + // in nested signal handlers. + const char msg[] = "AddressSanitizer: nested bug in the same thread, " + "aborting.\n"; + WriteToFile(kStderrFd, msg, sizeof(msg)); + + internal__exit(common_flags()->exitcode); + } + + if (halt_on_error_) { // 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. + // they are effectively no-returns. + Report("AddressSanitizer: while reporting a bug found another one. " - "Ignoring.\n"); - u32 current_tid = GetCurrentTidOrInvalid(); - if (current_tid != reporting_thread_tid) { - // ASan found two bugs in different threads simultaneously. Sleep - // long enough to make sure that the thread which started to print - // an error report will finish doing it. - SleepForSeconds(Max(100, flags()->sleep_before_dying + 1)); - } + "Ignoring.\n"); + + // Sleep long enough to make sure that the thread which started + // to print an error report will finish doing it. + SleepForSeconds(Max(100, flags()->sleep_before_dying + 1)); + // If we're still not dead for some reason, use raw _exit() instead of // Die() to bypass any additional checks. - internal__exit(flags()->exitcode); + internal__exit(common_flags()->exitcode); + } else { + // The other thread will eventually finish reporting + // so it's safe to wait + lock_.Lock(); + } + + StartReporting(report); + } + + ~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(); + + // Copy the message buffer so that we could start logging without holding a + // lock that gets aquired during printing. + InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize); + { + BlockingMutexLock l(&error_message_buf_mutex); + internal_memcpy(buffer_copy.data(), + error_message_buffer, kErrorMessageBufferSize); + } + + // Remove color sequences since logs cannot print them. + RemoveANSIEscapeSequencesFromString(buffer_copy.data()); + + LogFullErrorReport(buffer_copy.data()); + + if (error_report_callback) { + error_report_callback(buffer_copy.data()); } + CommonSanitizerReportMutex.Unlock(); + reporting_thread_tid_ = kInvalidTid; + lock_.Unlock(); + if (halt_on_error_) { + Report("ABORTING\n"); + Die(); + } + } + + private: + void StartReporting(ReportData *report) { if (report) report_data = *report; report_happened = true; ASAN_ON_ERROR(); @@ -650,27 +724,19 @@ class ScopedInErrorReport { // recursive reports. asanThreadRegistry().Lock(); CommonSanitizerReportMutex.Lock(); - reporting_thread_tid = GetCurrentTidOrInvalid(); + reporting_thread_tid_ = GetCurrentTidOrInvalid(); Printf("====================================================" "=============\n"); } - // Destructor is NORETURN, as functions that report errors are. - 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(); - if (error_report_callback) { - error_report_callback(error_message_buffer); - } - Report("ABORTING\n"); - Die(); - } + + static StaticSpinMutex lock_; + static u32 reporting_thread_tid_; + bool halt_on_error_; }; +StaticSpinMutex ScopedInErrorReport::lock_; +u32 ScopedInErrorReport::reporting_thread_tid_; + void ReportStackOverflow(const SignalContext &sig) { ScopedInErrorReport in_report; Decorator d; @@ -686,8 +752,8 @@ void ReportStackOverflow(const SignalContext &sig) { ReportErrorSummary("stack-overflow", &stack); } -void ReportSIGSEGV(const char *description, const SignalContext &sig) { - ScopedInErrorReport in_report; +void ReportDeadlySignal(const char *description, const SignalContext &sig) { + ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true); Decorator d; Printf("%s", d.Warning()); Report( @@ -703,7 +769,7 @@ void ReportSIGSEGV(const char *description, const SignalContext &sig) { stack.Print(); MaybeDumpInstructionBytes(sig.pc); Printf("AddressSanitizer can not provide additional info.\n"); - ReportErrorSummary("SEGV", &stack); + ReportErrorSummary(description, &stack); } void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { @@ -744,7 +810,7 @@ void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, stack.Print(); DescribeHeapAddress(addr, 1); ReportErrorSummary("new-delete-type-mismatch", &stack); - Report("HINT: if you don't care about these warnings you may set " + Report("HINT: if you don't care about these errors you may set " "ASAN_OPTIONS=new_delete_type_mismatch=0\n"); } @@ -784,7 +850,7 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, stack.Print(); DescribeHeapAddress(addr, 1); ReportErrorSummary("alloc-dealloc-mismatch", &stack); - Report("HINT: if you don't care about these warnings you may set " + Report("HINT: if you don't care about these errors you may set " "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); } @@ -886,7 +952,7 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1, Printf(" [2]:\n"); StackDepotGet(stack_id2).Print(); } - Report("HINT: if you don't care about these warnings you may set " + Report("HINT: if you don't care about these errors you may set " "ASAN_OPTIONS=detect_odr_violation=0\n"); InternalScopedString error_msg(256); error_msg.append("odr-violation: global '%s' at %s", @@ -925,17 +991,6 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { } // ----------------------- Mac-specific reports ----------------- {{{1 -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); - stack->Print(); - DescribeHeapAddress(addr, 1); -} - void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, BufferedStackTrace *stack) { ScopedInErrorReport in_report; @@ -947,24 +1002,23 @@ void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, DescribeHeapAddress(addr, 1); } -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); - stack->Print(); - DescribeHeapAddress(addr, 1); +// -------------- SuppressErrorReport -------------- {{{1 +// Avoid error reports duplicating for ASan recover mode. +static bool SuppressErrorReport(uptr pc) { + if (!common_flags()->suppress_equal_pcs) return false; + for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) { + uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]); + if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp, + pc, memory_order_relaxed)) + return false; + if (cmp == pc) return true; + } + Die(); } -} // namespace __asan - -// --------------------------- Interface --------------------- {{{1 -using namespace __asan; // NOLINT - -void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, - uptr access_size, u32 exp) { +void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, + uptr access_size, u32 exp, bool fatal) { + if (!fatal && SuppressErrorReport(pc)) return; ENABLE_FRAME_POINTER; // Optimization experiments. @@ -1033,7 +1087,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size, bug_descr }; - ScopedInErrorReport in_report(&report); + ScopedInErrorReport in_report(&report, fatal); Decorator d; Printf("%s", d.Warning()); @@ -1059,14 +1113,21 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, PrintShadowMemoryForAddress(addr); } +} // namespace __asan + +// --------------------------- Interface --------------------- {{{1 +using namespace __asan; // NOLINT + +void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, + uptr access_size, u32 exp) { + ENABLE_FRAME_POINTER; + bool fatal = flags()->halt_on_error; + ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal); +} + void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) { + BlockingMutexLock l(&error_message_buf_mutex); error_report_callback = callback; - if (callback) { - error_message_buffer_size = 1 << 16; - error_message_buffer = - (char*)MmapOrDie(error_message_buffer_size, __func__); - error_message_buffer_pos = 0; - } } void __asan_describe_address(uptr addr) { @@ -1117,7 +1178,7 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_ptr_cmp(void *a, void *b) { CheckForInvalidPointerPair(a, b); } -} // extern "C" +} // 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 e2786b0f260c..559b8adfd51d 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -49,44 +49,39 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size); void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. -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, 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 ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, + uptr access_size, u32 exp, bool fatal); +void ReportStackOverflow(const SignalContext &sig); +void ReportDeadlySignal(const char *description, const SignalContext &sig); +void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, + BufferedStackTrace *free_stack); +void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); +void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack); +void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, + AllocType alloc_type, + AllocType dealloc_type); +void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack); +void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, + BufferedStackTrace *stack); +void ReportStringFunctionMemoryRangesOverlap(const char *function, + const char *offset1, uptr length1, + const char *offset2, uptr length2, + BufferedStackTrace *stack); +void ReportStringFunctionSizeOverflow(uptr offset, uptr size, + BufferedStackTrace *stack); +void 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); +void 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, - 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); +void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, + const char *zone_name, + BufferedStackTrace *stack); +void 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 a8d92b915a9a..7b8b5dd9be1b 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" @@ -56,11 +57,6 @@ static void AsanDie() { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } - if (common_flags()->coverage) - __sanitizer_cov_dump(); - if (flags()->abort_on_error) - Abort(); - internal__exit(flags()->exitcode); } static void AsanCheckFailed(const char *file, int line, const char *cond, @@ -117,13 +113,18 @@ static void OnLowLevelAllocate(uptr ptr, uptr size) { extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_ ## type ## size(uptr addr) { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size, 0); \ + ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \ } \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size, exp); \ -} + ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \ +} \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_ ## type ## size ## _noabort(uptr addr) { \ + GET_CALLER_PC_BP_SP; \ + ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \ +} \ ASAN_REPORT_ERROR(load, false, 1) ASAN_REPORT_ERROR(load, false, 2) @@ -136,22 +137,27 @@ ASAN_REPORT_ERROR(store, true, 4) ASAN_REPORT_ERROR(store, true, 8) ASAN_REPORT_ERROR(store, true, 16) -#define ASAN_REPORT_ERROR_N(type, is_write) \ -extern "C" NOINLINE INTERFACE_ATTRIBUTE \ -void __asan_report_ ## type ## _n(uptr addr, uptr size) { \ - GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size, 0); \ -} \ -extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +#define ASAN_REPORT_ERROR_N(type, is_write) \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_ ## type ## _n(uptr addr, uptr size) { \ + GET_CALLER_PC_BP_SP; \ + ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \ +} \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size, exp); \ -} + ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \ +} \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_ ## type ## _n_noabort(uptr addr, uptr size) { \ + GET_CALLER_PC_BP_SP; \ + ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \ +} \ ASAN_REPORT_ERROR_N(load, false) ASAN_REPORT_ERROR_N(store, true) -#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg) \ +#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \ uptr sp = MEM_TO_SHADOW(addr); \ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \ : *reinterpret_cast<u16 *>(sp); \ @@ -163,7 +169,8 @@ ASAN_REPORT_ERROR_N(store, true) *__asan_test_only_reported_buggy_pointer = addr; \ } else { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size, exp_arg); \ + ReportGenericError(pc, bp, sp, addr, is_write, size, exp_arg, \ + fatal); \ } \ } \ } @@ -171,12 +178,16 @@ 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) { \ - ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0) \ + ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, true) \ } \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_exp_##type##size(uptr addr, u32 exp) { \ - ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp) \ - } + ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp, true) \ + } \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE \ + void __asan_##type##size ## _noabort(uptr addr) { \ + ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, false) \ + } \ ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2) @@ -194,7 +205,7 @@ 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, 0); + ReportGenericError(pc, bp, sp, addr, false, size, 0, true); } } @@ -203,7 +214,16 @@ NOINLINE INTERFACE_ATTRIBUTE void __asan_exp_loadN(uptr addr, uptr size, u32 exp) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; - __asan_report_error(pc, bp, sp, addr, false, size, exp); + ReportGenericError(pc, bp, sp, addr, false, size, exp, true); + } +} + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE +void __asan_loadN_noabort(uptr addr, uptr size) { + if (__asan_region_is_poisoned(addr, size)) { + GET_CALLER_PC_BP_SP; + ReportGenericError(pc, bp, sp, addr, false, size, 0, false); } } @@ -212,7 +232,7 @@ 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, 0); + ReportGenericError(pc, bp, sp, addr, true, size, 0, true); } } @@ -221,7 +241,16 @@ NOINLINE INTERFACE_ATTRIBUTE void __asan_exp_storeN(uptr addr, uptr size, u32 exp) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; - __asan_report_error(pc, bp, sp, addr, true, size, exp); + ReportGenericError(pc, bp, sp, addr, true, size, exp, true); + } +} + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE +void __asan_storeN_noabort(uptr addr, uptr size) { + if (__asan_region_is_poisoned(addr, size)) { + GET_CALLER_PC_BP_SP; + ReportGenericError(pc, bp, sp, addr, true, size, 0, false); } } @@ -259,16 +288,15 @@ static NOINLINE void force_interface_symbols() { case 22: __asan_report_exp_store8(0, 0); break; case 23: __asan_report_exp_store16(0, 0); break; case 24: __asan_report_exp_store_n(0, 0, 0); break; - case 25: __asan_register_globals(0, 0); break; - case 26: __asan_unregister_globals(0, 0); break; - case 27: __asan_set_death_callback(0); break; - case 28: __asan_set_error_report_callback(0); break; + case 25: __asan_register_globals(nullptr, 0); break; + case 26: __asan_unregister_globals(nullptr, 0); break; + case 27: __asan_set_death_callback(nullptr); break; + case 28: __asan_set_error_report_callback(nullptr); break; case 29: __asan_handle_no_return(); break; - case 30: __asan_address_is_poisoned(0); break; - case 31: __asan_poison_memory_region(0, 0); break; - case 32: __asan_unpoison_memory_region(0, 0); break; - case 33: __asan_set_error_exit_code(0); break; - case 34: __asan_before_dynamic_init(0); break; + case 30: __asan_address_is_poisoned(nullptr); break; + case 31: __asan_poison_memory_region(nullptr, 0); break; + case 32: __asan_unpoison_memory_region(nullptr, 0); break; + case 34: __asan_before_dynamic_init(nullptr); break; case 35: __asan_after_dynamic_init(); break; case 36: __asan_poison_stack_memory(0, 0); break; case 37: __asan_unpoison_stack_memory(0, 0); break; @@ -298,9 +326,25 @@ static void InitializeHighMemEnd() { } static void ProtectGap(uptr addr, uptr size) { + if (!flags()->protect_shadow_gap) + return; void *res = MmapNoAccess(addr, size, "shadow gap"); if (addr == (uptr)res) return; + // A few pages at the start of the address space can not be protected. + // But we really want to protect as much as possible, to prevent this memory + // being returned as a result of a non-FIXED mmap(). + if (addr == kZeroBaseShadowStart) { + uptr step = GetPageSizeCached(); + while (size > step && addr < kZeroBaseMaxShadowStart) { + addr += step; + size -= step; + void *res = MmapNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) + return; + } + } + Report("ERROR: Failed to protect the shadow gap. " "ASan cannot proceed correctly. ABORTING.\n"); DumpProcessMap(); @@ -363,12 +407,12 @@ static void AsanInitInternal() { CHECK(!asan_init_is_running && "ASan init calls itself!"); asan_init_is_running = true; + CacheBinaryName(); + // Initialize flags. This must be done early, because most of the // initialization steps look at flags(). InitializeFlags(); - CacheBinaryName(); - AsanCheckIncompatibleRT(); AsanCheckDynamicRTPrereqs(); @@ -381,7 +425,7 @@ static void AsanInitInternal() { AsanDoesNotSupportStaticLinkage(); // Install tool-specific callbacks in sanitizer_common. - SetDieCallback(AsanDie); + AddDieCallback(AsanDie); SetCheckFailedCallback(AsanCheckFailed); SetPrintfAndReportCallback(AppendToErrorMessageBuffer); @@ -457,7 +501,7 @@ static void AsanInitInternal() { } AsanTSDInit(PlatformTSDDtor); - InstallDeadlySignalHandlers(AsanOnSIGSEGV); + InstallDeadlySignalHandlers(AsanOnDeadlySignal); AllocatorOptions allocator_options; allocator_options.SetFrom(flags(), common_flags()); @@ -531,24 +575,26 @@ public: // NOLINT static AsanInitializer asan_initializer; #endif // ASAN_DYNAMIC -} // namespace __asan +} // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT -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); + uptr top, bottom; + if (curr_thread) { + top = curr_thread->stack_top(); + bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1); + } else { + // If we haven't seen this thread, try asking the OS for stack bounds. + uptr tls_addr, tls_size, stack_size; + GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr, + &tls_size); + top = bottom + stack_size; + } static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M if (top - bottom > kMaxExpectedCleanupSize) { static bool reported_warning = false; @@ -559,12 +605,12 @@ void NOINLINE __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", + "https://github.com/google/sanitizers/issues/189\n", top, bottom, top - bottom, top - bottom); return; } PoisonShadow(bottom, top - bottom, 0); - if (curr_thread->has_fake_stack()) + if (curr_thread && curr_thread->has_fake_stack()) curr_thread->fake_stack()->HandleNoReturn(); } @@ -578,3 +624,7 @@ void __asan_init() { AsanActivate(); AsanInitInternal(); } + +void __asan_version_mismatch_check() { + // Do nothing. +} diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h index 122967a152f8..5c5181509801 100644 --- a/lib/asan/asan_stack.h +++ b/lib/asan/asan_stack.h @@ -11,6 +11,7 @@ // // ASan-private header for asan_stack.cc. //===----------------------------------------------------------------------===// + #ifndef ASAN_STACK_H #define ASAN_STACK_H @@ -48,15 +49,15 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, 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) { + } else if (!t && !fast) { /* If GetCurrentThread() has failed, try to do slow unwind anyways. */ stack->Unwind(max_depth, pc, bp, context, 0, 0, false); } } -#endif // SANITIZER_WINDOWS +#endif // SANITIZER_WINDOWS } -} // namespace __asan +} // 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 @@ -115,4 +116,4 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, stack.Print(); \ } -#endif // ASAN_STACK_H +#endif // ASAN_STACK_H diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index 9af5706d86d0..69813546f551 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -42,7 +42,7 @@ void AsanThreadContext::OnCreated(void *arg) { void AsanThreadContext::OnFinished() { // Drop the link to the AsanThread object. - thread = 0; + thread = nullptr; } // MIPS requires aligned address @@ -125,7 +125,7 @@ void AsanThread::Destroy() { FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { uptr stack_size = this->stack_size(); if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. - return 0; + return nullptr; uptr old_val = 0; // fake_stack_ has 3 states: // 0 -- not initialized @@ -146,11 +146,11 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { SetTLSFakeStack(fake_stack_); return fake_stack_; } - return 0; + return nullptr; } void AsanThread::Init() { - fake_stack_ = 0; // Will be initialized lazily if needed. + fake_stack_ = nullptr; // Will be initialized lazily if needed. CHECK_EQ(this->stack_size(), 0U); SetThreadStackAndTls(); CHECK_GT(this->stack_size(), 0U); @@ -161,13 +161,12 @@ void AsanThread::Init() { 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, atomic_uintptr_t *signal_thread_is_registered) { Init(); - asanThreadRegistry().StartThread(tid(), os_id, 0); + asanThreadRegistry().StartThread(tid(), os_id, nullptr); if (signal_thread_is_registered) atomic_store(signal_thread_is_registered, 1, memory_order_release); @@ -277,7 +276,7 @@ AsanThread *GetCurrentThread() { return tctx->thread; } } - return 0; + return nullptr; } return context->thread; } @@ -302,7 +301,7 @@ AsanThread *FindThreadByStackAddress(uptr addr) { AsanThreadContext *tctx = static_cast<AsanThreadContext *>( asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress, (void *)addr)); - return tctx ? tctx->thread : 0; + return tctx ? tctx->thread : nullptr; } void EnsureMainThreadIDIsCorrect() { @@ -315,10 +314,10 @@ void EnsureMainThreadIDIsCorrect() { __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); - if (!context) return 0; + if (!context) return nullptr; return context->thread; } -} // namespace __asan +} // namespace __asan // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { @@ -355,4 +354,4 @@ void UnlockThreadRegistry() { void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); } -} // namespace __lsan +} // namespace __lsan diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h index 50acfc42d6a2..ac35711f5794 100644 --- a/lib/asan/asan_thread.h +++ b/lib/asan/asan_thread.h @@ -11,6 +11,7 @@ // // ASan-private header for asan_thread.cc. //===----------------------------------------------------------------------===// + #ifndef ASAN_THREAD_H #define ASAN_THREAD_H @@ -36,7 +37,7 @@ class AsanThreadContext : public ThreadContextBase { explicit AsanThreadContext(int tid) : ThreadContextBase(tid), announced(false), destructor_iterations(GetPthreadDestructorIterations()), stack_id(0), - thread(0) {} + thread(nullptr) {} bool announced; u8 destructor_iterations; u32 stack_id; @@ -84,8 +85,8 @@ class AsanThread { void DeleteFakeStack(int tid) { if (!fake_stack_) return; FakeStack *t = fake_stack_; - fake_stack_ = 0; - SetTLSFakeStack(0); + fake_stack_ = nullptr; + SetTLSFakeStack(nullptr); t->Destroy(tid); } @@ -95,7 +96,7 @@ class AsanThread { FakeStack *fake_stack() { if (!__asan_option_detect_stack_use_after_return) - return 0; + return nullptr; if (!has_fake_stack()) return AsyncSignalSafeLazyInitFakeStack(); return fake_stack_; @@ -179,6 +180,6 @@ AsanThread *FindThreadByStackAddress(uptr addr); // Used to handle fork(). void EnsureMainThreadIDIsCorrect(); -} // namespace __asan +} // namespace __asan -#endif // ASAN_THREAD_H +#endif // ASAN_THREAD_H diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index addb3d40a696..92bd893d10ef 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -14,9 +14,9 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_WINDOWS +#define WIN32_LEAN_AND_MEAN #include <windows.h> -#include <dbghelp.h> #include <stdlib.h> #include "asan_interceptors.h" @@ -175,14 +175,6 @@ void PlatformTSDDtor(void *tsd) { // }}} // ---------------------- Various stuff ---------------- {{{ -void DisableReexec() { - // No need to re-exec on Windows. -} - -void MaybeReexec() { - // No need to re-exec on Windows. -} - void *AsanDoesNotSupportStaticLinkage() { #if defined(_DEBUG) #error Please build the runtime with a non-debug CRT: /MD or /MT @@ -194,15 +186,11 @@ void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} -void AsanPlatformThreadInit() { - // Nothing here for now. -} - void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } -void AsanOnSIGSEGV(int, void *siginfo, void *context) { +void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); } @@ -219,7 +207,7 @@ static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { ? "access-violation" : "in-page-error"; SignalContext sig = SignalContext::Create(exception_record, context); - ReportSIGSEGV(description, sig); + ReportDeadlySignal(description, sig); } // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. @@ -257,7 +245,7 @@ int __asan_set_seh_filter() { // 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")) +__declspec(allocate(".CRT$XIZ")) int (*__intercept_seh)() = __asan_set_seh_filter; #endif // }}} diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc index b77f18168ae5..308196d307cc 100644 --- a/lib/asan/asan_win_dll_thunk.cc +++ b/lib/asan/asan_win_dll_thunk.cc @@ -12,8 +12,7 @@ // 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. +// See https://github.com/google/sanitizers/issues/209 for the details. //===----------------------------------------------------------------------===// // Only compile this code when buidling asan_dll_thunk.lib @@ -30,8 +29,9 @@ void *__stdcall GetProcAddress(void *module, const char *proc_name); void abort(); } -static void *getRealProcAddressOrDie(const char *name) { - void *ret = GetProcAddress(GetModuleHandleA(0), name); +static uptr getRealProcAddressOrDie(const char *name) { + uptr ret = + __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name); if (!ret) abort(); return ret; @@ -62,13 +62,12 @@ struct FunctionInterceptor<0> { }; #define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \ - template<> struct FunctionInterceptor<__LINE__> { \ + template <> struct FunctionInterceptor<__LINE__> { \ static void Execute() { \ - void *wrapper = getRealProcAddressOrDie(main_function); \ - if (!__interception::OverrideFunction((uptr)dll_function, \ - (uptr)wrapper, 0)) \ + uptr wrapper = getRealProcAddressOrDie(main_function); \ + if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \ abort(); \ - FunctionInterceptor<__LINE__-1>::Execute(); \ + FunctionInterceptor<__LINE__ - 1>::Execute(); \ } \ }; @@ -210,7 +209,7 @@ extern "C" { // __asan_init is expected to be called by only one thread. if (fn) return; - fn = (fntype)getRealProcAddressOrDie(__asan_init_name); + fn = (fntype)getRealProcAddressOrDie("__asan_init"); fn(); __asan_option_detect_stack_use_after_return = (__asan_should_detect_stack_use_after_return() != 0); @@ -219,6 +218,10 @@ extern "C" { } } +extern "C" void __asan_version_mismatch_check() { + // Do nothing. +} + INTERFACE_FUNCTION(__asan_handle_no_return) INTERFACE_FUNCTION(__asan_report_store1) @@ -253,6 +256,9 @@ INTERFACE_FUNCTION(__asan_memcpy); INTERFACE_FUNCTION(__asan_memset); INTERFACE_FUNCTION(__asan_memmove); +INTERFACE_FUNCTION(__asan_alloca_poison); +INTERFACE_FUNCTION(__asan_allocas_unpoison); + INTERFACE_FUNCTION(__asan_register_globals) INTERFACE_FUNCTION(__asan_unregister_globals) @@ -296,6 +302,7 @@ INTERFACE_FUNCTION(__asan_stack_free_10) // FIXME: we might want to have a sanitizer_win_dll_thunk? INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container) +INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address) INTERFACE_FUNCTION(__sanitizer_cov) INTERFACE_FUNCTION(__sanitizer_cov_dump) INTERFACE_FUNCTION(__sanitizer_cov_indir_call16) @@ -304,6 +311,7 @@ INTERFACE_FUNCTION(__sanitizer_cov_module_init) INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block) INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter) INTERFACE_FUNCTION(__sanitizer_cov_trace_cmp) +INTERFACE_FUNCTION(__sanitizer_cov_trace_switch) INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_get_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) @@ -312,6 +320,7 @@ INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_free_bytes) INTERFACE_FUNCTION(__sanitizer_get_heap_size) INTERFACE_FUNCTION(__sanitizer_get_ownership) +INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs) INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage) INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) diff --git a/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc index d59f9f5768a0..73e5207bb334 100644 --- a/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -24,6 +24,7 @@ // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK +#define WIN32_LEAN_AND_MEAN #include <windows.h> // First, declare CRT sections we'll be using in this file @@ -58,6 +59,7 @@ int __asan_option_detect_stack_use_after_return = // using atexit() that calls a small subset of C terminators // where LLVM global_dtors is placed. Fingers crossed, no other C terminators // are there. +extern "C" int __cdecl atexit(void (__cdecl *f)(void)); extern "C" void __cdecl _initterm(void *a, void *b); namespace { diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index 104e07b722ca..6cb7b94c2197 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -88,19 +88,25 @@ function adb_pull { fi } -function get_device_arch { # OUTVAR +function get_device_arch { # OUT OUT64 local _outvar=$1 + local _outvar64=$2 local _ABI=$(adb_shell getprop ro.product.cpu.abi) local _ARCH= + local _ARCH64= if [[ $_ABI == x86* ]]; then _ARCH=i686 elif [[ $_ABI == armeabi* ]]; then _ARCH=arm + elif [[ $_ABI == arm64-v8a* ]]; then + _ARCH=arm + _ARCH64=aarch64 else echo "Unrecognized device ABI: $_ABI" exit 1 fi eval $_outvar=\$_ARCH + eval $_outvar64=\$_ARCH64 } while [[ $# > 0 ]]; do @@ -167,22 +173,33 @@ adb_wait_for_device adb_remount adb_wait_for_device -get_device_arch ARCH +get_device_arch ARCH ARCH64 echo "Target architecture: $ARCH" ASAN_RT="libclang_rt.asan-$ARCH-android.so" +if [[ -n $ARCH64 ]]; then + echo "Target architecture: $ARCH64" + ASAN_RT64="libclang_rt.asan-$ARCH64-android.so" +fi if [[ x$revert == xyes ]]; then echo '>> Uninstalling ASan' if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*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 + echo '>> Pre-L device detected.' + adb_shell mv /system/bin/app_process.real /system/bin/app_process + adb_shell rm /system/bin/asanwrapper + elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then + # 64-bit installation. + adb_shell mv /system/bin/app_process32.real /system/bin/app_process32 + adb_shell mv /system/bin/app_process64.real /system/bin/app_process64 + adb_shell rm /system/bin/asanwrapper + adb_shell rm /system/bin/asanwrapper64 else - adb_shell rm /system/bin/app_process.wrap - adb_shell rm /system/bin/asanwrapper - adb_shell rm /system/bin/app_process - adb_shell ln -s /system/bin/app_process32 /system/bin/app_process + # 32-bit installation. + adb_shell rm /system/bin/app_process.wrap + adb_shell rm /system/bin/asanwrapper + adb_shell rm /system/bin/app_process + adb_shell ln -s /system/bin/app_process32 /system/bin/app_process fi echo '>> Restarting shell' @@ -205,8 +222,13 @@ 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) + # Consider ../lib, ../lib/asan, ../lib/linux, + # ../lib/clang/$VERSION/lib/linux, and ../lib64/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" \ + "$HERE"/../lib64/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1) if [[ -n "$P" ]]; then ASAN_RT_PATH="$(dirname "$P")" fi @@ -217,6 +239,13 @@ if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then exit 1 fi +if [[ -n "$ASAN_RT64" ]]; then + if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then + echo ">> ASan runtime library not found" + exit 1 + fi +fi + TMPDIRBASE=$(mktemp -d) TMPDIROLD="$TMPDIRBASE/old" TMPDIR="$TMPDIRBASE/new" @@ -241,12 +270,24 @@ if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev 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 +if [[ -n "$ASAN_RT64" ]]; then + adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true + adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true + adb_pull /system/bin/app_process32 "$TMPDIROLD" || true + adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true + adb_pull /system/bin/app_process64 "$TMPDIROLD" || true + adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true + adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true + adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true +else + adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true + adb_pull /system/bin/app_process32 "$TMPDIROLD" || true + adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true + adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true +fi cp -r "$TMPDIROLD" "$TMPDIR" -if [[ -f "$TMPDIR/app_process.wrap" ]]; then +if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then echo ">> Previous installation detected" else echo ">> New installation" @@ -255,10 +296,27 @@ fi echo '>> Generating wrappers' cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/" +if [[ -n "$ASAN_RT64" ]]; then + cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/" +fi # 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 +ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0,malloc_context_size=0 + +function generate_zygote_wrapper { # from, to, asan_rt + local _from=$1 + local _to=$2 + local _asan_rt=$3 + cat <<EOF >"$TMPDIR/$_from" +#!/system/bin/sh-from-zygote +ASAN_OPTIONS=$ASAN_OPTIONS \\ +ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\ +LD_PRELOAD=\$LD_PRELOAD:$_asan_rt \\ +exec $_to \$@ + +EOF +} # On Android-L not allowing user segv handler breaks some applications. if [[ PRE_L -eq 0 ]]; then @@ -270,13 +328,19 @@ if [[ x$extra_options != x ]] ; then 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 +if [[ -f "$TMPDIR/app_process64" ]]; then + # A 64-bit device. + if [[ ! -f "$TMPDIR/app_process64.real" ]]; then + # New installation. + mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real" + mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real" + fi + generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real" "$ASAN_RT" + generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real" "$ASAN_RT64" +else + # A 32-bit device. + generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32" "$ASAN_RT" +fi # General command-line tool wrapper (use for anything that's not started as # zygote). @@ -287,25 +351,33 @@ 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 - adb_push "$TMPDIR/asanwrapper" /system/bin - - 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 +if [[ -n "$ASAN_RT64" ]]; then + cat <<EOF >"$TMPDIR/asanwrapper64" +#!/system/bin/sh +LD_PRELOAD=$ASAN_RT64 \\ +exec \$@ + +EOF +fi + +function install { # from, to, chmod, chcon + local _from=$1 + local _to=$2 + local _mode=$3 + local _context=$4 + local _basename="$(basename "$_from")" + echo "Installing $_to/$_basename $_mode $_context" + adb_push "$_from" "$_to/$_basename" + adb_shell chown root.shell "$_to/$_basename" + if [[ -n "$_mode" ]]; then + adb_shell chmod "$_mode" "$_to/$_basename" + fi + if [[ -n "$_context" ]]; then + adb_shell chcon "$_context" "$_to/$_basename" + fi +} +if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then # Make SELinux happy by keeping app_process wrapper and the shell # it runs on in zygote domain. ENFORCING=0 @@ -316,17 +388,35 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then 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 + + echo '>> Pushing files to the device' + + if [[ -n "$ASAN_RT64" ]]; then + install "$TMPDIR/$ASAN_RT" /system/lib 644 + install "$TMPDIR/$ASAN_RT64" /system/lib64 644 + install "$TMPDIR/app_process32" /system/bin 755 $CTX + install "$TMPDIR/app_process32.real" /system/bin 755 $CTX + install "$TMPDIR/app_process64" /system/bin 755 $CTX + install "$TMPDIR/app_process64.real" /system/bin 755 $CTX + install "$TMPDIR/asanwrapper" /system/bin 755 + install "$TMPDIR/asanwrapper64" /system/bin 755 + else + install "$TMPDIR/$ASAN_RT" /system/lib 644 + install "$TMPDIR/app_process32" /system/bin 755 $CTX + install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX + install "$TMPDIR/asanwrapper" /system/bin 755 $CTX + + adb_shell rm /system/bin/app_process + adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process + fi + + adb_shell cp /system/bin/sh /system/bin/sh-from-zygote + adb_shell chcon $CTX /system/bin/sh-from-zygote if [ $ENFORCING == 1 ]; then adb_shell setenforce 1 diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py index b9d3ad3ad2fe..8e6fb61f7bf7 100755 --- a/lib/asan/scripts/asan_symbolize.py +++ b/lib/asan/scripts/asan_symbolize.py @@ -77,7 +77,7 @@ class LLVMSymbolizer(Symbolizer): cmd = [self.symbolizer_path, '--use-symbol-table=true', '--demangle=%s' % demangle, - '--functions=short', + '--functions=linkage', '--inlining=true', '--default-arch=%s' % self.default_arch] if self.system == 'Darwin': @@ -135,12 +135,13 @@ class Addr2LineSymbolizer(Symbolizer): super(Addr2LineSymbolizer, self).__init__() self.binary = binary self.pipe = self.open_addr2line() + self.output_terminator = -1 def open_addr2line(self): addr2line_tool = 'addr2line' if binutils_prefix: addr2line_tool = binutils_prefix + addr2line_tool - cmd = [addr2line_tool, '-f'] + cmd = [addr2line_tool, '-fi'] if demangle: cmd += ['--demangle'] cmd += ['-e', self.binary] @@ -153,16 +154,23 @@ class Addr2LineSymbolizer(Symbolizer): """Overrides Symbolizer.symbolize.""" if self.binary != binary: return None + lines = [] try: print >> self.pipe.stdin, offset - function_name = self.pipe.stdout.readline().rstrip() - file_name = self.pipe.stdout.readline().rstrip() + print >> self.pipe.stdin, self.output_terminator + is_first_frame = True + while True: + function_name = self.pipe.stdout.readline().rstrip() + file_name = self.pipe.stdout.readline().rstrip() + if is_first_frame: + is_first_frame = False + elif function_name in ['', '??']: + assert file_name == function_name + break + lines.append((function_name, file_name)); except Exception: - function_name = '' - file_name = '' - file_name = fix_filename(file_name) - return ['%s in %s %s' % (addr, function_name, file_name)] - + lines.append(('??', '??:0')) + return ['%s in %s %s' % (addr, function, fix_filename(file)) for (function, file) in lines] class UnbufferedLineConverter(object): """ @@ -263,7 +271,7 @@ def BreakpadSymbolizerFactory(binary): def SystemSymbolizerFactory(system, addr, binary): if system == 'Darwin': return DarwinSymbolizer(addr, binary) - elif system == 'Linux': + elif system == 'Linux' or system == 'FreeBSD': return Addr2LineSymbolizer(binary) diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index afdd2adf0887..7a8d8f7f106b 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -106,7 +106,7 @@ append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread # TODO(eugenis): move all -l flags above to _LIBS? set(ASAN_UNITTEST_NOINST_LIBS) -append_list_if(ANDROID log ASAN_UNITTEST_NOINST_LIBS) +append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_UNITTEST_NOINST_LIBS) # NDK r10 requires -latomic almost always. append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS) @@ -217,9 +217,10 @@ macro(add_asan_tests_for_arch_and_kind arch kind) set(ASAN_TEST_RUNTIME RTAsanTest.${arch}${kind}) if(APPLE) set(ASAN_TEST_RUNTIME_OBJECTS - $<TARGET_OBJECTS:RTAsan.osx> + $<TARGET_OBJECTS:RTAsan_dynamic.osx> $<TARGET_OBJECTS:RTInterception.osx> $<TARGET_OBJECTS:RTSanitizerCommon.osx> + $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx> $<TARGET_OBJECTS:RTLSanCommon.osx> $<TARGET_OBJECTS:RTUbsan.osx>) else() @@ -261,7 +262,11 @@ macro(add_asan_tests_for_arch_and_kind arch kind) endmacro() if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) - foreach(arch ${ASAN_SUPPORTED_ARCH}) + set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH}) + if(APPLE) + darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH) + endif() + foreach(arch ${ASAN_TEST_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) diff --git a/lib/asan/tests/asan_asm_test.cc b/lib/asan/tests/asan_asm_test.cc index 200de2c137a5..09af5c386079 100644 --- a/lib/asan/tests/asan_asm_test.cc +++ b/lib/asan/tests/asan_asm_test.cc @@ -14,7 +14,10 @@ #if defined(__linux__) -#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__)) +// Assembly instrumentation is broken on x86 Android (x86 + PIC + shared runtime +// library). See https://github.com/google/sanitizers/issues/353 +#if defined(__x86_64__) || \ + (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__)) #include <emmintrin.h> @@ -70,7 +73,7 @@ DECLARE_ASM_REP_MOVS(U8, "movsq"); #endif // defined(__x86_64__) -#if defined(__i386__) && defined(__SSE2__) +#if defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__) namespace { @@ -108,7 +111,8 @@ template<> Type asm_read<Type>(Type *ptr) { \ #endif // defined(__i386__) && defined(__SSE2__) -#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__)) +#if defined(__x86_64__) || \ + (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__)) namespace { diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc index a34c8528eae0..f5bfb8046b0a 100644 --- a/lib/asan/tests/asan_interface_test.cc +++ b/lib/asan/tests/asan_interface_test.cc @@ -140,16 +140,6 @@ static void DoDoubleFree() { delete Ident(x); } -TEST(AddressSanitizerInterface, ExitCode) { - int original_exit_code = __asan_set_error_exit_code(7); - EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), ""); - EXPECT_EQ(7, __asan_set_error_exit_code(8)); - EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), ""); - EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code)); - EXPECT_EXIT(DoDoubleFree(), - ::testing::ExitedWithCode(original_exit_code), ""); -} - static void MyDeathCallback() { fprintf(stderr, "MyDeathCallback\n"); fflush(0); // On Windows, stderr doesn't flush on crash. diff --git a/lib/asan/tests/asan_mac_test.cc b/lib/asan/tests/asan_mac_test.cc index cabdfd711ea2..dfa6d7596d74 100644 --- a/lib/asan/tests/asan_mac_test.cc +++ b/lib/asan/tests/asan_mac_test.cc @@ -216,12 +216,12 @@ TEST(AddressSanitizerMac, NSObjectOOB) { // Make sure that correct pointer is passed to free() when deallocating a // NSURL object. -// See http://code.google.com/p/address-sanitizer/issues/detail?id=70. +// See https://github.com/google/sanitizers/issues/70. TEST(AddressSanitizerMac, NSURLDeallocation) { TestNSURLDeallocation(); } -// See http://code.google.com/p/address-sanitizer/issues/detail?id=109. +// See https://github.com/google/sanitizers/issues/109. TEST(AddressSanitizerMac, Mstats) { malloc_statistics_t stats1, stats2; malloc_zone_statistics(/*all zones*/NULL, &stats1); diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc index 6a428fbbc2b9..5f5354f92caf 100644 --- a/lib/asan/tests/asan_noinst_test.cc +++ b/lib/asan/tests/asan_noinst_test.cc @@ -34,7 +34,7 @@ // Make sure __asan_init is called before any test case is run. struct AsanInitCaller { AsanInitCaller() { - __asan::DisableReexec(); + DisableReexec(); __asan_init(); } }; diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 07d59e09a72f..71fb27a0ca11 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -250,12 +250,12 @@ TEST(AddressSanitizer, BitFieldNegativeTest) { #if ASAN_NEEDS_SEGV namespace { -const char kUnknownCrash[] = "AddressSanitizer: SEGV on unknown address"; +const char kSEGVCrash[] = "AddressSanitizer: SEGV on unknown address"; const char kOverriddenHandler[] = "ASan signal handler has been overridden\n"; TEST(AddressSanitizer, WildAddressTest) { char *c = (char*)0x123; - EXPECT_DEATH(*c = 0, kUnknownCrash); + EXPECT_DEATH(*c = 0, kSEGVCrash); } void my_sigaction_sighandler(int, siginfo_t*, void*) { @@ -279,10 +279,10 @@ TEST(AddressSanitizer, SignalTest) { EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0)); #endif char *c = (char*)0x123; - EXPECT_DEATH(*c = 0, kUnknownCrash); + EXPECT_DEATH(*c = 0, kSEGVCrash); // ... and signal(). EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler)); - EXPECT_DEATH(*c = 0, kUnknownCrash); + EXPECT_DEATH(*c = 0, kSEGVCrash); } } // namespace #endif @@ -335,6 +335,8 @@ void *ManyThreadsWorker(void *a) { return 0; } +#if !defined(__aarch64__) +// FIXME: Infinite loop in AArch64 (PR24389). TEST(AddressSanitizer, ManyThreadsTest) { const size_t kNumThreads = (SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000; @@ -346,6 +348,7 @@ TEST(AddressSanitizer, ManyThreadsTest) { PTHREAD_JOIN(t[i], 0); } } +#endif TEST(AddressSanitizer, ReallocTest) { const int kMinElem = 5; @@ -607,7 +610,7 @@ NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) { } // Does not work on Power and ARM: -// https://code.google.com/p/address-sanitizer/issues/detail?id=185 +// https://github.com/google/sanitizers/issues/185 TEST(AddressSanitizer, BuiltinLongJmpTest) { static jmp_buf buf; if (!__builtin_setjmp((void**)buf)) { @@ -1153,9 +1156,9 @@ TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) { // 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 +// https://github.com/google/sanitizers/issues/131 // Windows support is tracked here: -// https://code.google.com/p/address-sanitizer/issues/detail?id=309 +// https://github.com/google/sanitizers/issues/309 #if !defined(__ANDROID__) && \ !defined(__APPLE__) && \ !defined(_WIN32) @@ -1252,7 +1255,7 @@ TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) { } } -// http://code.google.com/p/address-sanitizer/issues/detail?id=66 +// https://github.com/google/sanitizers/issues/66 TEST(AddressSanitizer, BufferOverflowAfterManyFrees) { for (int i = 0; i < 1000000; i++) { delete [] (Ident(new char [8644])); diff --git a/lib/asan/tests/asan_test_main.cc b/lib/asan/tests/asan_test_main.cc index 1746c5f4837b..cdaf801d914b 100644 --- a/lib/asan/tests/asan_test_main.cc +++ b/lib/asan/tests/asan_test_main.cc @@ -11,6 +11,20 @@ // //===----------------------------------------------------------------------===// #include "asan_test_utils.h" +#include "sanitizer_common/sanitizer_platform.h" + +// Default ASAN_OPTIONS for the unit tests. Let's turn symbolication off to +// speed up testing (unit tests don't use it anyway). +extern "C" const char* __asan_default_options() { +#if SANITIZER_MAC + // On Darwin, we default to `abort_on_error=1`, which would make tests run + // much slower. Let's override this and run lit tests with 'abort_on_error=0'. + // Also, make sure we do not overwhelm the syslog while testing. + return "symbolize=false:abort_on_error=0:log_to_syslog=0"; +#else + return "symbolize=false"; +#endif +} int main(int argc, char **argv) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; |