Index: lib/asan/asan_globals.cc =================================================================== --- lib/asan/asan_globals.cc +++ lib/asan/asan_globals.cc @@ -284,6 +284,25 @@ // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT + +// Apply __asan_register_globals to all globals found in the same loaded +// executable or shared library as `flag'. The flag tracks whether globals have +// already been registered or not for this image. +void __asan_register_image_globals(uptr *flag) { + if (*flag) // check that globals have not already been registered + return; + AsanApplyToGlobals(__asan_register_globals, flag); + *flag = 1; // indicate that globals have now been registered +} + +// This mirrors __asan_register_image_globals. +void __asan_unregister_image_globals(uptr *flag) { + if (!*flag) + return; + AsanApplyToGlobals(__asan_unregister_globals, flag); + *flag = 0; +} + // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; Index: lib/asan/asan_init_version.h =================================================================== --- lib/asan/asan_init_version.h +++ lib/asan/asan_init_version.h @@ -19,17 +19,20 @@ // Every time the ASan ABI changes we also change the version number in the // __asan_init function name. Objects built with incompatible ASan ABI // versions will not link with run-time. + // // Changes between ABI versions: // v1=>v2: added 'module_name' to __asan_global // v2=>v3: stack frame description (created by the compiler) - // contains the function PC as the 3-rd field (see - // DescribeAddressIfStack). - // v3=>v4: added '__asan_global_source_location' to __asan_global. + // contains the function PC as the 3rd field (see + // DescribeAddressIfStack) + // 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. + // __asan_stack_free_ functions // v5=>v6: changed the name of the version check symbol - // v6=>v7: added 'odr_indicator' to __asan_global. - #define __asan_version_mismatch_check __asan_version_mismatch_check_v7 + // v6=>v7: added 'odr_indicator' to __asan_global + // v7=>v8: added '__asan_(un)register_image_globals' functions for dead + // stripping support on Mach-O platforms + #define __asan_version_mismatch_check __asan_version_mismatch_check_v8 } #endif // ASAN_INIT_VERSION_H Index: lib/asan/asan_interface_internal.h =================================================================== --- lib/asan/asan_interface_internal.h +++ lib/asan/asan_interface_internal.h @@ -57,6 +57,14 @@ uptr odr_indicator; // The address of the ODR indicator symbol. }; + // These functions can be called on some platforms to find globals in the same + // loaded image as `flag' and apply __asan_(un)register_globals to them, + // filtering out redundant calls. + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_register_image_globals(uptr *flag); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unregister_image_globals(uptr *flag); + // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE Index: lib/asan/asan_internal.h =================================================================== --- lib/asan/asan_internal.h +++ lib/asan/asan_internal.h @@ -73,6 +73,13 @@ void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); +// Support function for __asan_(un)register_image_globals. Searches for the +// loaded image containing `needle' and then enumerates all global metadata +// structures declared in that image, applying `op' (e.g., +// __asan_(un)register_globals) to them. +typedef void (*globals_op_fptr)(__asan_global *, uptr); +void AsanApplyToGlobals(globals_op_fptr op, const void *needle); + void AsanOnDeadlySignal(int, void *siginfo, void *context); void ReadContextStack(void *context, uptr *stack, uptr *ssize); Index: lib/asan/asan_linux.cc =================================================================== --- lib/asan/asan_linux.cc +++ lib/asan/asan_linux.cc @@ -75,6 +75,10 @@ return &_DYNAMIC; // defined in link.h } +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + UNIMPLEMENTED(); +} + #if SANITIZER_ANDROID // FIXME: should we do anything for Android? void AsanCheckDynamicRTPrereqs() {} Index: lib/asan/asan_mac.cc =================================================================== --- lib/asan/asan_mac.cc +++ lib/asan/asan_mac.cc @@ -24,9 +24,11 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mac.h" +#include #include #include #include +#include #include #include #include // for free() @@ -66,6 +68,30 @@ // No-op. Mac does not support static linkage anyway. void AsanCheckIncompatibleRT() {} +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + // Find the Mach-O header for the image containing the needle + Dl_info info; + int err = dladdr(needle, &info); + if (err == 0) return; + +#if __LP64__ + const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase; +#else + const struct mach_header *mh = (struct mach_header *)info.dli_fbase; +#endif + + // Look up the __asan_globals section in that image and register its globals + unsigned long size = 0; + __asan_global *globals = (__asan_global *)getsectiondata( + mh, + "__DATA", "__asan_globals", + &size); + + if (!globals) return; + if (size % sizeof(__asan_global) != 0) return; + op(globals, size / sizeof(__asan_global)); +} + void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } Index: lib/asan/asan_win.cc =================================================================== --- lib/asan/asan_win.cc +++ lib/asan/asan_win.cc @@ -149,6 +149,10 @@ (uptr *)&REAL(NtWaitForWorkViaWorkerFactory))); } +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + UNIMPLEMENTED(); +} + // ---------------------- TSD ---------------- {{{ static bool tsd_key_inited = false; Index: test/asan/TestCases/Darwin/dead-strip.c =================================================================== --- test/asan/TestCases/Darwin/dead-strip.c +++ test/asan/TestCases/Darwin/dead-strip.c @@ -0,0 +1,26 @@ +// Test that AddressSanitizer does not re-animate dead globals when dead +// stripping is turned on. +// +// This test verifies that an out-of-bounds access on a global variable is +// detected after dead stripping has been performed. This proves that the +// runtime is able to register globals in the __DATA,__asan_globals section. + +// RUN: %clang_asan -Xlinker -dead_strip -o %t %s +// RUN: llvm-nm -format=posix %t | FileCheck --check-prefix NM-CHECK %s +// RUN: not %run %t 2>&1 | FileCheck --check-prefix ASAN-CHECK %s + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warray-bounds" + +int alive[1] = {}; +int dead[1] = {}; +// NM-CHECK: {{^_alive }} +// NM-CHECK-NOT: {{^_dead }} + +int main() { + alive[1] = 0; + // ASAN-CHECK: {{0x.* is located 0 bytes to the right of global variable}} + return 0; +} + +#pragma clang diagnostic pop Index: test/asan/TestCases/initialization-bug.cc =================================================================== --- test/asan/TestCases/initialization-bug.cc +++ test/asan/TestCases/initialization-bug.cc @@ -6,7 +6,7 @@ // Do not test with optimization -- the error may be optimized away. // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=186 -// XFAIL: darwin,win32 +// XFAIL: win32 #include