Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -89,6 +89,7 @@ static const char *const kAsanModuleDtorName = "asan.module_dtor"; static const uint64_t kAsanCtorAndDtorPriority = 1; static const char *const kAsanReportErrorTemplate = "__asan_report_"; +static const char *const kAsanApplyToGlobalsName = "__asan_apply_to_globals"; static const char *const kAsanRegisterGlobalsName = "__asan_register_globals"; static const char *const kAsanUnregisterGlobalsName = "__asan_unregister_globals"; @@ -546,6 +547,7 @@ Function *AsanUnpoisonGlobals; Function *AsanRegisterGlobals; Function *AsanUnregisterGlobals; + Function *AsanApplyToGlobals; }; // Stack poisoning does not play well with exception handling. @@ -1298,6 +1300,13 @@ M.getOrInsertFunction(kAsanUnregisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy, nullptr)); AsanUnregisterGlobals->setLinkage(Function::ExternalLinkage); + + if (TargetTriple.isOSBinFormatMachO()) { + AsanApplyToGlobals = checkSanitizerInterfaceFunction( + M.getOrInsertFunction(kAsanApplyToGlobalsName, + IRB.getVoidTy(), IntptrTy, IntptrTy, nullptr)); + AsanApplyToGlobals->setLinkage(Function::ExternalLinkage); + } } // This function replaces all global variables with new variables that have @@ -1406,17 +1415,58 @@ DEBUG(dbgs() << "NEW GLOBAL: " << *NewGlobal << "\n"); } - ArrayType *ArrayOfGlobalStructTy = ArrayType::get(GlobalStructTy, n); - GlobalVariable *AllGlobals = new GlobalVariable( - M, ArrayOfGlobalStructTy, false, GlobalVariable::InternalLinkage, - ConstantArray::get(ArrayOfGlobalStructTy, Initializers), ""); + + GlobalVariable *AllGlobals = nullptr; + + // On Mach-O platforms, we emit the global metadata in a way that allows the + // linker to properly strip dead globals. + if (TargetTriple.isOSBinFormatMachO()) { + // We use AllGlobals as a dummy symbol which lets us look up the header + // of the library that contains it later. + AllGlobals = new GlobalVariable( + M, IntptrTy, false, GlobalVariable::InternalLinkage, + ConstantInt::get(IntptrTy, 0), ""); + + // We also emit a structure which binds the liveness of the global + // variable to the metadata struct. + StructType *LivenessTy = StructType::get(IntptrTy, IntptrTy, nullptr); + + for (size_t i = 0; i < n; i++) { + GlobalVariable *Metadata = new GlobalVariable( + M, GlobalStructTy, false, GlobalVariable::InternalLinkage, + Initializers[i], ""); + Metadata->setSection("__DATA,__asan_globals,regular"); + Metadata->setAlignment(1); // don't leave padding in between + + auto LivenessBinder = ConstantStruct::get(LivenessTy, + Initializers[i]->getAggregateElement(0u), + ConstantExpr::getPointerCast(Metadata, IntptrTy), + nullptr); + GlobalVariable *Liveness = new GlobalVariable( + M, LivenessTy, false, GlobalVariable::InternalLinkage, + LivenessBinder, ""); + Liveness->setSection("__DATA,__asan_liveness,regular,live_support"); + } + } else { + ArrayType *ArrayOfGlobalStructTy = ArrayType::get(GlobalStructTy, n); + AllGlobals = new GlobalVariable( + M, ArrayOfGlobalStructTy, false, GlobalVariable::InternalLinkage, + ConstantArray::get(ArrayOfGlobalStructTy, Initializers), ""); + } // Create calls for poisoning before initializers run and unpoisoning after. if (HasDynamicallyInitializedGlobals) createInitializerPoisonCalls(M, ModuleName); - IRB.CreateCall(AsanRegisterGlobals, - {IRB.CreatePointerCast(AllGlobals, IntptrTy), - ConstantInt::get(IntptrTy, n)}); + + if (TargetTriple.isOSBinFormatMachO()) { + IRB.CreateCall(AsanApplyToGlobals, + {IRB.CreatePointerCast(AsanRegisterGlobals, IntptrTy), + IRB.CreatePointerCast(AllGlobals, IntptrTy)}); + } else { + IRB.CreateCall(AsanRegisterGlobals, + {IRB.CreatePointerCast(AllGlobals, IntptrTy), + ConstantInt::get(IntptrTy, n)}); + } // We also need to unregister globals at the end, e.g. when a shared library // gets closed. @@ -1425,9 +1475,17 @@ GlobalValue::InternalLinkage, kAsanModuleDtorName, &M); BasicBlock *AsanDtorBB = BasicBlock::Create(*C, "", AsanDtorFunction); IRBuilder<> IRB_Dtor(ReturnInst::Create(*C, AsanDtorBB)); - IRB_Dtor.CreateCall(AsanUnregisterGlobals, - {IRB.CreatePointerCast(AllGlobals, IntptrTy), - ConstantInt::get(IntptrTy, n)}); + + if (TargetTriple.isOSBinFormatMachO()) { + IRB_Dtor.CreateCall(AsanApplyToGlobals, + {IRB.CreatePointerCast(AsanUnregisterGlobals, IntptrTy), + IRB.CreatePointerCast(AllGlobals, IntptrTy)}); + } else { + IRB_Dtor.CreateCall(AsanUnregisterGlobals, + {IRB.CreatePointerCast(AllGlobals, IntptrTy), + ConstantInt::get(IntptrTy, n)}); + } + appendToGlobalDtors(M, AsanDtorFunction, kAsanCtorAndDtorPriority); DEBUG(dbgs() << M); Index: lib/asan/asan_globals.cc =================================================================== --- lib/asan/asan_globals.cc +++ lib/asan/asan_globals.cc @@ -26,6 +26,12 @@ #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#if SANITIZER_MAC +#include +#include +#endif + + namespace __asan { typedef __asan_global Global; @@ -212,6 +218,35 @@ // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT + +#if SANITIZER_MAC +// Apply __asan_(un)register_globals to globals found listed in the +// __DATA,__asan_globals section. +void __asan_apply_to_globals(global_func func, void *canary) { + // Find the Mach-O header for the image containing the canary + Dl_info info; + int err = dladdr(canary, &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; + func(globals, size / sizeof(__asan_global)); +} +#endif + // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; Index: lib/asan/asan_interface_internal.h =================================================================== --- lib/asan/asan_interface_internal.h +++ lib/asan/asan_interface_internal.h @@ -56,6 +56,13 @@ // or NULL if it is unknown. }; + // This function can be called by instrumented code on Mach-O platforms. +#if SANITIZER_MAC + typedef void (*global_func)(__asan_global *, uptr); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_apply_to_globals(global_func foo, void *canary); +#endif + // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE