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"; @@ -96,7 +97,7 @@ static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init"; static const char *const kAsanInitName = "__asan_init"; static const char *const kAsanVersionCheckName = - "__asan_version_mismatch_check_v6"; + "__asan_version_mismatch_check_v7"; static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp"; static const char *const kAsanPtrSub = "__sanitizer_ptr_sub"; static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return"; @@ -109,6 +110,8 @@ "__asan_poison_stack_memory"; static const char *const kAsanUnpoisonStackMemoryName = "__asan_unpoison_stack_memory"; +static const char *const kAsanGlobalMetadataNeedleName = + "__asan_needle"; static const char *const kAsanOptionDetectUAR = "__asan_option_detect_stack_use_after_return"; @@ -546,6 +549,7 @@ Function *AsanUnpoisonGlobals; Function *AsanRegisterGlobals; Function *AsanUnregisterGlobals; + Function *AsanApplyToGlobals; }; // Stack poisoning does not play well with exception handling. @@ -1283,6 +1287,7 @@ void AddressSanitizerModule::initializeCallbacks(Module &M) { IRBuilder<> IRB(*C); + // Declare our poisoning and unpoisoning functions. AsanPoisonGlobals = checkSanitizerInterfaceFunction(M.getOrInsertFunction( kAsanPoisonGlobalsName, IRB.getVoidTy(), IntptrTy, nullptr)); @@ -1290,6 +1295,7 @@ AsanUnpoisonGlobals = checkSanitizerInterfaceFunction(M.getOrInsertFunction( kAsanUnpoisonGlobalsName, IRB.getVoidTy(), nullptr)); AsanUnpoisonGlobals->setLinkage(Function::ExternalLinkage); + // Declare functions that register/unregister globals. AsanRegisterGlobals = checkSanitizerInterfaceFunction(M.getOrInsertFunction( kAsanRegisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy, nullptr)); @@ -1298,6 +1304,13 @@ M.getOrInsertFunction(kAsanUnregisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy, nullptr)); AsanUnregisterGlobals->setLinkage(Function::ExternalLinkage); + + // Declare the function that finds globals in a shared object and then invokes + // the (un)register function on them. + 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 +1419,60 @@ 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; + GlobalVariable *Needle = 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 Needle as a dummy symbol which lets us look up the header of the + // loaded image that contains it. (We can't just use an existing global, + // since that might interfere with dead code stripping.) + Needle = new GlobalVariable( + M, IntptrTy, false, GlobalVariable::InternalLinkage, + ConstantInt::get(IntptrTy, 0), kAsanGlobalMetadataNeedleName); + + // 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(Needle, 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 +1481,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(Needle, IntptrTy)}); + } else { + IRB_Dtor.CreateCall(AsanUnregisterGlobals, + {IRB.CreatePointerCast(AllGlobals, IntptrTy), + ConstantInt::get(IntptrTy, n)}); + } + appendToGlobalDtors(M, AsanDtorFunction, kAsanCtorAndDtorPriority); DEBUG(dbgs() << M); Index: test/Instrumentation/AddressSanitizer/global_metadata.ll =================================================================== --- test/Instrumentation/AddressSanitizer/global_metadata.ll +++ test/Instrumentation/AddressSanitizer/global_metadata.ll @@ -20,7 +20,7 @@ ; CHECK: [[FILENAME:@__asan_gen_.[0-9]+]] = private unnamed_addr constant [22 x i8] c"/tmp/asan-globals.cpp\00", align 1 ; CHECK: [[LOCDESCR:@__asan_gen_.[0-9]+]] = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* [[FILENAME]], i32 5, i32 5 } -; Check that location decriptors and global names were passed into __asan_register_globals: +; Check that location descriptors and global names were passed into __asan_register_globals: ; CHECK: i64 ptrtoint ([7 x i8]* [[VARNAME]] to i64) ; CHECK: i64 ptrtoint ({ [22 x i8]*, i32, i32 }* [[LOCDESCR]] to i64) Index: test/Instrumentation/AddressSanitizer/global_metadata_darwin.ll =================================================================== --- /dev/null +++ test/Instrumentation/AddressSanitizer/global_metadata_darwin.ll @@ -0,0 +1,37 @@ +; Test that global metadata is placed in a separate section on Mach-O platforms, +; allowing dead stripping to be performed, and that the appropriate runtime +; routines are invoked. + +; RUN: opt < %s -asan -asan-module -S | FileCheck %s + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +@global = global [1 x i32] zeroinitializer, align 4 + +!llvm.asan.globals = !{!0} + +!0 = !{[1 x i32]* @global, !1, !"global", i1 false, i1 false} +!1 = !{!"test-globals.c", i32 1, i32 5} + + +; Test that there is a Needle global variable: +; CHECK: @__asan_needle = internal global i64 0 + +; Find the metadata for @global: +; CHECK: [[METADATA:@[0-9]+]] = internal global {{.*}} @global {{.*}} section "__DATA,__asan_globals,regular", align 1 + +; Find the liveness binder for @global and its metadata: +; CHECK: @{{[0-9]+}} = internal global {{.*}} @global {{.*}} [[METADATA]] {{.*}} section "__DATA,__asan_liveness,regular,live_support" + +; Test that __asan_apply_to_globals is invoked from the constructor: +; CHECK-LABEL: define internal void @asan.module_ctor +; CHECK-NOT: ret +; CHECK: call void @__asan_apply_to_globals(i64 ptrtoint (void (i64, i64)* @__asan_register_globals to i64), i64 ptrtoint (i64* @__asan_needle to i64)) +; CHECK: ret + +; Test that __asan_apply_to_globals is invoked from the destructor: +; CHECK-LABEL: define internal void @asan.module_dtor +; CHECK-NOT: ret +; CHECK: call void @__asan_apply_to_globals(i64 ptrtoint (void (i64, i64)* @__asan_unregister_globals to i64), i64 ptrtoint (i64* @__asan_needle to i64)) +; CHECK: ret