diff options
Diffstat (limited to 'libsanitizer/asan/asan_rtl.cc')
-rw-r--r-- | libsanitizer/asan/asan_rtl.cc | 475 |
1 files changed, 337 insertions, 138 deletions
diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc index 537d40612a..2c599047da 100644 --- a/libsanitizer/asan/asan_rtl.cc +++ b/libsanitizer/asan/asan_rtl.cc @@ -9,6 +9,7 @@ // // Main file of the ASan run-time library. //===----------------------------------------------------------------------===// +#include "asan_activation.h" #include "asan_allocator.h" #include "asan_interceptors.h" #include "asan_interface_internal.h" @@ -26,6 +27,7 @@ #include "lsan/lsan_common.h" int __asan_option_detect_stack_use_after_return; // Global interface symbol. +uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan. namespace __asan { @@ -49,7 +51,7 @@ static void AsanDie() { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } - if (flags()->coverage) + if (common_flags()->coverage) __sanitizer_cov_dump(); if (death_callback) death_callback(); @@ -60,10 +62,10 @@ static void AsanDie() { static void AsanCheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) { - Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", - file, line, cond, (uptr)v1, (uptr)v2); + Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file, + line, cond, (uptr)v1, (uptr)v2); // FIXME: check for infinite recursion without a thread-local counter here. - PRINT_CURRENT_STACK(); + PRINT_CURRENT_STACK_CHECK(); Die(); } @@ -76,7 +78,7 @@ static const char *MaybeCallAsanDefaultOptions() { return (&__asan_default_options) ? __asan_default_options() : ""; } -static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() { +static const char *MaybeUseAsanDefaultOptionsCompileDefinition() { #ifdef ASAN_DEFAULT_OPTIONS // Stringize the macro value. # define ASAN_STRINGIZE(x) #x @@ -91,56 +93,159 @@ static void ParseFlagsFromString(Flags *f, const char *str) { CommonFlags *cf = common_flags(); ParseCommonFlagsFromString(cf, str); CHECK((uptr)cf->malloc_context_size <= kStackTraceMax); - - ParseFlag(str, &f->quarantine_size, "quarantine_size"); - ParseFlag(str, &f->redzone, "redzone"); + // Please write meaningful flag descriptions when adding new flags. + ParseFlag(str, &f->quarantine_size, "quarantine_size", + "Size (in bytes) of quarantine used to detect use-after-free " + "errors. Lower value may reduce memory usage but increase the " + "chance of false negatives."); + ParseFlag(str, &f->redzone, "redzone", + "Minimal size (in bytes) of redzones around heap objects. " + "Requirement: redzone >= 16, is a power of two."); + ParseFlag(str, &f->max_redzone, "max_redzone", + "Maximal size (in bytes) of redzones around heap objects."); CHECK_GE(f->redzone, 16); + CHECK_GE(f->max_redzone, f->redzone); + CHECK_LE(f->max_redzone, 2048); CHECK(IsPowerOfTwo(f->redzone)); - - ParseFlag(str, &f->debug, "debug"); - ParseFlag(str, &f->report_globals, "report_globals"); - ParseFlag(str, &f->check_initialization_order, "check_initialization_order"); - - ParseFlag(str, &f->replace_str, "replace_str"); - ParseFlag(str, &f->replace_intrin, "replace_intrin"); - ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free"); + CHECK(IsPowerOfTwo(f->max_redzone)); + + ParseFlag(str, &f->debug, "debug", + "If set, prints some debugging information and does additional checks."); + ParseFlag(str, &f->report_globals, "report_globals", + "Controls the way to handle globals (0 - don't detect buffer overflow on " + "globals, 1 - detect buffer overflow, 2 - print data about registered " + "globals)."); + + ParseFlag(str, &f->check_initialization_order, + "check_initialization_order", + "If set, attempts to catch initialization order issues."); + + ParseFlag(str, &f->replace_str, "replace_str", + "If set, uses custom wrappers and replacements for libc string functions " + "to find more errors."); + + ParseFlag(str, &f->replace_intrin, "replace_intrin", + "If set, uses custom wrappers for memset/memcpy/memmove intinsics."); + ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free", + "Ignore invalid free() calls to work around some bugs. Used on OS X " + "only."); ParseFlag(str, &f->detect_stack_use_after_return, - "detect_stack_use_after_return"); - ParseFlag(str, &f->uar_stack_size_log, "uar_stack_size_log"); - ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size"); - ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte"); - ParseFlag(str, &f->exitcode, "exitcode"); - ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning"); - ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying"); - ParseFlag(str, &f->handle_segv, "handle_segv"); - ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler"); - ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack"); - ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size"); - ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit"); - ParseFlag(str, &f->abort_on_error, "abort_on_error"); - ParseFlag(str, &f->print_stats, "print_stats"); - ParseFlag(str, &f->print_legend, "print_legend"); - ParseFlag(str, &f->atexit, "atexit"); - ParseFlag(str, &f->coverage, "coverage"); - ParseFlag(str, &f->disable_core, "disable_core"); - ParseFlag(str, &f->allow_reexec, "allow_reexec"); - ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history"); - ParseFlag(str, &f->poison_heap, "poison_heap"); - ParseFlag(str, &f->poison_partial, "poison_partial"); - ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch"); - ParseFlag(str, &f->strict_memcmp, "strict_memcmp"); - ParseFlag(str, &f->strict_init_order, "strict_init_order"); + "detect_stack_use_after_return", + "Enables stack-use-after-return checking at run-time."); + ParseFlag(str, &f->min_uar_stack_size_log, "min_uar_stack_size_log", + "Minimum fake stack size log."); + ParseFlag(str, &f->max_uar_stack_size_log, "max_uar_stack_size_log", + "Maximum fake stack size log."); + ParseFlag(str, &f->uar_noreserve, "uar_noreserve", + "Use mmap with 'norserve' flag to allocate fake stack."); + ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size", + "ASan allocator flag. max_malloc_fill_size is the maximal amount of " + "bytes that will be filled with malloc_fill_byte on malloc."); + ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte", + "Value used to fill the newly allocated memory."); + ParseFlag(str, &f->exitcode, "exitcode", + "Override the program exit status if the tool found an error."); + ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning", + "If set, user may manually mark memory regions as poisoned or " + "unpoisoned."); + ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying", + "Number of seconds to sleep between printing an error report and " + "terminating the program. Useful for debugging purposes (e.g. when one " + "needs to attach gdb)."); + + ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size", + "Allows the users to work around the bug in Nvidia drivers prior to " + "295.*."); + + ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit", + "If set, explicitly unmaps the (huge) shadow at exit."); + ParseFlag(str, &f->abort_on_error, "abort_on_error", + "If set, the tool calls abort() instead of _exit() after printing the " + "error report."); + ParseFlag(str, &f->print_stats, "print_stats", + "Print various statistics after printing an error message or if " + "atexit=1."); + ParseFlag(str, &f->print_legend, "print_legend", + "Print the legend for the shadow bytes."); + ParseFlag(str, &f->atexit, "atexit", + "If set, prints ASan exit stats even after program terminates " + "successfully."); + + ParseFlag(str, &f->allow_reexec, "allow_reexec", + "Allow the tool to re-exec the program. This may interfere badly with " + "the debugger."); + + ParseFlag(str, &f->print_full_thread_history, + "print_full_thread_history", + "If set, prints thread creation stacks for the threads involved in the " + "report and their ancestors up to the main thread."); + + ParseFlag(str, &f->poison_heap, "poison_heap", + "Poison (or not) the heap memory on [de]allocation. Zero value is useful " + "for benchmarking the allocator or instrumentator."); + + ParseFlag(str, &f->poison_array_cookie, "poison_array_cookie", + "Poison (or not) the array cookie after operator new[]."); + + ParseFlag(str, &f->poison_partial, "poison_partial", + "If true, poison partially addressable 8-byte aligned words " + "(default=true). This flag affects heap and global buffers, but not " + "stack buffers."); + + ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch", + "Report errors on malloc/delete, new/free, new/delete[], etc."); + + ParseFlag(str, &f->new_delete_type_mismatch, "new_delete_type_mismatch", + "Report errors on mismatch betwen size of new and delete."); + + ParseFlag(str, &f->strict_memcmp, "strict_memcmp", + "If true, assume that memcmp(p1, p2, n) always reads n bytes before " + "comparing p1 and p2."); + + ParseFlag(str, &f->strict_init_order, "strict_init_order", + "If true, assume that dynamic initializers can never access globals from " + "other modules, even if the latter are already initialized."); + + ParseFlag(str, &f->start_deactivated, "start_deactivated", + "If true, ASan tweaks a bunch of other flags (quarantine, redzone, heap " + "poisoning) to reduce memory consumption as much as possible, and " + "restores them to original values when the first instrumented module is " + "loaded into the process. This is mainly intended to be used on " + "Android. "); + + ParseFlag(str, &f->detect_invalid_pointer_pairs, + "detect_invalid_pointer_pairs", + "If non-zero, try to detect operations like <, <=, >, >= and - on " + "invalid pointer pairs (e.g. when pointers belong to different objects). " + "The bigger the value the harder we try."); + + ParseFlag(str, &f->detect_container_overflow, + "detect_container_overflow", + "If true, honor the container overflow annotations. " + "See https://code.google.com/p/address-sanitizer/wiki/ContainerOverflow"); + + ParseFlag(str, &f->detect_odr_violation, "detect_odr_violation", + "If >=2, detect violation of One-Definition-Rule (ODR); " + "If ==1, detect ODR-violation only if the two variables " + "have different sizes"); + + ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes", + "If true, dump 16 bytes starting at the instruction that caused SEGV"); } void InitializeFlags(Flags *f, const char *env) { CommonFlags *cf = common_flags(); SetCommonFlagsDefaults(cf); + cf->detect_leaks = CAN_SANITIZE_LEAKS; cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); cf->malloc_context_size = kDefaultMallocContextSize; + cf->intercept_tls_get_addr = true; + cf->coverage = false; internal_memset(f, 0, sizeof(*f)); f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28; f->redzone = 16; + f->max_redzone = 2048; f->debug = false; f->report_globals = 1; f->check_initialization_order = false; @@ -148,53 +253,58 @@ void InitializeFlags(Flags *f, const char *env) { f->replace_intrin = true; f->mac_ignore_invalid_free = false; f->detect_stack_use_after_return = false; // Also needs the compiler flag. - f->uar_stack_size_log = 0; + f->min_uar_stack_size_log = 16; // We can't do smaller anyway. + f->max_uar_stack_size_log = 20; // 1Mb per size class, i.e. ~11Mb per thread. + f->uar_noreserve = false; f->max_malloc_fill_size = 0x1000; // By default, fill only the first 4K. f->malloc_fill_byte = 0xbe; f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE; f->allow_user_poisoning = true; f->sleep_before_dying = 0; - f->handle_segv = ASAN_NEEDS_SEGV; - f->allow_user_segv_handler = false; - f->use_sigaltstack = false; f->check_malloc_usable_size = true; f->unmap_shadow_on_exit = false; f->abort_on_error = false; f->print_stats = false; f->print_legend = true; f->atexit = false; - f->coverage = false; - f->disable_core = (SANITIZER_WORDSIZE == 64); f->allow_reexec = true; f->print_full_thread_history = true; f->poison_heap = true; + f->poison_array_cookie = true; f->poison_partial = true; // Turn off alloc/dealloc mismatch checker on Mac and Windows for now. + // https://code.google.com/p/address-sanitizer/issues/detail?id=131 + // https://code.google.com/p/address-sanitizer/issues/detail?id=309 // TODO(glider,timurrrr): Fix known issues and enable this back. f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0); + f->new_delete_type_mismatch = true; f->strict_memcmp = true; f->strict_init_order = false; + f->start_deactivated = false; + f->detect_invalid_pointer_pairs = 0; + f->detect_container_overflow = true; + f->detect_odr_violation = 2; + f->dump_instruction_bytes = false; // Override from compile definition. - ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton()); + ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition()); // Override from user-specified string. ParseFlagsFromString(f, MaybeCallAsanDefaultOptions()); - if (cf->verbosity) { - Report("Using the defaults from __asan_default_options: %s\n", - MaybeCallAsanDefaultOptions()); - } + VReport(1, "Using the defaults from __asan_default_options: %s\n", + MaybeCallAsanDefaultOptions()); // Override from command line. ParseFlagsFromString(f, env); + if (common_flags()->help) { + PrintFlagDescriptions(); + } -#if !CAN_SANITIZE_LEAKS - if (cf->detect_leaks) { + if (!CAN_SANITIZE_LEAKS && cf->detect_leaks) { Report("%s: detect_leaks is not supported on this platform.\n", SanitizerToolName); cf->detect_leaks = false; } -#endif // Make "strict_init_order" imply "check_initialization_order". // TODO(samsonov): Use a single runtime flag for an init-order checker. @@ -203,6 +313,17 @@ void InitializeFlags(Flags *f, const char *env) { } } +// Parse flags that may change between startup and activation. +// On Android they come from a system property. +// On other platforms this is no-op. +void ParseExtraActivationFlags() { + char buf[100]; + GetExtraActivationFlags(buf, sizeof(buf)); + ParseFlagsFromString(flags(), buf); + if (buf[0] != '\0') + VReport(1, "Extra activation flags: %s\n", buf); +} + // -------------------------- Globals --------------------- {{{1 int asan_inited; bool asan_init_is_running; @@ -224,6 +345,7 @@ static void ReserveShadowMemoryRange(uptr beg, uptr end) { CHECK_EQ((beg % GetPageSizeCached()), 0); CHECK_EQ(((end + 1) % GetPageSizeCached()), 0); uptr size = end - beg + 1; + DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. void *res = MmapFixedNoReserve(beg, size); if (res != (void*)beg) { Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " @@ -269,6 +391,53 @@ void __asan_report_ ## type ## _n(uptr addr, uptr size) { \ ASAN_REPORT_ERROR_N(load, false) ASAN_REPORT_ERROR_N(store, true) +#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_##type##size(uptr addr); \ + void __asan_##type##size(uptr addr) { \ + uptr sp = MEM_TO_SHADOW(addr); \ + uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \ + : *reinterpret_cast<u16 *>(sp); \ + if (UNLIKELY(s)) { \ + if (UNLIKELY(size >= SHADOW_GRANULARITY || \ + ((s8)((addr & (SHADOW_GRANULARITY - 1)) + size - 1)) >= \ + (s8)s)) { \ + if (__asan_test_only_reported_buggy_pointer) { \ + *__asan_test_only_reported_buggy_pointer = addr; \ + } else { \ + GET_CALLER_PC_BP_SP; \ + __asan_report_error(pc, bp, sp, addr, is_write, size); \ + } \ + } \ + } \ + } + +ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1) +ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2) +ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4) +ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8) +ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16) +ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1) +ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2) +ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4) +ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8) +ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16) + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) { + if (__asan_region_is_poisoned(addr, size)) { + GET_CALLER_PC_BP_SP; + __asan_report_error(pc, bp, sp, addr, false, size); + } +} + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) { + if (__asan_region_is_poisoned(addr, size)) { + GET_CALLER_PC_BP_SP; + __asan_report_error(pc, bp, sp, addr, true, size); + } +} + // Force the linker to keep the symbols for various ASan interface functions. // We want to keep those in the executable in order to let the instrumented // dynamic libraries access the symbol even if it is not used by the executable @@ -295,13 +464,6 @@ static NOINLINE void force_interface_symbols() { case 15: __asan_set_error_report_callback(0); break; case 16: __asan_handle_no_return(); break; case 17: __asan_address_is_poisoned(0); break; - case 18: __asan_get_allocated_size(0); break; - case 19: __asan_get_current_allocated_bytes(); break; - case 20: __asan_get_estimated_allocated_size(0); break; - case 21: __asan_get_free_bytes(); break; - case 22: __asan_get_heap_size(); break; - case 23: __asan_get_ownership(0); break; - case 24: __asan_get_unmapped_bytes(); break; case 25: __asan_poison_memory_region(0, 0); break; case 26: __asan_unpoison_memory_region(0, 0); break; case 27: __asan_set_error_exit_code(0); break; @@ -372,7 +534,8 @@ static void PrintAddressSpaceLayout() { (void*)MEM_TO_SHADOW(kMidShadowEnd)); } Printf("\n"); - Printf("red_zone=%zu\n", (uptr)flags()->redzone); + Printf("redzone=%zu\n", (uptr)flags()->redzone); + Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone); Printf("quarantine_size=%zuM\n", (uptr)flags()->quarantine_size >> 20); Printf("malloc_context_size=%zu\n", (uptr)common_flags()->malloc_context_size); @@ -387,59 +550,17 @@ static void PrintAddressSpaceLayout() { kHighShadowBeg > kMidMemEnd); } -} // namespace __asan - -// ---------------------- Interface ---------------- {{{1 -using namespace __asan; // NOLINT - -#if !SANITIZER_SUPPORTS_WEAK_HOOKS -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -const char* __asan_default_options() { return ""; } -} // extern "C" -#endif - -int NOINLINE __asan_set_error_exit_code(int exit_code) { - int old = flags()->exitcode; - flags()->exitcode = exit_code; - return old; -} - -void NOINLINE __asan_handle_no_return() { - int local_stack; - AsanThread *curr_thread = GetCurrentThread(); - CHECK(curr_thread); - uptr PageSize = GetPageSizeCached(); - uptr top = curr_thread->stack_top(); - uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1); - static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M - if (top - bottom > kMaxExpectedCleanupSize) { - static bool reported_warning = false; - if (reported_warning) - return; - reported_warning = true; - Report("WARNING: ASan is ignoring requested __asan_handle_no_return: " - "stack top: %p; bottom %p; size: %p (%zd)\n" - "False positive error reports may follow\n" - "For details see " - "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n", - top, bottom, top - bottom, top - bottom); - return; - } - PoisonShadow(bottom, top - bottom, 0); - if (curr_thread->has_fake_stack()) - curr_thread->fake_stack()->HandleNoReturn(); -} - -void NOINLINE __asan_set_death_callback(void (*callback)(void)) { - death_callback = callback; -} - -void __asan_init() { - if (asan_inited) return; +static void AsanInitInternal() { + if (LIKELY(asan_inited)) return; SanitizerToolName = "AddressSanitizer"; CHECK(!asan_init_is_running && "ASan init calls itself!"); asan_init_is_running = true; + + // Initialize flags. This must be done early, because most of the + // initialization steps look at flags(). + const char *options = GetEnv("ASAN_OPTIONS"); + InitializeFlags(flags(), options); + InitializeHighMemEnd(); // Make sure we are not statically linked. @@ -450,18 +571,21 @@ void __asan_init() { SetCheckFailedCallback(AsanCheckFailed); SetPrintfAndReportCallback(AppendToErrorMessageBuffer); - // Initialize flags. This must be done early, because most of the - // initialization steps look at flags(). - const char *options = GetEnv("ASAN_OPTIONS"); - InitializeFlags(flags(), options); + if (!flags()->start_deactivated) + ParseExtraActivationFlags(); + __sanitizer_set_report_path(common_flags()->log_path); __asan_option_detect_stack_use_after_return = flags()->detect_stack_use_after_return; + CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log); - if (common_flags()->verbosity && options) { - Report("Parsed ASAN_OPTIONS: %s\n", options); + if (options) { + VReport(1, "Parsed ASAN_OPTIONS: %s\n", options); } + if (flags()->start_deactivated) + AsanStartDeactivated(); + // Re-exec ourselves if we need to set additional env or command line args. MaybeReexec(); @@ -470,8 +594,12 @@ void __asan_init() { InitializeAsanInterceptors(); + // Enable system log ("adb logcat") on Android. + // Doing this before interceptors are initialized crashes in: + // AsanInitInternal -> android_log_write -> __interceptor_strcmp + AndroidLogInit(); + ReplaceSystemMalloc(); - ReplaceOperatorsNewAndDelete(); uptr shadow_start = kLowShadowBeg; if (kLowShadowBeg) @@ -479,7 +607,8 @@ void __asan_init() { bool full_shadow_is_available = MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); -#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING +#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ + !ASAN_FIXED_MAPPING if (!full_shadow_is_available) { kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; @@ -489,9 +618,7 @@ void __asan_init() { if (common_flags()->verbosity) PrintAddressSpaceLayout(); - if (flags()->disable_core) { - DisableCoreDumper(); - } + DisableCoreDumperIfNecessary(); if (full_shadow_is_available) { // mmap the low shadow plus at least one page at the left. @@ -501,6 +628,7 @@ void __asan_init() { ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); // protect the gap. ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); + CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); } else if (kMidMemBeg && MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { @@ -523,19 +651,10 @@ void __asan_init() { } AsanTSDInit(PlatformTSDDtor); - InstallSignalHandlers(); + InstallDeadlySignalHandlers(AsanOnSIGSEGV); - // Allocator should be initialized before starting external symbolizer, as - // fork() on Mac locks the allocator. InitializeAllocator(); - // Start symbolizer process if necessary. - if (common_flags()->symbolize) { - Symbolizer::Init(common_flags()->external_symbolizer_path); - } else { - Symbolizer::Disable(); - } - // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited // should be set to 1 prior to initializing the threads. asan_inited = 1; @@ -544,8 +663,10 @@ void __asan_init() { if (flags()->atexit) Atexit(asan_atexit); - if (flags()->coverage) + if (common_flags()->coverage) { + __sanitizer_cov_init(); Atexit(__sanitizer_cov_dump); + } // interceptors InitTlsSize(); @@ -559,15 +680,93 @@ void __asan_init() { SetCurrentThread(main_thread); main_thread->ThreadStart(internal_getpid()); force_interface_symbols(); // no-op. + SanitizerInitializeUnwinder(); #if CAN_SANITIZE_LEAKS - __lsan::InitCommonLsan(); + __lsan::InitCommonLsan(false); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { Atexit(__lsan::DoLeakCheck); } #endif // CAN_SANITIZE_LEAKS - if (common_flags()->verbosity) { - Report("AddressSanitizer Init done\n"); + VReport(1, "AddressSanitizer Init done\n"); +} + +// Initialize as requested from some part of ASan runtime library (interceptors, +// allocator, etc). +void AsanInitFromRtl() { + AsanInitInternal(); +} + +#if ASAN_DYNAMIC +// Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable +// (and thus normal initializer from .preinit_array haven't run). + +class AsanInitializer { +public: // NOLINT + AsanInitializer() { + AsanCheckIncompatibleRT(); + AsanCheckDynamicRTPrereqs(); + if (UNLIKELY(!asan_inited)) + __asan_init(); } +}; + +static AsanInitializer asan_initializer; +#endif // ASAN_DYNAMIC + +} // namespace __asan + +// ---------------------- Interface ---------------- {{{1 +using namespace __asan; // NOLINT + +#if !SANITIZER_SUPPORTS_WEAK_HOOKS +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +const char* __asan_default_options() { return ""; } +} // extern "C" +#endif + +int NOINLINE __asan_set_error_exit_code(int exit_code) { + int old = flags()->exitcode; + flags()->exitcode = exit_code; + return old; +} + +void NOINLINE __asan_handle_no_return() { + int local_stack; + AsanThread *curr_thread = GetCurrentThread(); + CHECK(curr_thread); + uptr PageSize = GetPageSizeCached(); + uptr top = curr_thread->stack_top(); + uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1); + static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M + if (top - bottom > kMaxExpectedCleanupSize) { + static bool reported_warning = false; + if (reported_warning) + return; + reported_warning = true; + Report("WARNING: ASan is ignoring requested __asan_handle_no_return: " + "stack top: %p; bottom %p; size: %p (%zd)\n" + "False positive error reports may follow\n" + "For details see " + "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n", + top, bottom, top - bottom, top - bottom); + return; + } + PoisonShadow(bottom, top - bottom, 0); + if (curr_thread->has_fake_stack()) + curr_thread->fake_stack()->HandleNoReturn(); +} + +void NOINLINE __asan_set_death_callback(void (*callback)(void)) { + death_callback = callback; +} + +// Initialize as requested from instrumented application code. +// We use this call as a trigger to wake up ASan from deactivated state. +void __asan_init() { + AsanCheckIncompatibleRT(); + AsanActivate(); + AsanInitInternal(); } |