diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-02-22 22:43:40 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-02-22 22:43:40 +0000 |
commit | cd2dd3df15523e2be8d2bbace27641d6ac9fa40d (patch) | |
tree | fbdacaec253cc5ceee88cb44de5545fa32c8bd67 /lib/asan | |
parent | 476c4db3dc56bee43df384704c75ccc71cfa7a1d (diff) | |
download | src-cd2dd3df15523e2be8d2bbace27641d6ac9fa40d.tar.gz src-cd2dd3df15523e2be8d2bbace27641d6ac9fa40d.zip |
Import compiler-rt trunk r230183.vendor/compiler-rt/compiler-rt-r230183
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=279192
svn path=/vendor/compiler-rt/compiler-rt-r230183/; revision=279193; tag=vendor/compiler-rt/compiler-rt-r230183
Diffstat (limited to 'lib/asan')
-rw-r--r-- | lib/asan/README.txt | 14 | ||||
-rw-r--r-- | lib/asan/asan_flags.cc | 55 | ||||
-rw-r--r-- | lib/asan/asan_flags.h | 4 | ||||
-rw-r--r-- | lib/asan/asan_flags.inc | 1 | ||||
-rw-r--r-- | lib/asan/asan_globals.cc | 16 | ||||
-rw-r--r-- | lib/asan/asan_interface_internal.h | 7 | ||||
-rw-r--r-- | lib/asan/asan_internal.h | 1 | ||||
-rw-r--r-- | lib/asan/asan_linux.cc | 4 | ||||
-rw-r--r-- | lib/asan/asan_mac.cc | 8 | ||||
-rw-r--r-- | lib/asan/asan_rtl.cc | 4 | ||||
-rw-r--r-- | lib/asan/asan_suppressions.cc | 40 | ||||
-rw-r--r-- | lib/asan/asan_win.cc | 4 | ||||
-rw-r--r-- | lib/asan/asan_win_dll_thunk.cc | 36 | ||||
-rw-r--r-- | lib/asan/asan_win_dynamic_runtime_thunk.cc | 85 | ||||
-rwxr-xr-x | lib/asan/scripts/asan_device_setup | 158 | ||||
-rw-r--r-- | lib/asan/tests/asan_noinst_test.cc | 5 |
16 files changed, 342 insertions, 100 deletions
diff --git a/lib/asan/README.txt b/lib/asan/README.txt index b9c43acd5fe4..8cc9bb17b59d 100644 --- a/lib/asan/README.txt +++ b/lib/asan/README.txt @@ -1,7 +1,6 @@ AddressSanitizer RT ================================ -This directory contains sources of the AddressSanitizer (asan) runtime library. -We are in the process of integrating AddressSanitizer with LLVM, stay tuned. +This directory contains sources of the AddressSanitizer (ASan) runtime library. Directory structure: README.txt : This file. @@ -13,14 +12,13 @@ tests/* : ASan unit tests. Also ASan runtime needs the following libraries: lib/interception/ : Machinery used to intercept function calls. -lib/sanitizer_common/ : Code shared between ASan and TSan. +lib/sanitizer_common/ : Code shared between various sanitizers. -Currently ASan runtime can be built by both make and cmake build systems. -(see compiler-rt/make and files Makefile.mk for make-based build and -files CMakeLists.txt for cmake-based build). +ASan runtime currently also embeds part of LeakSanitizer runtime for +leak detection (lib/lsan/lsan_common.{cc,h}). -ASan unit and output tests work only with cmake. You may run this -command from the root of your cmake build tree: +ASan runtime can only be built by CMake. You can run ASan tests +from the root of your CMake build tree: make check-asan diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 1d82ab0e725f..efb7767d5d91 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -46,18 +46,15 @@ void Flags::SetDefaults() { #undef ASAN_FLAG } -void RegisterAsanFlags(FlagParser *parser, Flags *f) { +static void RegisterAsanFlags(FlagParser *parser, Flags *f) { #define ASAN_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(parser, #Name, Description, &f->Name); #include "asan_flags.inc" #undef ASAN_FLAG } -void InitializeFlags(Flags *f) { - FlagParser parser; - RegisterAsanFlags(&parser, f); - RegisterCommonFlags(&parser); - +void InitializeFlags() { + // Set the default values and prepare for parsing ASan and common flags. SetCommonFlagsDefaults(); { CommonFlags cf; @@ -68,28 +65,44 @@ void InitializeFlags(Flags *f) { cf.intercept_tls_get_addr = true; OverrideCommonFlags(cf); } - - const int kDefaultQuarantineSizeMb = (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8; + Flags *f = flags(); f->SetDefaults(); - // Override from compile definition. - const char *compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); - parser.ParseString(compile_def); + FlagParser asan_parser; + RegisterAsanFlags(&asan_parser, f); + RegisterCommonFlags(&asan_parser); + + // Set the default values and prepare for parsing LSan flags (which can also + // overwrite common flags). +#if CAN_SANITIZE_LEAKS + __lsan::Flags *lf = __lsan::flags(); + lf->SetDefaults(); + + FlagParser lsan_parser; + __lsan::RegisterLsanFlags(&lsan_parser, lf); + RegisterCommonFlags(&lsan_parser); +#endif + + // Override from ASan compile definition. + const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); + asan_parser.ParseString(asan_compile_def); // Override from user-specified string. - const char *default_options = MaybeCallAsanDefaultOptions(); - parser.ParseString(default_options); + const char *asan_default_options = MaybeCallAsanDefaultOptions(); + asan_parser.ParseString(asan_default_options); // Override from command line. - const char *env = GetEnv("ASAN_OPTIONS"); - if (env) parser.ParseString(env); + asan_parser.ParseString(GetEnv("ASAN_OPTIONS")); +#if CAN_SANITIZE_LEAKS + lsan_parser.ParseString(GetEnv("LSAN_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)); - parser.ParseString(buf); + asan_parser.ParseString(buf); } SetVerbosity(common_flags()->verbosity); @@ -97,7 +110,10 @@ void InitializeFlags(Flags *f) { // TODO(eugenis): dump all flags at verbosity>=2? if (Verbosity()) ReportUnrecognizedFlags(); - if (common_flags()->help) parser.PrintFlagDescriptions(); + if (common_flags()->help) { + // TODO(samsonov): print all of the flags (ASan, LSan, common). + asan_parser.PrintFlagDescriptions(); + } // Flag validation: if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) { @@ -127,8 +143,11 @@ void InitializeFlags(Flags *f) { } if (f->quarantine_size >= 0) f->quarantine_size_mb = f->quarantine_size >> 20; - if (f->quarantine_size_mb < 0) + if (f->quarantine_size_mb < 0) { + const int kDefaultQuarantineSizeMb = + (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8; f->quarantine_size_mb = kDefaultQuarantineSizeMb; + } } } // namespace __asan diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h index 7653543f6d88..4935161c30f1 100644 --- a/lib/asan/asan_flags.h +++ b/lib/asan/asan_flags.h @@ -41,8 +41,8 @@ extern Flags asan_flags_dont_use_directly; inline Flags *flags() { return &asan_flags_dont_use_directly; } -void RegisterAsanFlags(FlagParser *parser, Flags *f); -void InitializeFlags(Flags *f); + +void InitializeFlags(); } // namespace __asan diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index ec9d41980d9c..53a8a4039e7e 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -142,3 +142,4 @@ ASAN_FLAG(int, detect_odr_violation, 2, "have different sizes") 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.") diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index c4571953c408..06140bbb360a 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -182,6 +182,8 @@ static void RegisterGlobal(const Global *g) { static void UnregisterGlobal(const Global *g) { CHECK(asan_inited); + if (flags()->report_globals >= 2) + ReportGlobal(*g, "Removed"); CHECK(flags()->report_globals); CHECK(AddrIsInMem(g->beg)); CHECK(AddrIsAlignedByGranularity(g->beg)); @@ -208,6 +210,20 @@ void StopInitOrderChecking() { } } +#if SANITIZER_WINDOWS // Should only be called on Windows. +SANITIZER_INTERFACE_ATTRIBUTE +void UnregisterGlobalsInRange(void *beg, void *end) { + if (!flags()->report_globals) + return; + BlockingMutexLock lock(&mu_for_globals); + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { + void *address = (void *)l->g->beg; + if (beg <= address && address < end) + UnregisterGlobal(l->g); + } +} +#endif + } // namespace __asan // ---------------------- Interface ---------------- {{{1 diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index edaf44d7893a..ea7540f6bb56 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -9,8 +9,11 @@ // // This file is a part of AddressSanitizer, an address sanity checker. // -// This header can be included by the instrumented program to fetch -// data (mostly allocator statistics) from ASan runtime library. +// This header declares the AddressSanitizer runtime interface functions. +// The runtime library has to define these functions so the instrumented program +// could call them. +// +// See also include/sanitizer/asan_interface.h //===----------------------------------------------------------------------===// #ifndef ASAN_INTERFACE_INTERNAL_H #define ASAN_INTERFACE_INTERNAL_H diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index a8e23ce772ff..ffd3ff82d71e 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -93,6 +93,7 @@ void AsanCheckIncompatibleRT(); void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); void AsanOnSIGSEGV(int, void *siginfo, void *context); +void DisableReexec(); void MaybeReexec(); void ReadContextStack(void *context, uptr *stack, uptr *ssize); void AsanPlatformThreadInit(); diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 65605009005f..8e8bafd47af6 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -68,6 +68,10 @@ asan_rt_version_t __asan_rt_version; namespace __asan { +void DisableReexec() { + // No need to re-exec on Linux. +} + void MaybeReexec() { // No need to re-exec on Linux. } diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index 5c2caeae4934..b35368617dca 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -101,7 +101,15 @@ void LeakyResetEnv(const char *name, const char *name_value) { } } +static bool reexec_disabled = false; + +void DisableReexec() { + reexec_disabled = true; +} + 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. diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index 0b2a23d40379..9126e71a6437 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -314,7 +314,7 @@ static void AsanInitInternal() { // Initialize flags. This must be done early, because most of the // initialization steps look at flags(). - InitializeFlags(flags()); + InitializeFlags(); SetCanPoisonMemory(flags()->poison_heap); SetMallocContextSize(common_flags()->malloc_context_size); @@ -440,7 +440,7 @@ static void AsanInitInternal() { SanitizerInitializeUnwinder(); #if CAN_SANITIZE_LEAKS - __lsan::InitCommonLsan(false); + __lsan::InitCommonLsan(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { Atexit(__lsan::DoLeakCheck); } diff --git a/lib/asan/asan_suppressions.cc b/lib/asan/asan_suppressions.cc index ef554716faa0..62198aec64e7 100644 --- a/lib/asan/asan_suppressions.cc +++ b/lib/asan/asan_suppressions.cc @@ -15,57 +15,62 @@ #include "asan_suppressions.h" #include "asan_stack.h" +#include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_symbolizer.h" namespace __asan { -static bool suppressions_inited = false; +ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; +static SuppressionContext *suppression_ctx = nullptr; +static const char kInterceptorName[] = "interceptor_name"; +static const char kInterceptorViaFunction[] = "interceptor_via_fun"; +static const char kInterceptorViaLibrary[] = "interceptor_via_lib"; +static const char *kSuppressionTypes[] = { + kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary}; void InitializeSuppressions() { - CHECK(!suppressions_inited); - SuppressionContext::InitIfNecessary(); - suppressions_inited = true; + CHECK_EQ(nullptr, suppression_ctx); + suppression_ctx = new (suppression_placeholder) // NOLINT + SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); + suppression_ctx->ParseFromFile(flags()->suppressions); } bool IsInterceptorSuppressed(const char *interceptor_name) { - CHECK(suppressions_inited); - SuppressionContext *ctx = SuppressionContext::Get(); + CHECK(suppression_ctx); Suppression *s; // Match "interceptor_name" suppressions. - return ctx->Match(interceptor_name, SuppressionInterceptorName, &s); + return suppression_ctx->Match(interceptor_name, kInterceptorName, &s); } bool HaveStackTraceBasedSuppressions() { - CHECK(suppressions_inited); - SuppressionContext *ctx = SuppressionContext::Get(); - return ctx->HasSuppressionType(SuppressionInterceptorViaFunction) || - ctx->HasSuppressionType(SuppressionInterceptorViaLibrary); + CHECK(suppression_ctx); + return suppression_ctx->HasSuppressionType(kInterceptorViaFunction) || + suppression_ctx->HasSuppressionType(kInterceptorViaLibrary); } bool IsStackTraceSuppressed(const StackTrace *stack) { - CHECK(suppressions_inited); if (!HaveStackTraceBasedSuppressions()) return false; - SuppressionContext *ctx = SuppressionContext::Get(); + CHECK(suppression_ctx); Symbolizer *symbolizer = Symbolizer::GetOrInit(); Suppression *s; for (uptr i = 0; i < stack->size && stack->trace[i]; i++) { uptr addr = stack->trace[i]; - if (ctx->HasSuppressionType(SuppressionInterceptorViaLibrary)) { + if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) { const char *module_name; uptr module_offset; // Match "interceptor_via_lib" suppressions. if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name, &module_offset) && - ctx->Match(module_name, SuppressionInterceptorViaLibrary, &s)) { + suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) { return true; } } - if (ctx->HasSuppressionType(SuppressionInterceptorViaFunction)) { + if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) { SymbolizedStack *frames = symbolizer->SymbolizePC(addr); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { const char *function_name = cur->info.function; @@ -73,7 +78,8 @@ bool IsStackTraceSuppressed(const StackTrace *stack) { continue; } // Match "interceptor_via_fun" suppressions. - if (ctx->Match(function_name, SuppressionInterceptorViaFunction, &s)) { + if (suppression_ctx->Match(function_name, kInterceptorViaFunction, + &s)) { frames->ClearAll(); return true; } diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index 4f02b022fe79..693f0bcdee8e 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -60,6 +60,10 @@ void PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); } // ---------------------- Various stuff ---------------- {{{1 +void DisableReexec() { + // No need to re-exec on Windows. +} + void MaybeReexec() { // No need to re-exec on Windows. } diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc index b38a2d16087f..5d39e33096a8 100644 --- a/lib/asan/asan_win_dll_thunk.cc +++ b/lib/asan/asan_win_dll_thunk.cc @@ -294,7 +294,43 @@ INTERFACE_FUNCTION(__asan_stack_free_8) INTERFACE_FUNCTION(__asan_stack_free_9) 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_cov) +INTERFACE_FUNCTION(__sanitizer_cov_dump) +INTERFACE_FUNCTION(__sanitizer_cov_indir_call16) +INTERFACE_FUNCTION(__sanitizer_cov_init) INTERFACE_FUNCTION(__sanitizer_cov_module_init) +INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block) +INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter) +INTERFACE_FUNCTION(__sanitizer_cov_with_check) +INTERFACE_FUNCTION(__sanitizer_free_hook) +INTERFACE_FUNCTION(__sanitizer_get_allocated_size) +INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) +INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes) +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_coverage) +INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) +INTERFACE_FUNCTION(__sanitizer_malloc_hook) +INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) +INTERFACE_FUNCTION(__sanitizer_print_stack_trace) +INTERFACE_FUNCTION(__sanitizer_ptr_cmp) +INTERFACE_FUNCTION(__sanitizer_ptr_sub) +INTERFACE_FUNCTION(__sanitizer_report_error_summary) +INTERFACE_FUNCTION(__sanitizer_reset_coverage) +INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify) +INTERFACE_FUNCTION(__sanitizer_set_death_callback) +INTERFACE_FUNCTION(__sanitizer_set_report_path) +INTERFACE_FUNCTION(__sanitizer_unaligned_load16) +INTERFACE_FUNCTION(__sanitizer_unaligned_load32) +INTERFACE_FUNCTION(__sanitizer_unaligned_load64) +INTERFACE_FUNCTION(__sanitizer_unaligned_store16) +INTERFACE_FUNCTION(__sanitizer_unaligned_store32) +INTERFACE_FUNCTION(__sanitizer_unaligned_store64) +INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) // TODO(timurrrr): Add more interface functions on the as-needed basis. diff --git a/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc index 3a4de7dbf1fb..19456141c1ec 100644 --- a/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -23,10 +23,11 @@ // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK -extern "C" { -__declspec(dllimport) int __asan_set_seh_filter(); -__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); +#include <windows.h> +#include <psapi.h> +extern "C" { +//////////////////////////////////////////////////////////////////////////////// // Define a copy of __asan_option_detect_stack_use_after_return that should be // used when linking an MD runtime with a set of object files on Windows. // @@ -37,16 +38,82 @@ __declspec(dllimport) int __asan_should_detect_stack_use_after_return(); // with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows // just to work around this issue, let's clone the a variable that is // constant after initialization anyways. +__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); int __asan_option_detect_stack_use_after_return = __asan_should_detect_stack_use_after_return(); +} + +//////////////////////////////////////////////////////////////////////////////// +// For some reason, the MD CRT doesn't call the C/C++ terminators as MT does. +// To work around this, for each DLL we schedule a call to +// UnregisterGlobalsInRange atexit() specifying the address range of the DLL +// image to unregister globals in that range. We don't do the same +// for the main module (.exe) as the asan_globals.cc allocator is destroyed +// by the time UnregisterGlobalsInRange is executed. +// See PR22545 for the details. +namespace __asan { +__declspec(dllimport) +void UnregisterGlobalsInRange(void *beg, void *end); +} + +namespace { +void *this_module_base, *this_module_end; + +void UnregisterGlobals() { + __asan::UnregisterGlobalsInRange(this_module_base, this_module_end); +} + +int ScheduleUnregisterGlobals() { + HMODULE this_module = 0; + // Increments the reference counter of the DLL module, so need to call + // FreeLibrary later. + if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCTSTR)&UnregisterGlobals, &this_module)) + return 1; + + // Skip the main module. + if (this_module == GetModuleHandle(0)) + return 0; + + MODULEINFO mi; + bool success = + GetModuleInformation(GetCurrentProcess(), this_module, &mi, sizeof(mi)); + if (!FreeLibrary(this_module)) + return 2; + if (!success) + return 3; -// Set the ASan-specific SEH handler at the end of CRT initialization of each -// module (see asan_win.cc for the details). + this_module_base = mi.lpBaseOfDll; + this_module_end = (char*)mi.lpBaseOfDll + mi.SizeOfImage; + + return atexit(UnregisterGlobals); +} +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// ASan SEH handling. +extern "C" __declspec(dllimport) int __asan_set_seh_filter(); +static int SetSEHFilter() { return __asan_set_seh_filter(); } + +/////////////////////////////////////////////////////////////////////////////// +// We schedule some work at start-up by placing callbacks to our code to the +// list of CRT C initializers. +// +// First, declare sections we'll be using: +#pragma section(".CRT$XID", long, read) // NOLINT +#pragma section(".CRT$XIZ", long, read) // NOLINT + +// We need to call 'atexit(UnregisterGlobals);' after atexit() is initialized +// (.CRT$XIC) but before the C++ constructors (.CRT$XCA). +__declspec(allocate(".CRT$XID")) +static int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; + +// We need to set the ASan-specific SEH handler at the end of CRT initialization +// of each module (see also asan_win.cc). // // Unfortunately, putting a pointer to __asan_set_seh_filter into // __asan_intercept_seh gets optimized out, so we have to use an extra function. -static int SetSEHFilter() { return __asan_set_seh_filter(); } -#pragma section(".CRT$XIZ", long, read) // NOLINT -__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter; -} +extern "C" __declspec(allocate(".CRT$XIZ")) +int (*__asan_seh_interceptor)() = SetSEHFilter; + #endif // ASAN_DYNAMIC_RUNTIME_THUNK diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index c143b9fab13c..104e07b722ca 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -18,6 +18,7 @@ revert=no extra_options= device= lib= +use_su=0 function usage { echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]" @@ -26,13 +27,70 @@ function usage { echo " --extra-options: Extra ASAN_OPTIONS." echo " --device: Install to the given device. Use 'adb devices' to find" echo " device-id." + echo " --use-su: Use 'su -c' prefix for every adb command instead of using" + echo " 'adb root' once." echo exit 1 } +function adb_push { + if [ $use_su -eq 0 ]; then + $ADB push "$1" "$2" + else + local FILENAME=$(basename $1) + $ADB push "$1" "/data/local/tmp/$FILENAME" + $ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null + $ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\"" + $ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\"" + fi +} + +function adb_remount { + if [ $use_su -eq 0 ]; then + $ADB remount + else + local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1` + if [ "$STORAGE" != "" ]; then + echo Remounting $STORAGE at /system + $ADB shell su -c "mount -o remount,rw $STORAGE /system" + else + echo Failed to get storage device name for "/system" mount point + fi + fi +} + +function adb_shell { + if [ $use_su -eq 0 ]; then + $ADB shell $@ + else + $ADB shell su -c "$*" + fi +} + +function adb_root { + if [ $use_su -eq 0 ]; then + $ADB root + fi +} + +function adb_wait_for_device { + $ADB wait-for-device +} + +function adb_pull { + if [ $use_su -eq 0 ]; then + $ADB pull "$1" "$2" + else + local FILENAME=$(basename $1) + $ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null + $ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" && + $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\"" + fi +} + function get_device_arch { # OUTVAR local _outvar=$1 - local _ABI=$($ADB shell getprop ro.product.cpu.abi) + local _ABI=$(adb_shell getprop ro.product.cpu.abi) local _ARCH= if [[ $_ABI == x86* ]]; then _ARCH=i686 @@ -74,6 +132,9 @@ while [[ $# > 0 ]]; do fi device="$1" ;; + --use-su) + use_su=1 + ;; *) usage ;; @@ -86,12 +147,25 @@ if [[ x$device != x ]]; then ADB="$ADB -s $device" fi +if [ $use_su -eq 1 ]; then + # Test if 'su' is present on the device + SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'` + if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then + echo "ERROR: Cannot use 'su -c':" + echo "$ adb shell su -c \"echo foo\"" + echo $SU_TEST_OUT + echo "Check that 'su' binary is correctly installed on the device or omit" + echo " --use-su flag" + exit 1 + fi +fi + echo '>> Remounting /system rw' -$ADB wait-for-device -$ADB root -$ADB wait-for-device -$ADB remount -$ADB wait-for-device +adb_wait_for_device +adb_root +adb_wait_for_device +adb_remount +adb_wait_for_device get_device_arch ARCH echo "Target architecture: $ARCH" @@ -100,22 +174,24 @@ ASAN_RT="libclang_rt.asan-$ARCH-android.so" if [[ x$revert == xyes ]]; then echo '>> Uninstalling ASan' - if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then + 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 - $ADB shell rm /system/lib/$ASAN_RT + adb_shell mv /system/bin/app_process.real /system/bin/app_process + adb_shell rm /system/bin/asanwrapper else - $ADB shell rm /system/bin/app_process.wrap - $ADB shell rm /system/bin/asanwrapper - $ADB shell rm /system/lib/$ASAN_RT - $ADB shell rm /system/bin/app_process - $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process + 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' - $ADB shell stop - $ADB shell start + adb_shell stop + adb_shell start + + # Remove the library on the last step to give a chance to the 'su' binary to + # be executed without problem. + adb_shell rm /system/lib/$ASAN_RT echo '>> Done' exit 0 @@ -146,28 +222,28 @@ TMPDIROLD="$TMPDIRBASE/old" TMPDIR="$TMPDIRBASE/new" mkdir "$TMPDIROLD" -RELEASE=$($ADB shell getprop ro.build.version.release) +RELEASE=$(adb_shell getprop ro.build.version.release) PRE_L=0 if echo "$RELEASE" | grep '^4\.' >&/dev/null; then PRE_L=1 fi -if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then +if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then - if $ADB pull /system/bin/app_process.real /dev/null >&/dev/null; then + if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then echo '>> Old-style ASan installation detected. Reverting.' - $ADB shell mv /system/bin/app_process.real /system/bin/app_process + adb_shell mv /system/bin/app_process.real /system/bin/app_process fi echo '>> Pre-L device detected. Setting up app_process symlink.' - $ADB shell mv /system/bin/app_process /system/bin/app_process32 - $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process + adb_shell mv /system/bin/app_process /system/bin/app_process32 + adb_shell ln -s /system/bin/app_process32 /system/bin/app_process fi echo '>> Copying files from the device' -$ADB pull /system/bin/app_process.wrap "$TMPDIROLD" || true -$ADB pull /system/bin/asanwrapper "$TMPDIROLD" || true -$ADB pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true +adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true +adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true +adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true cp -r "$TMPDIROLD" "$TMPDIR" if [[ -f "$TMPDIR/app_process.wrap" ]]; then @@ -213,52 +289,52 @@ EOF if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then echo '>> Pushing files to the device' - $ADB push "$TMPDIR/$ASAN_RT" /system/lib/ - $ADB push "$TMPDIR/app_process.wrap" /system/bin/app_process.wrap - $ADB push "$TMPDIR/asanwrapper" /system/bin/asanwrapper + adb_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 rm /system/bin/app_process + adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process - $ADB shell chown root.shell \ + adb_shell chown root.shell \ /system/lib/"$ASAN_RT" \ /system/bin/app_process.wrap \ /system/bin/asanwrapper - $ADB shell chmod 644 \ + adb_shell chmod 644 \ /system/lib/"$ASAN_RT" - $ADB shell chmod 755 \ + adb_shell chmod 755 \ /system/bin/app_process.wrap \ /system/bin/asanwrapper # Make SELinux happy by keeping app_process wrapper and the shell # it runs on in zygote domain. ENFORCING=0 - if $ADB shell getenforce | grep Enforcing >/dev/null; then + if adb_shell getenforce | grep Enforcing >/dev/null; then # Sometimes shell is not allowed to change file contexts. # Temporarily switch to permissive. ENFORCING=1 - $ADB shell setenforce 0 + adb_shell setenforce 0 fi - $ADB shell cp /system/bin/sh /system/bin/sh-from-zygote + 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 \ + adb_shell chcon $CTX \ /system/bin/sh-from-zygote \ /system/bin/app_process.wrap \ /system/bin/app_process32 if [ $ENFORCING == 1 ]; then - $ADB shell setenforce 1 + adb_shell setenforce 1 fi echo '>> Restarting shell (asynchronous)' - $ADB shell stop - $ADB shell start + adb_shell stop + adb_shell start echo '>> Please wait until the device restarts' else diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc index c469d62a6766..6a428fbbc2b9 100644 --- a/lib/asan/tests/asan_noinst_test.cc +++ b/lib/asan/tests/asan_noinst_test.cc @@ -33,7 +33,10 @@ // Make sure __asan_init is called before any test case is run. struct AsanInitCaller { - AsanInitCaller() { __asan_init(); } + AsanInitCaller() { + __asan::DisableReexec(); + __asan_init(); + } }; static AsanInitCaller asan_init_caller; |