llvm.org GIT mirror llvm / 3386d25
[asan] Optimize accesses to global arrays with constant index Summary: Given a global array G[N], which is declared in this CU and has static initializer avoid instrumenting accesses like G[i], where 'i' is a constant and 0<=i<N. Also add a bit of stats. This eliminates ~1% of instrumentations on SPEC2006 and also partially helps when asan is being run together with coverage. Reviewers: samsonov Reviewed By: samsonov CC: llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1947 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192794 91177308-0d34-0410-b5e6-96231b3b80d8 Kostya Serebryany 7 years ago
3 changed file(s) with 97 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
2222 #include "llvm/ADT/SmallSet.h"
2323 #include "llvm/ADT/SmallString.h"
2424 #include "llvm/ADT/SmallVector.h"
25 #include "llvm/ADT/Statistic.h"
2526 #include "llvm/ADT/StringExtras.h"
2627 #include "llvm/ADT/Triple.h"
2728 #include "llvm/DIBuilder.h"
192193 static cl::opt ClDebugMax("asan-debug-max", cl::desc("Debug man inst"),
193194 cl::Hidden, cl::init(-1));
194195
196 STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
197 STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
198 STATISTIC(NumOptimizedAccessesToGlobalArray,
199 "Number of optimized accesses to global arrays");
200 STATISTIC(NumOptimizedAccessesToGlobalVar,
201 "Number of optimized accesses to global vars");
202
195203 namespace {
196204 /// A set of dynamically initialized globals extracted from metadata.
197205 class SetOfDynamicallyInitializedGlobals {
314322 bool ShouldInstrumentGlobal(GlobalVariable *G);
315323 bool LooksLikeCodeInBug11395(Instruction *I);
316324 void FindDynamicInitializers(Module &M);
325 bool GlobalIsLinkerInitialized(GlobalVariable *G);
317326
318327 bool CheckInitOrder;
319328 bool CheckUseAfterReturn;
654663 return NULL;
655664 }
656665
666 bool AddressSanitizer::GlobalIsLinkerInitialized(GlobalVariable *G) {
667 // If a global variable does not have dynamic initialization we don't
668 // have to instrument it. However, if a global does not have initializer
669 // at all, we assume it has dynamic initializer (in other TU).
670 return G->hasInitializer() && !DynamicallyInitializedGlobals.Contains(G);
671 }
672
657673 void AddressSanitizer::instrumentMop(Instruction *I) {
658674 bool IsWrite = false;
659675 Value *Addr = isInterestingMemoryAccess(I, &IsWrite);
662678 if (GlobalVariable *G = dyn_cast(Addr)) {
663679 // If initialization order checking is disabled, a simple access to a
664680 // dynamically initialized global is always valid.
665 if (!CheckInitOrder)
681 if (!CheckInitOrder || GlobalIsLinkerInitialized(G)) {
682 NumOptimizedAccessesToGlobalVar++;
666683 return;
667 // If a global variable does not have dynamic initialization we don't
668 // have to instrument it. However, if a global does not have initailizer
669 // at all, we assume it has dynamic initializer (in other TU).
670 if (G->hasInitializer() && !DynamicallyInitializedGlobals.Contains(G))
671 return;
684 }
685 }
686 ConstantExpr *CE = dyn_cast(Addr);
687 if (CE && CE->isGEPWithNoNotionalOverIndexing()) {
688 if (GlobalVariable *G = dyn_cast(CE->getOperand(0))) {
689 if (CE->getOperand(1)->isNullValue() && GlobalIsLinkerInitialized(G)) {
690 NumOptimizedAccessesToGlobalArray++;
691 return;
692 }
693 }
672694 }
673695 }
674696
679701 uint32_t TypeSize = TD->getTypeStoreSizeInBits(OrigTy);
680702
681703 assert((TypeSize % 8) == 0);
704
705 if (IsWrite)
706 NumInstrumentedWrites++;
707 else
708 NumInstrumentedReads++;
682709
683710 // Instrument a 1-, 2-, 4-, 8-, or 16- byte access with one check.
684711 if (TypeSize == 8 || TypeSize == 16 ||
88
99 %struct_of_7_bytes_4_aligned = type { i32, i8, i8, i8}
1010
11 @f = global %struct_of_7_bytes_4_aligned zeroinitializer, align 4
11 @f = external global %struct_of_7_bytes_4_aligned , align 4
1212
1313 ; Accessing bytes 4 and 6, not ok to widen to i32 if sanitize_address is set.
1414
88 ; CHECK: llvm.global_ctors
99 ; CHECK: llvm.global_dtors
1010
11 ; CHECK: define internal void @asan.module_ctor
11 ; Test that we don't instrument global arrays with static initializer
12 ; indexed with constants in-bounds. But instrument all other cases.
13
14 @GlobSt = global [10 x i32] zeroinitializer, align 16 ; static initializer
15 @GlobDy = global [10 x i32] zeroinitializer, align 16 ; dynamic initializer
16 @GlobEx = external global [10 x i32] , align 16 ; extern initializer
17
18 ; GlobSt is declared here, and has static initializer -- ok to optimize.
19 define i32 @AccessGlobSt_0_2() sanitize_address {
20 entry:
21 %0 = load i32* getelementptr inbounds ([10 x i32]* @GlobSt, i64 0, i64 2), align 8
22 ret i32 %0
23 ; CHECK-LABEL: define i32 @AccessGlobSt_0_2
24 ; CHECK-NOT: __asan_report
25 ; CHECK: ret i32 %0
26 }
27
28 ; GlobSt is accessed out of bounds -- can't optimize
29 define i32 @AccessGlobSt_0_12() sanitize_address {
30 entry:
31 %0 = load i32* getelementptr inbounds ([10 x i32]* @GlobSt, i64 0, i64 12), align 8
32 ret i32 %0
33 ; CHECK-LABEL: define i32 @AccessGlobSt_0_12
34 ; CHECK: __asan_report
35 ; CHECK: ret i32
36 }
37
38 ; GlobSt is accessed with Gep that has non-0 first index -- can't optimize.
39 define i32 @AccessGlobSt_1_2() sanitize_address {
40 entry:
41 %0 = load i32* getelementptr inbounds ([10 x i32]* @GlobSt, i64 1, i64 2), align 8
42 ret i32 %0
43 ; CHECK-LABEL: define i32 @AccessGlobSt_1_2
44 ; CHECK: __asan_report
45 ; CHECK: ret i32
46 }
47
48 ; GlobDy is declared with dynamic initializer -- can't optimize.
49 define i32 @AccessGlobDy_0_2() sanitize_address {
50 entry:
51 %0 = load i32* getelementptr inbounds ([10 x i32]* @GlobDy, i64 0, i64 2), align 8
52 ret i32 %0
53 ; CHECK-LABEL: define i32 @AccessGlobDy_0_2
54 ; CHECK: __asan_report
55 ; CHECK: ret i32
56 }
57
58 ; GlobEx is an external global -- can't optimize.
59 define i32 @AccessGlobEx_0_2() sanitize_address {
60 entry:
61 %0 = load i32* getelementptr inbounds ([10 x i32]* @GlobEx, i64 0, i64 2), align 8
62 ret i32 %0
63 ; CHECK-LABEL: define i32 @AccessGlobEx_0_2
64 ; CHECK: __asan_report
65 ; CHECK: ret i32
66 }
67
68
69 !llvm.asan.dynamically_initialized_globals = !{!0}
70 !0 = metadata !{[10 x i32]* @GlobDy}
71
72 ; CHECK-LABEL: define internal void @asan.module_ctor
1273 ; CHECK-NOT: ret
1374 ; CHECK: call void @__asan_register_globals
1475 ; CHECK: ret
1576
16 ; CHECK: define internal void @asan.module_dtor
77 ; CHECK-LABEL: define internal void @asan.module_dtor
1778 ; CHECK-NOT: ret
1879 ; CHECK: call void @__asan_unregister_globals
1980 ; CHECK: ret