Index: lib/asan/asan_flags.inc =================================================================== --- lib/asan/asan_flags.inc +++ lib/asan/asan_flags.inc @@ -161,3 +161,6 @@ ASAN_FLAG(bool, verify_asan_link_order, true, "Check position of ASan runtime in library list (needs to be disabled" " when other library has to be preloaded system-wide)") +ASAN_FLAG(bool, disable_init, false, + "If true, disables all initialization of the " + "sanitizer after flags are parsed. Only supported on Darwin.") Index: lib/asan/asan_internal.h =================================================================== --- lib/asan/asan_internal.h +++ lib/asan/asan_internal.h @@ -111,8 +111,14 @@ void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name); -// Add convenient macro for interface functions that may be represented as -// weak hooks. +#if SANITIZER_SUPPORTS_DISABLED_INIT +void HandleDisabledInit(); +#else +void HandleDisabledInit() { Die(); } +#endif + +// Add convenient macro for interface functions that may be represented +// as weak hooks. #define ASAN_MALLOC_HOOK(ptr, size) \ do { \ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size); \ Index: lib/asan/asan_malloc_mac.cc =================================================================== --- lib/asan/asan_malloc_mac.cc +++ lib/asan/asan_malloc_mac.cc @@ -61,4 +61,13 @@ #include "sanitizer_common/sanitizer_malloc_mac.inc" +namespace COMMON_MALLOC_NAMESPACE { +void HandleDisabledInit() { + // On the no init path make sure we still initialize the malloc zone + // so Symbolication clients (e.g. `leaks`) can find an initialized + // malloc zone when the sanitizer dylib gets dlopen()'ed. + InitMallocZoneFields(); +} +} // namespace COMMON_MALLOC_NAMESPACE + #endif Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -396,6 +396,15 @@ // initialization steps look at flags(). InitializeFlags(); + // Stop performing init if supported by the platform and it + // has been requested. + if (SANITIZER_SUPPORTS_DISABLED_INIT && UNLIKELY(flags()->disable_init)) { + asan_init_is_running = false; + Report("AddressSanitizer init has been disabled in this process.\n"); + HandleDisabledInit(); + return; + } + AsanCheckIncompatibleRT(); AsanCheckDynamicRTPrereqs(); AvoidCVE_2016_2143(); Index: lib/sanitizer_common/sanitizer_platform.h =================================================================== --- lib/sanitizer_common/sanitizer_platform.h +++ lib/sanitizer_common/sanitizer_platform.h @@ -342,4 +342,11 @@ #define SANITIZER_SYMBOLIZER_MARKUP 0 #endif +// Enable ability to disable dynamic library initialization. +#if SANITIZER_MAC +#define SANITIZER_SUPPORTS_DISABLED_INIT 1 +#else +#define SANITIZER_SUPPORTS_DISABLED_INIT 0 +#endif + #endif // SANITIZER_PLATFORM_H Index: test/asan/TestCases/Darwin/disable_init.cc =================================================================== --- /dev/null +++ test/asan/TestCases/Darwin/disable_init.cc @@ -0,0 +1,26 @@ +// RUN: %clangxx -g -O0 %s -o %t +// RUN: not --crash env ASAN_OPTIONS=disable_init=0 %run %t %shared_libasan +// RUN: env ASAN_OPTIONS=disable_init=1 %run %t %shared_libasan +#include +#include + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + const char *dylib_path = argv[1]; + void *handle = dlopen(dylib_path, RTLD_LAZY); + if (!handle) { + fprintf(stderr, "Failed to dlopen: %s\n", dlerror()); + return 1; + } + // Make sure we can find a function we expect to be in the dylib. + void *fn = dlsym(handle, "__sanitizer_mz_size"); + if (!fn) { + fprintf(stderr, "Failed to get symbol: %s\n", dlerror()); + return 1; + } + // TODO(dliew): Actually call a function from the dylib that is safe to call. + return 0; +}