llvm.org GIT mirror llvm / 1b6333c
[ASan] Print exact source location of global variables in error reports. See https://code.google.com/p/address-sanitizer/issues/detail?id=299 for the original feature request. Introduce llvm.asan.globals metadata, which Clang (or any other frontend) may use to report extra information about global variables to ASan instrumentation pass in the backend. This metadata replaces llvm.asan.dynamically_initialized_globals that was used to detect init-order bugs. llvm.asan.globals contains the following data for each global: 1) source location (file/line/column info); 2) whether it is dynamically initialized; 3) whether it is blacklisted (shouldn't be instrumented). Source location data is then emitted in the binary and can be picked up by ASan runtime in case it needs to print error report involving some global. For example: 0x... is located 4 bytes to the right of global variable 'C::array' defined in '/path/to/file:17:8' (0x...) of size 40 These source locations are printed even if the binary doesn't have any debug info. This is an ABI-breaking change. ASan initialization is renamed to __asan_init_v4(). Pre-built libraries compiled with older Clang will not work with the fresh runtime. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212188 91177308-0d34-0410-b5e6-96231b3b80d8 Alexey Samsonov 5 years ago
4 changed file(s) with 165 addition(s) and 36 deletion(s). Raw diff Collapse all Expand all
1515 #include "llvm/Transforms/Instrumentation.h"
1616 #include "llvm/ADT/ArrayRef.h"
1717 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/DenseSet.h"
1819 #include "llvm/ADT/DepthFirstIterator.h"
1920 #include "llvm/ADT/SmallSet.h"
2021 #include "llvm/ADT/SmallString.h"
7879 "__asan_unregister_globals";
7980 static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
8081 static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
81 static const char *const kAsanInitName = "__asan_init_v3";
82 static const char *const kAsanInitName = "__asan_init_v4";
8283 static const char *const kAsanCovModuleInitName = "__sanitizer_cov_module_init";
8384 static const char *const kAsanCovName = "__sanitizer_cov";
8485 static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp";
214215 "Number of optimized accesses to global vars");
215216
216217 namespace {
217 /// A set of dynamically initialized globals extracted from metadata.
218 class SetOfDynamicallyInitializedGlobals {
218 /// Frontend-provided metadata for global variables.
219 class GlobalsMetadata {
219220 public:
220 void Init(Module& M) {
221 // Clang generates metadata identifying all dynamically initialized globals.
222 NamedMDNode *DynamicGlobals =
223 M.getNamedMetadata("llvm.asan.dynamically_initialized_globals");
224 if (!DynamicGlobals)
221 void init(Module& M) {
222 assert(!inited_);
223 inited_ = true;
224 NamedMDNode *Globals = M.getNamedMetadata("llvm.asan.globals");
225 if (!Globals)
225226 return;
226 for (const auto MDN : DynamicGlobals->operands()) {
227 assert(MDN->getNumOperands() == 1);
228 Value *VG = MDN->getOperand(0);
229 // The optimizer may optimize away a global entirely, in which case we
230 // cannot instrument access to it.
231 if (!VG)
227 for (auto MDN : Globals->operands()) {
228 // Format of the metadata node for the global:
229 // {
230 // global,
231 // source_location,
232 // i1 is_dynamically_initialized,
233 // i1 is_blacklisted
234 // }
235 assert(MDN->getNumOperands() == 4);
236 Value *V = MDN->getOperand(0);
237 // The optimizer may optimize away a global entirely.
238 if (!V)
232239 continue;
233 DynInitGlobals.insert(cast(VG));
240 GlobalVariable *GV = cast(V);
241 if (Value *Loc = MDN->getOperand(1)) {
242 GlobalVariable *GVLoc = cast(Loc);
243 // We may already know the source location for GV, if it was merged
244 // with another global.
245 if (SourceLocation.insert(std::make_pair(GV, GVLoc)).second)
246 addSourceLocationGlobal(GVLoc);
247 }
248 ConstantInt *IsDynInit = cast(MDN->getOperand(2));
249 if (IsDynInit->isOne())
250 DynInitGlobals.insert(GV);
251 ConstantInt *IsBlacklisted = cast(MDN->getOperand(3));
252 if (IsBlacklisted->isOne())
253 BlacklistedGlobals.insert(GV);
234254 }
235255 }
236 bool Contains(GlobalVariable *G) { return DynInitGlobals.count(G) != 0; }
256
257 GlobalVariable *getSourceLocation(GlobalVariable *G) const {
258 auto Pos = SourceLocation.find(G);
259 return (Pos != SourceLocation.end()) ? Pos->second : nullptr;
260 }
261
262 /// Check if the global is dynamically initialized.
263 bool isDynInit(GlobalVariable *G) const {
264 return DynInitGlobals.count(G);
265 }
266
267 /// Check if the global was blacklisted.
268 bool isBlacklisted(GlobalVariable *G) const {
269 return BlacklistedGlobals.count(G);
270 }
271
272 /// Check if the global was generated to describe source location of another
273 /// global (we don't want to instrument them).
274 bool isSourceLocationGlobal(GlobalVariable *G) const {
275 return LocationGlobals.count(G);
276 }
277
237278 private:
238 SmallSet DynInitGlobals;
279 bool inited_ = false;
280 DenseMap SourceLocation;
281 DenseSet DynInitGlobals;
282 DenseSet BlacklistedGlobals;
283 DenseSet LocationGlobals;
284
285 void addSourceLocationGlobal(GlobalVariable *SourceLocGV) {
286 // Source location global is a struct with layout:
287 // {
288 // filename,
289 // i32 line_number,
290 // i32 column_number,
291 // }
292 LocationGlobals.insert(SourceLocGV);
293 ConstantStruct *Contents =
294 cast(SourceLocGV->getInitializer());
295 GlobalVariable *FilenameGV = cast(Contents->getOperand(0));
296 LocationGlobals.insert(FilenameGV);
297 }
239298 };
240299
241300 /// This struct defines the shadow mapping using the rule:
350409 *AsanMemoryAccessCallbackSized[2];
351410 Function *AsanMemmove, *AsanMemcpy, *AsanMemset;
352411 InlineAsm *EmptyAsm;
353 SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals;
412 GlobalsMetadata GlobalsMD;
354413
355414 friend struct FunctionStackPoisoner;
356415 };
380439 SmallString<64> BlacklistFile;
381440
382441 std::unique_ptr BL;
383 SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals;
442 GlobalsMetadata GlobalsMD;
384443 Type *IntptrTy;
385444 LLVMContext *C;
386445 const DataLayout *DL;
658717 // If a global variable does not have dynamic initialization we don't
659718 // have to instrument it. However, if a global does not have initializer
660719 // at all, we assume it has dynamic initializer (in other TU).
661 return G->hasInitializer() && !DynamicallyInitializedGlobals.Contains(G);
720 return G->hasInitializer() && !GlobalsMD.isDynInit(G);
662721 }
663722
664723 void
865924 Type *Ty = cast(G->getType())->getElementType();
866925 DEBUG(dbgs() << "GLOBAL: " << *G << "\n");
867926
927 // FIXME: Don't use the blacklist here, all the data should be collected
928 // by the frontend and passed in globals metadata.
868929 if (BL->isIn(*G)) return false;
930 if (GlobalsMD.isBlacklisted(G)) return false;
931 if (GlobalsMD.isSourceLocationGlobal(G)) return false;
869932 if (!Ty->isSized()) return false;
870933 if (!G->hasInitializer()) return false;
871934 if (GlobalWasGeneratedByAsan(G)) return false; // Our own global.
9661029 // trailing redzones. It also creates a function that poisons
9671030 // redzones and inserts this function into llvm.global_ctors.
9681031 bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
969 DynamicallyInitializedGlobals.Init(M);
1032 GlobalsMD.init(M);
9701033
9711034 SmallVector GlobalsToChange;
9721035
9851048 // const char *name;
9861049 // const char *module_name;
9871050 // size_t has_dynamic_init;
1051 // void *source_location;
9881052 // We initialize an array of such structures and pass it to a run-time call.
989 StructType *GlobalStructTy = StructType::get(IntptrTy, IntptrTy,
990 IntptrTy, IntptrTy,
991 IntptrTy, IntptrTy, NULL);
1053 StructType *GlobalStructTy =
1054 StructType::get(IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy,
1055 IntptrTy, IntptrTy, NULL);
9921056 SmallVector Initializers(n);
9931057
9941058 bool HasDynamicallyInitializedGlobals = false;
10161080 RightRedzoneSize += MinRZ - (SizeInBytes % MinRZ);
10171081 assert(((RightRedzoneSize + SizeInBytes) % MinRZ) == 0);
10181082 Type *RightRedZoneTy = ArrayType::get(IRB.getInt8Ty(), RightRedzoneSize);
1019 // Determine whether this global should be poisoned in initialization.
1020 bool GlobalHasDynamicInitializer =
1021 DynamicallyInitializedGlobals.Contains(G);
10221083
10231084 StructType *NewTy = StructType::get(Ty, RightRedZoneTy, NULL);
10241085 Constant *NewInitializer = ConstantStruct::get(
10471108 NewGlobal->takeName(G);
10481109 G->eraseFromParent();
10491110
1111 bool GlobalHasDynamicInitializer = GlobalsMD.isDynInit(G);
1112 GlobalVariable *SourceLoc = GlobalsMD.getSourceLocation(G);
1113
10501114 Initializers[i] = ConstantStruct::get(
1051 GlobalStructTy,
1052 ConstantExpr::getPointerCast(NewGlobal, IntptrTy),
1115 GlobalStructTy, ConstantExpr::getPointerCast(NewGlobal, IntptrTy),
10531116 ConstantInt::get(IntptrTy, SizeInBytes),
10541117 ConstantInt::get(IntptrTy, SizeInBytes + RightRedzoneSize),
10551118 ConstantExpr::getPointerCast(Name, IntptrTy),
10561119 ConstantExpr::getPointerCast(ModuleName, IntptrTy),
10571120 ConstantInt::get(IntptrTy, GlobalHasDynamicInitializer),
1121 SourceLoc ? ConstantExpr::getPointerCast(SourceLoc, IntptrTy)
1122 : ConstantInt::get(IntptrTy, 0),
10581123 NULL);
10591124
1060 // Populate the first and last globals declared in this TU.
10611125 if (ClInitializers && GlobalHasDynamicInitializer)
10621126 HasDynamicallyInitializedGlobals = true;
10631127
11851249 report_fatal_error("data layout missing");
11861250 DL = &DLP->getDataLayout();
11871251
1188 DynamicallyInitializedGlobals.Init(M);
1252 GlobalsMD.init(M);
11891253
11901254 C = &(M.getContext());
11911255 LongSize = DL->getPointerSizeInBits();
0 ; RUN: opt < %s -asan -asan-module -S | FileCheck %s
1
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3 target triple = "x86_64-unknown-linux-gnu"
4
5 ; Globals:
6 @global = global i32 0, align 4
7 @dyn_init_global = global i32 0, align 4
8 @blacklisted_global = global i32 0, align 4
9 @_ZZ4funcvE10static_var = internal global i32 0, align 4
10 @.str = private unnamed_addr constant [14 x i8] c"Hello, world!\00", align 1
11 @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_asan_globals.cpp, i8* null }]
12
13 ; Sanitizer location descriptors:
14 @.str1 = private unnamed_addr constant [22 x i8] c"/tmp/asan-globals.cpp\00", align 1
15 @.asan_loc_descr = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 5, i32 5 }
16 @.asan_loc_descr1 = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 7, i32 5 }
17 @.asan_loc_descr2 = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 12, i32 14 }
18 @.asan_loc_descr4 = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 14, i32 25 }
19
20 ; Check that globals were instrumented, but sanitizer location descriptors weren't:
21 ; CHECK: @global = global { i32, [60 x i8] } zeroinitializer, align 32
22 ; 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
23 ; CHECK: @.asan_loc_descr = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* @.str1, i32 5, i32 5 }
24
25 ; Check that location decriptors were passed into __asan_register_globals:
26 ; CHECK: i64 ptrtoint ({ [22 x i8]*, i32, i32 }* @.asan_loc_descr to i64)
27
28 ; Function Attrs: nounwind sanitize_address
29 define internal void @__cxx_global_var_init() #0 section ".text.startup" {
30 entry:
31 %0 = load i32* @global, align 4
32 store i32 %0, i32* @dyn_init_global, align 4
33 ret void
34 }
35
36 ; Function Attrs: nounwind sanitize_address
37 define void @_Z4funcv() #1 {
38 entry:
39 %literal = alloca i8*, align 8
40 store i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0), i8** %literal, align 8
41 ret void
42 }
43
44 ; Function Attrs: nounwind sanitize_address
45 define internal void @_GLOBAL__sub_I_asan_globals.cpp() #0 section ".text.startup" {
46 entry:
47 call void @__cxx_global_var_init()
48 ret void
49 }
50
51 attributes #0 = { nounwind sanitize_address }
52 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" }
53
54 !llvm.asan.globals = !{!0, !1, !2, !3, !4}
55 !llvm.ident = !{!5}
56
57 !0 = metadata !{i32* @global, { [22 x i8]*, i32, i32 }* @.asan_loc_descr, i1 false, i1 false}
58 !1 = metadata !{i32* @dyn_init_global, { [22 x i8]*, i32, i32 }* @.asan_loc_descr1, i1 true, i1 false}
59 !2 = metadata !{i32* @blacklisted_global, null, i1 false, i1 true}
60 !3 = metadata !{i32* @_ZZ4funcvE10static_var, { [22 x i8]*, i32, i32 }* @.asan_loc_descr2, i1 false, i1 false}
61 !4 = metadata !{[14 x i8]* @.str, { [22 x i8]*, i32, i32 }* @.asan_loc_descr4, i1 false, i1 false}
62 !5 = metadata !{metadata !"clang version 3.5.0 (211282)"}
6767 }
6868
6969
70 !llvm.asan.dynamically_initialized_globals = !{!0}
71 !0 = metadata !{[10 x i32]* @GlobDy}
70 !llvm.asan.globals = !{!0}
71 !0 = metadata !{[10 x i32]* @GlobDy, null, i1 true, i1 false}
7272
7373 ; CHECK-LABEL: define internal void @asan.module_ctor
7474 ; CHECK-NOT: ret
66 @YYY = global i32 0, align 4 ; W/o dynamic initializer.
77 ; Clang will emit the following metadata identifying @xxx as dynamically
88 ; initialized.
9 !0 = metadata !{i32* @xxx}
10 !1 = metadata !{i32* @XXX}
11 !llvm.asan.dynamically_initialized_globals = !{!0, !1}
9 !0 = metadata !{i32* @xxx, null, i1 true, i1 false}
10 !1 = metadata !{i32* @XXX, null, i1 true, i1 false}
11 !2 = metadata !{i32* @yyy, null, i1 false, i1 false}
12 !3 = metadata !{i32* @YYY, null, i1 false, i1 false}
13 !llvm.asan.globals = !{!0, !1, !2, !3}
1214
1315 define i32 @initializer() uwtable {
1416 entry: