summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp2
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp58
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h3
-rw-r--r--clang/test/CodeGen/asan-globals.cpp23
-rw-r--r--clang/test/CodeGen/sanitize-init-order.cpp11
-rw-r--r--compiler-rt/lib/asan/asan_dll_thunk.cc8
-rw-r--r--compiler-rt/lib/asan/asan_interface_internal.h15
-rw-r--r--compiler-rt/lib/asan/asan_report.cc35
-rw-r--r--compiler-rt/test/asan/TestCases/global-location.cc38
-rw-r--r--llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp126
-rw-r--r--llvm/test/Instrumentation/AddressSanitizer/global_metadata.ll63
-rw-r--r--llvm/test/Instrumentation/AddressSanitizer/instrument_global.ll4
-rw-r--r--llvm/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll8
13 files changed, 334 insertions, 60 deletions
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index a28e7213771..9bd61d7164f 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -345,6 +345,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
DMEntry = castedAddr;
CGM.setStaticLocalDeclAddress(&D, castedAddr);
+ CGM.reportGlobalToASan(var, D.getLocation());
+
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
if (DI &&
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index d172b45c682..e088bd4e4fe 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1958,16 +1958,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
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 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
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 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment);
if (Entry)
Entry->setValue(GV);
+
+ reportGlobalToASan(GV, S->getStrTokenLoc(0));
return GV;
}
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index a4d398a2fa7..88f5faf7093 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1025,6 +1025,9 @@ public:
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);
}
diff --git a/clang/test/CodeGen/asan-globals.cpp b/clang/test/CodeGen/asan-globals.cpp
new file mode 100644
index 00000000000..996be2b95a2
--- /dev/null
+++ b/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}
diff --git a/clang/test/CodeGen/sanitize-init-order.cpp b/clang/test/CodeGen/sanitize-init-order.cpp
index dc8e8e2f9fa..8c662dbe034 100644
--- a/clang/test/CodeGen/sanitize-init-order.cpp
+++ b/clang/test/CodeGen/sanitize-init-order.cpp
@@ -27,7 +27,12 @@ PODWithCtorAndDtor s3;
// 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
+// 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-NOT: llvm.asan.dynamically_initialized_globals
+// 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}
diff --git a/compiler-rt/lib/asan/asan_dll_thunk.cc b/compiler-rt/lib/asan/asan_dll_thunk.cc
index aa27c404f4d..7b6ccc6a645 100644
--- a/compiler-rt/lib/asan/asan_dll_thunk.cc
+++ b/compiler-rt/lib/asan/asan_dll_thunk.cc
@@ -203,13 +203,13 @@ extern "C" {
// 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 @@ void InterceptHooks() {
// 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
diff --git a/compiler-rt/lib/asan/asan_interface_internal.h b/compiler-rt/lib/asan/asan_interface_internal.h
index 84525d090ac..6d95ad8199a 100644
--- a/compiler-rt/lib/asan/asan_interface_internal.h
+++ b/compiler-rt/lib/asan/asan_interface_internal.h
@@ -30,8 +30,17 @@ extern "C" {
// 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 @@ extern "C" {
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.
diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc
index 3b8fa3e800a..66329c07819 100644
--- a/compiler-rt/lib/asan/asan_report.cc
+++ b/compiler-rt/lib/asan/asan_report.cc
@@ -212,6 +212,26 @@ static void PrintGlobalNameIfASCII(InternalScopedString *str,
(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 @@ bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
// 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 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
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 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
}
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
diff --git a/compiler-rt/test/asan/TestCases/global-location.cc b/compiler-rt/test/asan/TestCases/global-location.cc
new file mode 100644
index 00000000000..4e386c98866
--- /dev/null
+++ b/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 <string.h>
+
+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
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index 6dbcde03cf2..290efe2ec00 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/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 @@ static const char *const kAsanUnregisterGlobalsName =
"__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 @@ STATISTIC(NumOptimizedAccessesToGlobalVar,
"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<GlobalVariable>(VG));
+ GlobalVariable *GV = cast<GlobalVariable>(V);
+ if (Value *Loc = MDN->getOperand(1)) {
+ GlobalVariable *GVLoc = cast<GlobalVariable>(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<ConstantInt>(MDN->getOperand(2));
+ if (IsDynInit->isOne())
+ DynInitGlobals.insert(GV);
+ ConstantInt *IsBlacklisted = cast<ConstantInt>(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<GlobalValue*, 32> DynInitGlobals;
+ bool inited_ = false;
+ DenseMap<GlobalVariable*, GlobalVariable*> SourceLocation;
+ DenseSet<GlobalVariable*> DynInitGlobals;
+ DenseSet<GlobalVariable*> BlacklistedGlobals;
+ DenseSet<GlobalVariable*> 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<ConstantStruct>(SourceLocGV->getInitializer());
+ GlobalVariable *FilenameGV = cast<GlobalVariable>(Contents->getOperand(0));
+ LocationGlobals.insert(FilenameGV);
+ }
};
/// This struct defines the shadow mapping using the rule:
@@ -351,7 +410,7 @@ struct AddressSanitizer : public FunctionPass {
*AsanMemoryAccessCallbackSized[2];
Function *AsanMemmove, *AsanMemcpy, *AsanMemset;
InlineAsm *EmptyAsm;
- SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals;
+ GlobalsMetadata GlobalsMD;
friend struct FunctionStackPoisoner;
};
@@ -381,7 +440,7 @@ class AddressSanitizerModule : public ModulePass {
SmallString<64> BlacklistFile;
std::unique_ptr<SpecialCaseList> BL;
- SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals;
+ GlobalsMetadata GlobalsMD;
Type *IntptrTy;
LLVMContext *C;
const DataLayout *DL;
@@ -659,7 +718,7 @@ bool AddressSanitizer::GlobalIsLinkerInitialized(GlobalVariable *G) {
// 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 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) {
Type *Ty = cast<PointerType>(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 @@ void AddressSanitizerModule::initializeCallbacks(Module &M) {
// 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<GlobalVariable *, 16> GlobalsToChange;
@@ -986,10 +1049,11 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
// 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<Constant *, 16> Initializers(n);
bool HasDynamicallyInitializedGlobals = false;
@@ -1017,9 +1081,6 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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 @@ bool AddressSanitizer::doInitialization(Module &M) {
report_fatal_error("data layout missing");
DL = &DLP->getDataLayout();
- DynamicallyInitializedGlobals.Init(M);
+ GlobalsMD.init(M);
C = &(M.getContext());
LongSize = DL->getPointerSizeInBits();
diff --git a/llvm/test/Instrumentation/AddressSanitizer/global_metadata.ll b/llvm/test/Instrumentation/AddressSanitizer/global_metadata.ll
new file mode 100644
index 00000000000..9641c3ed4d7
--- /dev/null
+++ b/llvm/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)"}
diff --git a/llvm/test/Instrumentation/AddressSanitizer/instrument_global.ll b/llvm/test/Instrumentation/AddressSanitizer/instrument_global.ll
index 7945e816ca3..816ab291566 100644
--- a/llvm/test/Instrumentation/AddressSanitizer/instrument_global.ll
+++ b/llvm/test/Instrumentation/AddressSanitizer/instrument_global.ll
@@ -68,8 +68,8 @@ entry:
}
-!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
diff --git a/llvm/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll b/llvm/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll
index 05e18b5a01b..83ff53f6f51 100644
--- a/llvm/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll
+++ b/llvm/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll
@@ -7,9 +7,11 @@ target triple = "x86_64-unknown-linux-gnu"
@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:
OpenPOWER on IntegriCloud