From ca23d43084c45a7d6f4371d62f45be044650ce38 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 20 Nov 2012 13:00:01 +0000 Subject: [PATCH] [asan] make sure that linker-initialized globals (non-extern) are not instrumented even in -asan-initialization-order mode. This time with a test git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168366 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Instrumentation/AddressSanitizer.cpp | 62 +++++++++---------- .../instrument_initializer_metadata.ll | 21 ++++++- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index b7be4625ca8..aad31b4c6ed 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -148,6 +148,32 @@ static cl::opt ClDebugMax("asan-debug-max", cl::desc("Debug man inst"), cl::Hidden, cl::init(-1)); namespace { +/// A set of dynamically initialized globals extracted from metadata. +class SetOfDynamicallyInitializedGlobals { + public: + void Init(Module& M) { + // Clang generates metadata identifying all dynamically initialized globals. + NamedMDNode *DynamicGlobals = + M.getNamedMetadata("llvm.asan.dynamically_initialized_globals"); + if (!DynamicGlobals) + return; + for (int i = 0, n = DynamicGlobals->getNumOperands(); i < n; ++i) { + MDNode *MDN = DynamicGlobals->getOperand(i); + assert(MDN->getNumOperands() == 1); + Value *VG = MDN->getOperand(0); + // The optimizer may optimize away a global entirely, in which case we + // cannot instrument access to it. + if (!VG) + continue; + DynInitGlobals.insert(cast(VG)); + } + } + bool Contains(GlobalVariable *G) { return DynInitGlobals.count(G) != 0; } + private: + SmallSet DynInitGlobals; +}; + + /// AddressSanitizer: instrument the code in module to find memory bugs. struct AddressSanitizer : public FunctionPass { AddressSanitizer(); @@ -195,7 +221,6 @@ struct AddressSanitizer : public FunctionPass { Value *ShadowBase, bool DoPoison); bool LooksLikeCodeInBug11395(Instruction *I); void FindDynamicInitializers(Module &M); - bool HasDynamicInitializer(GlobalVariable *G); LLVMContext *C; DataLayout *TD; @@ -214,8 +239,8 @@ struct AddressSanitizer : public FunctionPass { // This array is indexed by AccessIsWrite and log2(AccessSize). Function *AsanErrorCallback[2][kNumberOfAccessSizes]; InlineAsm *EmptyAsm; - SmallSet DynamicallyInitializedGlobals; SmallSet GlobalsCreatedByAsan; + SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals; }; } // namespace @@ -328,30 +353,6 @@ static Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite) { return NULL; } -void AddressSanitizer::FindDynamicInitializers(Module& M) { - // Clang generates metadata identifying all dynamically initialized globals. - NamedMDNode *DynamicGlobals = - M.getNamedMetadata("llvm.asan.dynamically_initialized_globals"); - if (!DynamicGlobals) - return; - for (int i = 0, n = DynamicGlobals->getNumOperands(); i < n; ++i) { - MDNode *MDN = DynamicGlobals->getOperand(i); - assert(MDN->getNumOperands() == 1); - Value *VG = MDN->getOperand(0); - // The optimizer may optimize away a global entirely, in which case we - // cannot instrument access to it. - if (!VG) - continue; - - GlobalVariable *G = cast(VG); - DynamicallyInitializedGlobals.insert(G); - } -} -// Returns true if a global variable is initialized dynamically in this TU. -bool AddressSanitizer::HasDynamicInitializer(GlobalVariable *G) { - return DynamicallyInitializedGlobals.count(G); -} - void AddressSanitizer::instrumentMop(Instruction *I) { bool IsWrite = false; Value *Addr = isInterestingMemoryAccess(I, &IsWrite); @@ -367,7 +368,7 @@ void AddressSanitizer::instrumentMop(Instruction *I) { // assume it has dynamic initialization, as it may have an initializer // in a different TU. if (G->getLinkage() != GlobalVariable::ExternalLinkage && - !HasDynamicInitializer(G)) + !DynamicallyInitializedGlobals.Contains(G)) return; } } @@ -590,9 +591,6 @@ bool AddressSanitizer::insertGlobalRedzones(Module &M) { IRBuilder<> IRB(CtorInsertBefore); - if (ClInitializers) - FindDynamicInitializers(M); - // The addresses of the first and last dynamically initialized globals in // this TU. Used in initialization order checking. Value *FirstDynamic = 0, *LastDynamic = 0; @@ -606,7 +604,8 @@ bool AddressSanitizer::insertGlobalRedzones(Module &M) { (RedzoneSize - (SizeInBytes % RedzoneSize)); Type *RightRedZoneTy = ArrayType::get(IRB.getInt8Ty(), RightRedzoneSize); // Determine whether this global should be poisoned in initialization. - bool GlobalHasDynamicInitializer = HasDynamicInitializer(G); + bool GlobalHasDynamicInitializer = + DynamicallyInitializedGlobals.Contains(G); // Don't check initialization order if this global is blacklisted. GlobalHasDynamicInitializer &= !BL->isInInit(*G); @@ -704,6 +703,7 @@ bool AddressSanitizer::doInitialization(Module &M) { if (!TD) return false; BL.reset(new BlackList(ClBlackListFile)); + DynamicallyInitializedGlobals.Init(M); C = &(M.getContext()); LongSize = TD->getPointerSizeInBits(); diff --git a/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll b/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll index 472551654e5..fe13cd1b4e5 100644 --- a/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll +++ b/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll @@ -1,7 +1,8 @@ ; RUN: opt < %s -asan -asan-initialization-order -S | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-unknown-linux-gnu" -@xxx = global i32 0, align 4 +@xxx = internal global i32 0, align 4 ; With dynamic initializer. +@yyy = internal global i32 0, align 4 ; W/o dynamic initializer. ; Clang will emit the following metadata identifying @xxx as dynamically ; initialized. !0 = metadata !{i32* @xxx} @@ -34,3 +35,21 @@ entry: ; CHECK: call void @__cxx_global_var_init ; CHECK: call void @__asan_after_dynamic_init ; CHECK: ret + +; Check that xxx is instrumented. +define void @touch_xxx() address_safety { + store i32 0, i32 *@xxx, align 4 + ret void +; CHECK: define void @touch_xxx +; CHECK: call void @__asan_report_store4 +; CHECK: ret void +} + +; Check that yyy is NOT instrumented (as it does not have dynamic initializer). +define void @touch_yyy() address_safety { + store i32 0, i32 *@yyy, align 4 + ret void +; CHECK: define void @touch_yyy +; CHECK-NOT: call void @__asan_report_store4 +; CHECK: ret void +}