Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -16,6 +16,7 @@ #include "llvm/Transforms/Instrumentation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" @@ -79,7 +80,7 @@ "__asan_unregister_globals"; static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init"; static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init"; -static const char *const kAsanInitName = "__asan_init_v3"; +static const char *const kAsanInitName = "__asan_init_v4"; static const char *const kAsanCovModuleInitName = "__sanitizer_cov_module_init"; static const char *const kAsanCovName = "__sanitizer_cov"; static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp"; @@ -215,28 +216,86 @@ "Number of optimized accesses to global vars"); namespace { -/// A set of dynamically initialized globals extracted from metadata. -class SetOfDynamicallyInitializedGlobals { +/// Frontend-provided metadata for global variables. +class GlobalsMetadata { public: - void Init(Module& M) { - // Clang generates metadata identifying all dynamically initialized globals. - NamedMDNode *DynamicGlobals = - M.getNamedMetadata("llvm.asan.dynamically_initialized_globals"); - if (!DynamicGlobals) + void init(Module& M) { + assert(!inited_); + inited_ = true; + NamedMDNode *Globals = M.getNamedMetadata("llvm.asan.globals"); + if (!Globals) return; - for (const auto MDN : DynamicGlobals->operands()) { - 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) + for (auto MDN : Globals->operands()) { + // Format of the metadata node for the global: + // { + // global, + // source_location, + // i1 is_dynamically_initialized, + // i1 is_blacklisted + // } + assert(MDN->getNumOperands() == 4); + Value *V = MDN->getOperand(0); + // The optimizer may optimize away a global entirely. + if (!V) continue; - DynInitGlobals.insert(cast(VG)); + GlobalVariable *GV = cast(V); + if (Value *Loc = MDN->getOperand(1)) { + GlobalVariable *GVLoc = cast(Loc); + // We may already know the source location for GV, if it was merged + // with another global. + if (SourceLocation.insert(std::make_pair(GV, GVLoc)).second) + addSourceLocationGlobal(GVLoc); + } + ConstantInt *IsDynInit = cast(MDN->getOperand(2)); + if (IsDynInit->isOne()) + DynInitGlobals.insert(GV); + ConstantInt *IsBlacklisted = cast(MDN->getOperand(3)); + if (IsBlacklisted->isOne()) + BlacklistedGlobals.insert(GV); } } - bool Contains(GlobalVariable *G) { return DynInitGlobals.count(G) != 0; } + + GlobalVariable *getSourceLocation(GlobalVariable *G) const { + auto Pos = SourceLocation.find(G); + return (Pos != SourceLocation.end()) ? Pos->second : nullptr; + } + + /// Check if the global is dynamically initialized. + bool isDynInit(GlobalVariable *G) const { + return DynInitGlobals.count(G); + } + + /// Check if the global was blacklisted. + bool isBlacklisted(GlobalVariable *G) const { + return BlacklistedGlobals.count(G); + } + + /// Check if the global was generated to describe source location of another + /// global (we don't want to instrument them). + bool isSourceLocationGlobal(GlobalVariable *G) const { + return LocationGlobals.count(G); + } + private: - SmallSet DynInitGlobals; + bool inited_ = false; + DenseMap SourceLocation; + DenseSet DynInitGlobals; + DenseSet BlacklistedGlobals; + DenseSet LocationGlobals; + + void addSourceLocationGlobal(GlobalVariable *SourceLocGV) { + // Source location global is a struct with layout: + // { + // filename, + // i32 line_number, + // i32 column_number, + // } + LocationGlobals.insert(SourceLocGV); + ConstantStruct *Contents = + cast(SourceLocGV->getInitializer()); + GlobalVariable *FilenameGV = cast(Contents->getOperand(0)); + LocationGlobals.insert(FilenameGV); + } }; /// This struct defines the shadow mapping using the rule: @@ -351,7 +410,7 @@ *AsanMemoryAccessCallbackSized[2]; Function *AsanMemmove, *AsanMemcpy, *AsanMemset; InlineAsm *EmptyAsm; - SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals; + GlobalsMetadata GlobalsMD; friend struct FunctionStackPoisoner; }; @@ -381,7 +440,7 @@ SmallString<64> BlacklistFile; std::unique_ptr BL; - SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals; + GlobalsMetadata GlobalsMD; Type *IntptrTy; LLVMContext *C; const DataLayout *DL; @@ -659,7 +718,7 @@ // If a global variable does not have dynamic initialization we don't // have to instrument it. However, if a global does not have initializer // at all, we assume it has dynamic initializer (in other TU). - return G->hasInitializer() && !DynamicallyInitializedGlobals.Contains(G); + return G->hasInitializer() && !GlobalsMD.isDynInit(G); } void @@ -866,7 +925,11 @@ Type *Ty = cast(G->getType())->getElementType(); DEBUG(dbgs() << "GLOBAL: " << *G << "\n"); + // FIXME: Don't use the blacklist here, all the data should be collected + // by the frontend and passed in globals metadata. if (BL->isIn(*G)) return false; + if (GlobalsMD.isBlacklisted(G)) return false; + if (GlobalsMD.isSourceLocationGlobal(G)) return false; if (!Ty->isSized()) return false; if (!G->hasInitializer()) return false; if (GlobalWasGeneratedByAsan(G)) return false; // Our own global. @@ -967,7 +1030,7 @@ // trailing redzones. It also creates a function that poisons // redzones and inserts this function into llvm.global_ctors. bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) { - DynamicallyInitializedGlobals.Init(M); + GlobalsMD.init(M); SmallVector GlobalsToChange; @@ -986,10 +1049,11 @@ // const char *name; // const char *module_name; // size_t has_dynamic_init; + // void *source_location; // We initialize an array of such structures and pass it to a run-time call. - StructType *GlobalStructTy = StructType::get(IntptrTy, IntptrTy, - IntptrTy, IntptrTy, - IntptrTy, IntptrTy, NULL); + StructType *GlobalStructTy = + StructType::get(IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy, + IntptrTy, IntptrTy, NULL); SmallVector Initializers(n); bool HasDynamicallyInitializedGlobals = false; @@ -1017,9 +1081,6 @@ RightRedzoneSize += MinRZ - (SizeInBytes % MinRZ); assert(((RightRedzoneSize + SizeInBytes) % MinRZ) == 0); Type *RightRedZoneTy = ArrayType::get(IRB.getInt8Ty(), RightRedzoneSize); - // Determine whether this global should be poisoned in initialization. - bool GlobalHasDynamicInitializer = - DynamicallyInitializedGlobals.Contains(G); StructType *NewTy = StructType::get(Ty, RightRedZoneTy, NULL); Constant *NewInitializer = ConstantStruct::get( @@ -1048,17 +1109,20 @@ NewGlobal->takeName(G); G->eraseFromParent(); + bool GlobalHasDynamicInitializer = GlobalsMD.isDynInit(G); + GlobalVariable *SourceLoc = GlobalsMD.getSourceLocation(G); + Initializers[i] = ConstantStruct::get( - GlobalStructTy, - ConstantExpr::getPointerCast(NewGlobal, IntptrTy), + GlobalStructTy, ConstantExpr::getPointerCast(NewGlobal, IntptrTy), ConstantInt::get(IntptrTy, SizeInBytes), ConstantInt::get(IntptrTy, SizeInBytes + RightRedzoneSize), ConstantExpr::getPointerCast(Name, IntptrTy), ConstantExpr::getPointerCast(ModuleName, IntptrTy), ConstantInt::get(IntptrTy, GlobalHasDynamicInitializer), + SourceLoc ? ConstantExpr::getPointerCast(SourceLoc, IntptrTy) + : ConstantInt::get(IntptrTy, 0), NULL); - // Populate the first and last globals declared in this TU. if (ClInitializers && GlobalHasDynamicInitializer) HasDynamicallyInitializedGlobals = true; @@ -1186,7 +1250,7 @@ report_fatal_error("data layout missing"); DL = &DLP->getDataLayout(); - DynamicallyInitializedGlobals.Init(M); + GlobalsMD.init(M); C = &(M.getContext()); LongSize = DL->getPointerSizeInBits(); Index: projects/compiler-rt/lib/asan/asan_dll_thunk.cc =================================================================== --- projects/compiler-rt/lib/asan/asan_dll_thunk.cc +++ projects/compiler-rt/lib/asan/asan_dll_thunk.cc @@ -203,13 +203,13 @@ // Manually wrap __asan_init as we need to initialize // __asan_option_detect_stack_use_after_return afterwards. - void __asan_init_v3() { + void __asan_init_v4() { typedef void (*fntype)(); static fntype fn = 0; - // __asan_init_v3 is expected to be called by only one thread. + // __asan_init_v4 is expected to be called by only one thread. if (fn) return; - fn = (fntype)getRealProcAddressOrDie("__asan_init_v3"); + fn = (fntype)getRealProcAddressOrDie("__asan_init_v4"); fn(); __asan_option_detect_stack_use_after_return = (__asan_should_detect_stack_use_after_return() != 0); @@ -339,7 +339,7 @@ // In DLLs, the callbacks are expected to return 0, // otherwise CRT initialization fails. static int call_asan_init() { - __asan_init_v3(); + __asan_init_v4(); return 0; } #pragma section(".CRT$XIB", long, read) // NOLINT Index: projects/compiler-rt/lib/asan/asan_interface_internal.h =================================================================== --- projects/compiler-rt/lib/asan/asan_interface_internal.h +++ projects/compiler-rt/lib/asan/asan_interface_internal.h @@ -30,8 +30,17 @@ // v2=>v3: stack frame description (created by the compiler) // contains the function PC as the 3-rd field (see // DescribeAddressIfStack). - SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3(); - #define __asan_init __asan_init_v3 + // v3=>v4: added '__asan_global_source_location' to __asan_global. + SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v4(); + #define __asan_init __asan_init_v4 + + // This structure is used to describe the source location of a place where + // global was defined. + struct __asan_global_source_location { + const char *filename; + int line_no; + int column_no; + }; // This structure describes an instrumented global variable. struct __asan_global { @@ -42,6 +51,8 @@ const char *module_name; // Module name as a C string. This pointer is a // unique identifier of a module. uptr has_dynamic_init; // Non-zero if the global has dynamic initializer. + __asan_global_source_location *location; // Source location of a global, + // or NULL if it is unknown. }; // These two functions should be called by the instrumented code. Index: projects/compiler-rt/lib/asan/asan_report.cc =================================================================== --- projects/compiler-rt/lib/asan/asan_report.cc +++ projects/compiler-rt/lib/asan/asan_report.cc @@ -212,6 +212,26 @@ (char *)g.beg); } +static const char *GlobalFilename(const __asan_global &g) { + const char *res = g.module_name; + // Prefer the filename from source location, if is available. + if (g.location) + res = g.location->filename; + CHECK(res); + return res; +} + +static void PrintGlobalLocation(InternalScopedString *str, + const __asan_global &g) { + str->append("%s", GlobalFilename(g)); + if (!g.location) + return; + if (g.location->line_no) + str->append(":%d", g.location->line_no); + if (g.location->column_no) + str->append(":%d", g.location->column_no); +} + bool DescribeAddressRelativeToGlobal(uptr addr, uptr size, const __asan_global &g) { static const uptr kMinimalDistanceFromAnotherGlobal = 64; @@ -232,8 +252,10 @@ // Can it happen? str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg); } - str.append(" of global variable '%s' from '%s' (0x%zx) of size %zu\n", - MaybeDemangleGlobalName(g.name), g.module_name, g.beg, g.size); + str.append(" of global variable '%s' defined in '", + MaybeDemangleGlobalName(g.name)); + PrintGlobalLocation(&str, g); + str.append("' (0x%zx) of size %zu\n", g.beg, g.size); str.append("%s", d.EndLocation()); PrintGlobalNameIfASCII(&str, g); Printf("%s", str.data()); @@ -742,8 +764,11 @@ Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg); Printf("%s", d.EndWarning()); - Printf(" [1] size=%zd %s %s\n", g1->size, g1->name, g1->module_name); - Printf(" [2] size=%zd %s %s\n", g2->size, g2->name, g2->module_name); + InternalScopedString g1_loc(256), g2_loc(256); + PrintGlobalLocation(&g1_loc, *g1); + PrintGlobalLocation(&g2_loc, *g2); + Printf(" [1] size=%zd %s %s\n", g1->size, g1->name, g1_loc.data()); + Printf(" [2] size=%zd %s %s\n", g2->size, g2->name, g2_loc.data()); if (stack_id1 && stack_id2) { Printf("These globals were registered at these points:\n"); Printf(" [1]:\n"); @@ -756,7 +781,7 @@ } Report("HINT: if you don't care about these warnings you may set " "ASAN_OPTIONS=detect_odr_violation=0\n"); - ReportErrorSummary("odr-violation", g1->module_name, 0, g1->name); + ReportErrorSummary("odr-violation", g1_loc.data(), 0, g1->name); } // ----------------------- CheckForInvalidPointerPair ----------- {{{1 Index: projects/compiler-rt/test/asan/TestCases/global-location.cc =================================================================== --- /dev/null +++ projects/compiler-rt/test/asan/TestCases/global-location.cc @@ -0,0 +1,38 @@ +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t g 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=GLOB +// RUN: not %run %t c 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CLASS_STATIC +// RUN: not %run %t f 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=FUNC_STATIC +// RUN: not %run %t l 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=LITERAL + +// CHECK: AddressSanitizer: global-buffer-overflow + +#include + +struct C { + static int array[10]; +}; + +int global[10]; +// GLOB: 0x{{.*}} is located 4 bytes to the right of global variable 'global' defined in '{{.*}}global-location.cc:[[@LINE-1]]:5' {{.*}} of size 40 +int C::array[10]; +// CLASS_STATIC: 0x{{.*}} is located 4 bytes to the right of global variable 'C::array' defined in '{{.*}}global-location.cc:[[@LINE-1]]:8' {{.*}} of size 40 + +int main(int argc, char **argv) { + int one = argc - 1; + switch (argv[1][0]) { + case 'g': return global[one * 11]; + case 'c': return C::array[one * 11]; + case 'f': + static int array[10]; + // FUNC_STATIC: 0x{{.*}} is located 4 bytes to the right of global variable 'main::array' defined in '{{.*}}global-location.cc:[[@LINE-1]]:16' {{.*}} of size 40 + memset(array, 0, 10); + return array[one * 11]; + case 'l': + const char *str = "0123456789"; + // LITERAL: 0x{{.*}} is located 0 bytes to the right of global variable {{.*}} defined in '{{.*}}global-location.cc:[[@LINE-1]]:23' {{.*}} of size 11 + return str[one * 11]; + } + return 0; +} + +// CHECK: SUMMARY: AddressSanitizer: global-buffer-overflow Index: test/Instrumentation/AddressSanitizer/global_metadata.ll =================================================================== --- /dev/null +++ test/Instrumentation/AddressSanitizer/global_metadata.ll @@ -0,0 +1,63 @@ +; RUN: opt < %s -asan -asan-module -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Globals: +@global = global i32 0, align 4 +@dyn_init_global = global i32 0, align 4 +@blacklisted_global = global i32 0, align 4 +@_ZZ4funcvE10static_var = internal global i32 0, align 4 +@.str = private unnamed_addr constant [14 x i8] c"Hello, world!\00", align 1 +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_asan_globals.cpp, i8* null }] + +; Sanitizer location descriptors: +@.str1 = private unnamed_addr constant [22 x i8] c"/tmp/asan-globals.cpp\00", align 1 +@.asan_loc_descr = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 5, i32 5 } +@.asan_loc_descr1 = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 7, i32 5 } +@.asan_loc_descr2 = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 12, i32 14 } +@.asan_loc_descr4 = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 14, i32 25 } + +; Check that globals were instrumented, but sanitizer location descriptors weren't: +; CHECK: @global = global { i32, [60 x i8] } zeroinitializer, align 32 +; CHECK: @.str = internal unnamed_addr constant { [14 x i8], [50 x i8] } { [14 x i8] c"Hello, world!\00", [50 x i8] zeroinitializer }, align 32 +; CHECK: @.asan_loc_descr = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 5, i32 5 } + +; Check that location decriptors were passed into __asan_register_globals: +; CHECK: i64 ptrtoint ({ [22 x i8]*, i32, i32 }* @.asan_loc_descr to i64) + +; Function Attrs: nounwind sanitize_address +define internal void @__cxx_global_var_init() #0 section ".text.startup" { +entry: + %0 = load i32* @global, align 4 + store i32 %0, i32* @dyn_init_global, align 4 + ret void +} + +; Function Attrs: nounwind sanitize_address +define void @_Z4funcv() #1 { +entry: + %literal = alloca i8*, align 8 + store i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0), i8** %literal, align 8 + ret void +} + +; Function Attrs: nounwind sanitize_address +define internal void @_GLOBAL__sub_I_asan_globals.cpp() #0 section ".text.startup" { +entry: + call void @__cxx_global_var_init() + ret void +} + +attributes #0 = { nounwind sanitize_address } +attributes #1 = { nounwind sanitize_address "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.asan.globals = !{!0, !1, !2, !3, !4} +!llvm.ident = !{!5} + +!0 = metadata !{i32* @global, { [22 x i8]*, i32, i32 }* @.asan_loc_descr, i1 false, i1 false} +!1 = metadata !{i32* @dyn_init_global, { [22 x i8]*, i32, i32 }* @.asan_loc_descr1, i1 true, i1 false} +!2 = metadata !{i32* @blacklisted_global, null, i1 false, i1 true} +!3 = metadata !{i32* @_ZZ4funcvE10static_var, { [22 x i8]*, i32, i32 }* @.asan_loc_descr2, i1 false, i1 false} +!4 = metadata !{[14 x i8]* @.str, { [22 x i8]*, i32, i32 }* @.asan_loc_descr4, i1 false, i1 false} +!5 = metadata !{metadata !"clang version 3.5.0 (211282)"} Index: test/Instrumentation/AddressSanitizer/instrument_global.ll =================================================================== --- test/Instrumentation/AddressSanitizer/instrument_global.ll +++ test/Instrumentation/AddressSanitizer/instrument_global.ll @@ -68,8 +68,8 @@ } -!llvm.asan.dynamically_initialized_globals = !{!0} -!0 = metadata !{[10 x i32]* @GlobDy} +!llvm.asan.globals = !{!0} +!0 = metadata !{[10 x i32]* @GlobDy, null, i1 true, i1 false} ; CHECK-LABEL: define internal void @asan.module_ctor ; CHECK-NOT: ret Index: test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll =================================================================== --- test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll +++ test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll @@ -7,9 +7,11 @@ @YYY = global i32 0, align 4 ; W/o dynamic initializer. ; Clang will emit the following metadata identifying @xxx as dynamically ; initialized. -!0 = metadata !{i32* @xxx} -!1 = metadata !{i32* @XXX} -!llvm.asan.dynamically_initialized_globals = !{!0, !1} +!0 = metadata !{i32* @xxx, null, i1 true, i1 false} +!1 = metadata !{i32* @XXX, null, i1 true, i1 false} +!2 = metadata !{i32* @yyy, null, i1 false, i1 false} +!3 = metadata !{i32* @YYY, null, i1 false, i1 false} +!llvm.asan.globals = !{!0, !1, !2, !3} define i32 @initializer() uwtable { entry: Index: tools/clang/lib/CodeGen/CGDecl.cpp =================================================================== --- tools/clang/lib/CodeGen/CGDecl.cpp +++ tools/clang/lib/CodeGen/CGDecl.cpp @@ -345,6 +345,8 @@ DMEntry = castedAddr; CGM.setStaticLocalDeclAddress(&D, castedAddr); + CGM.reportGlobalToASan(var, D.getLocation()); + // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); if (DI && Index: tools/clang/lib/CodeGen/CodeGenModule.h =================================================================== --- tools/clang/lib/CodeGen/CodeGenModule.h +++ tools/clang/lib/CodeGen/CodeGenModule.h @@ -1025,6 +1025,9 @@ const SanitizerOptions &getSanOpts() const { return SanOpts; } + void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc, + bool IsDynInit = false); + void addDeferredVTable(const CXXRecordDecl *RD) { DeferredVTables.push_back(RD); } Index: tools/clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- tools/clang/lib/CodeGen/CodeGenModule.cpp +++ tools/clang/lib/CodeGen/CodeGenModule.cpp @@ -1958,16 +1958,7 @@ if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); - // If we are compiling with ASan, add metadata indicating dynamically - // initialized (and not blacklisted) globals. - if (SanOpts.Address && NeedsGlobalCtor && - !SanitizerBlacklist->isIn(*GV, "init")) { - llvm::NamedMDNode *DynamicInitializers = TheModule.getOrInsertNamedMetadata( - "llvm.asan.dynamically_initialized_globals"); - llvm::Value *GlobalToAdd[] = { GV }; - llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalToAdd); - DynamicInitializers->addOperand(ThisGlobal); - } + reportGlobalToASan(GV, D->getLocation(), NeedsGlobalCtor); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) @@ -1975,6 +1966,51 @@ DI->EmitGlobalVariable(GV, D); } +void CodeGenModule::reportGlobalToASan(llvm::GlobalVariable *GV, + SourceLocation Loc, bool IsDynInit) { + if (!SanOpts.Address) + return; + IsDynInit &= !SanitizerBlacklist->isIn(*GV, "init"); + bool IsBlacklisted = SanitizerBlacklist->isIn(*GV); + + llvm::LLVMContext &LLVMCtx = TheModule.getContext(); + + llvm::GlobalVariable *LocDescr = nullptr; + if (!IsBlacklisted) { + // Don't generate source location if a global is blacklisted - it won't + // be instrumented anyway. + PresumedLoc PLoc = Context.getSourceManager().getPresumedLoc(Loc); + if (PLoc.isValid()) { + llvm::Constant *LocData[] = { + GetAddrOfConstantCString(PLoc.getFilename()), + llvm::ConstantInt::get(llvm::Type::getInt32Ty(LLVMCtx), PLoc.getLine()), + llvm::ConstantInt::get(llvm::Type::getInt32Ty(LLVMCtx), + PLoc.getColumn()), + }; + auto LocStruct = llvm::ConstantStruct::getAnon(LocData); + LocDescr = new llvm::GlobalVariable(TheModule, LocStruct->getType(), true, + llvm::GlobalValue::PrivateLinkage, + LocStruct, ".asan_loc_descr"); + LocDescr->setUnnamedAddr(true); + // Add LocDescr to llvm.compiler.used, so that it won't be removed by + // the optimizer before the ASan instrumentation pass. + addCompilerUsedGlobal(LocDescr); + } + } + + llvm::Value *GlobalMetadata[] = { + GV, + LocDescr, + llvm::ConstantInt::get(llvm::Type::getInt1Ty(LLVMCtx), IsDynInit), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(LLVMCtx), IsBlacklisted) + }; + + llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalMetadata); + llvm::NamedMDNode *AsanGlobals = + TheModule.getOrInsertNamedMetadata("llvm.asan.globals"); + AsanGlobals->addOperand(ThisGlobal); +} + static bool isVarDeclStrongDefinition(const VarDecl *D, bool NoCommon) { // Don't give variables common linkage if -fno-common was specified unless it // was overridden by a NoCommon attribute. @@ -2779,6 +2815,8 @@ auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment); if (Entry) Entry->setValue(GV); + + reportGlobalToASan(GV, S->getStrTokenLoc(0)); return GV; } Index: tools/clang/test/CodeGen/asan-globals.cpp =================================================================== --- /dev/null +++ tools/clang/test/CodeGen/asan-globals.cpp @@ -0,0 +1,23 @@ +// RUN: echo "global:*blacklisted_global*" > %t.blacklist +// RUN: %clang_cc1 -fsanitize=address -fsanitize-blacklist=%t.blacklist -emit-llvm -o - %s | FileCheck %s +// REQUIRES: shell + +int global; +// CHECK: [[GLOBAL_LOC:@.asan_loc_descr[0-9]*]] = private unnamed_addr constant {{.*}} i32 [[@LINE-1]], i32 5 +int dyn_init_global = global; +// CHECK: [[DYN_INIT_LOC:@.asan_loc_descr[0-9]*]] = {{.*}} i32 [[@LINE-1]], i32 5 +int blacklisted_global; + +void func() { + static int static_var = 0; + // CHECK: [[STATIC_LOC:@.asan_loc_descr[0-9]*]] = {{.*}} i32 [[@LINE-1]], i32 14 + const char *literal = "Hello, world!"; + // CHECK: [[LITERAL_LOC:@.asan_loc_descr[0-9]*]] = {{.*}} i32 [[@LINE-1]], i32 25 +} + +// CHECK: !llvm.asan.globals = !{![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} +// CHECK: ![[GLOBAL]] = metadata !{{{.*}} [[GLOBAL_LOC]], i1 false, i1 false} +// CHECK: ![[DYN_INIT_GLOBAL]] = metadata !{{{.*}} [[DYN_INIT_LOC]], i1 true, i1 false} +// CHECK: ![[BLACKLISTED_GLOBAL]] = metadata !{{{.*}}, null, i1 false, i1 true} +// CHECK: ![[STATIC_VAR]] = metadata !{{{.*}} [[STATIC_LOC]], i1 false, i1 false} +// CHECK: ![[LITERAL]] = metadata !{{{.*}} [[LITERAL_LOC]], i1 false, i1 false} Index: tools/clang/test/CodeGen/sanitize-init-order.cpp =================================================================== --- tools/clang/test/CodeGen/sanitize-init-order.cpp +++ tools/clang/test/CodeGen/sanitize-init-order.cpp @@ -27,7 +27,12 @@ // Check that ASan init-order checking ignores structs with trivial default // constructor. -// CHECK: !llvm.asan.dynamically_initialized_globals = !{[[GLOB:![0-9]+]]} -// CHECK: [[GLOB]] = metadata !{%struct.PODWithCtorAndDtor - -// BLACKLIST-NOT: llvm.asan.dynamically_initialized_globals +// CHECK: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]]]} +// CHECK: ![[GLOB_1]] = metadata !{%struct.PODStruct* {{.*}}, i1 false, i1 false} +// CHECK: ![[GLOB_2]] = metadata !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false} +// CHECK: ![[GLOB_3]] = metadata !{%struct.PODWithCtorAndDtor* {{.*}}, i1 true, i1 false} + +// BLACKLIST: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]]]} +// BLACKLIST: ![[GLOB_1]] = metadata !{%struct.PODStruct* {{.*}}, i1 false, i1 false} +// BLACKLIST: ![[GLOB_2]] = metadata !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false} +// BLACKLIST: ![[GLOB_3]] = metadata !{%struct.PODWithCtorAndDtor* {{.*}}, i1 false, i1 false}