llvm.org GIT mirror llvm / ecf0fcd
[msan] Handling of atomic load/store, atomic rmw, cmpxchg. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191287 91177308-0d34-0410-b5e6-96231b3b80d8 Evgeniy Stepanov 7 years ago
3 changed file(s) with 289 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
6565 /// avoids storing origin to memory when a fully initialized value is stored.
6666 /// This way it avoids needless overwritting origin of the 4-byte region on
6767 /// a short (i.e. 1 byte) clean store, and it is also good for performance.
68 ///
69 /// Atomic handling.
70 ///
71 /// Ideally, every atomic store of application value should update the
72 /// corresponding shadow location in an atomic way. Unfortunately, atomic store
73 /// of two disjoint locations can not be done without severe slowdown.
74 ///
75 /// Therefore, we implement an approximation that may err on the safe side.
76 /// In this implementation, every atomically accessed location in the program
77 /// may only change from (partially) uninitialized to fully initialized, but
78 /// not the other way around. We load the shadow _after_ the application load,
79 /// and we store the shadow _before_ the app store. Also, we always store clean
80 /// shadow (if the application store is atomic). This way, if the store-load
81 /// pair constitutes a happens-before arc, shadow store and load are correctly
82 /// ordered such that the load will get either the value that was stored, or
83 /// some later value (which is always clean).
84 ///
85 /// This does not work very well with Compare-And-Swap (CAS) and
86 /// Read-Modify-Write (RMW) operations. To follow the above logic, CAS and RMW
87 /// must store the new shadow before the app operation, and load the shadow
88 /// after the app operation. Computers don't work this way. Current
89 /// implementation ignores the load aspect of CAS/RMW, always returning a clean
90 /// value. It implements the store part as a simple atomic store by storing a
91 /// clean shadow.
92
6893 //===----------------------------------------------------------------------===//
6994
7095 #define DEBUG_TYPE "msan"
486511 IRBuilder<> IRB(&I);
487512 Value *Val = I.getValueOperand();
488513 Value *Addr = I.getPointerOperand();
489 Value *Shadow = getShadow(Val);
514 Value *Shadow = I.isAtomic() ? getCleanShadow(Val) : getShadow(Val);
490515 Value *ShadowPtr = getShadowPtr(Addr, Shadow->getType(), IRB);
491516
492517 StoreInst *NewSI =
496521
497522 if (ClCheckAccessAddress)
498523 insertCheck(Addr, &I);
524
525 if (I.isAtomic())
526 I.setOrdering(addReleaseOrdering(I.getOrdering()));
499527
500528 if (MS.TrackOrigins) {
501529 unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment());
875903 ShadowOriginAndInsertPoint(Shadow, Origin, OrigIns));
876904 }
877905
906 AtomicOrdering addReleaseOrdering(AtomicOrdering a) {
907 switch (a) {
908 case NotAtomic:
909 return NotAtomic;
910 case Unordered:
911 case Monotonic:
912 case Release:
913 return Release;
914 case Acquire:
915 case AcquireRelease:
916 return AcquireRelease;
917 case SequentiallyConsistent:
918 return SequentiallyConsistent;
919 }
920 }
921
922 AtomicOrdering addAcquireOrdering(AtomicOrdering a) {
923 switch (a) {
924 case NotAtomic:
925 return NotAtomic;
926 case Unordered:
927 case Monotonic:
928 case Acquire:
929 return Acquire;
930 case Release:
931 case AcquireRelease:
932 return AcquireRelease;
933 case SequentiallyConsistent:
934 return SequentiallyConsistent;
935 }
936 }
937
878938 // ------------------- Visitors.
879939
880940 /// \brief Instrument LoadInst
883943 /// Optionally, checks that the load address is fully defined.
884944 void visitLoadInst(LoadInst &I) {
885945 assert(I.getType()->isSized() && "Load type must have size");
886 IRBuilder<> IRB(&I);
946 IRBuilder<> IRB(I.getNextNode());
887947 Type *ShadowTy = getShadowTy(&I);
888948 Value *Addr = I.getPointerOperand();
889949 if (LoadShadow) {
897957 if (ClCheckAccessAddress)
898958 insertCheck(I.getPointerOperand(), &I);
899959
960 if (I.isAtomic())
961 I.setOrdering(addAcquireOrdering(I.getOrdering()));
962
900963 if (MS.TrackOrigins) {
901964 if (LoadShadow) {
902965 unsigned Alignment = std::max(kMinOriginAlignment, I.getAlignment());
914977 /// Optionally, checks that the store address is fully defined.
915978 void visitStoreInst(StoreInst &I) {
916979 StoreList.push_back(&I);
980 }
981
982 void handleCASOrRMW(Instruction &I) {
983 assert(isa(I) || isa(I));
984
985 IRBuilder<> IRB(&I);
986 Value *Addr = I.getOperand(0);
987 Value *ShadowPtr = getShadowPtr(Addr, I.getType(), IRB);
988
989 if (ClCheckAccessAddress)
990 insertCheck(Addr, &I);
991
992 // Only test the conditional argument of cmpxchg instruction.
993 // The other argument can potentially be uninitialized, but we can not
994 // detect this situation reliably without possible false positives.
995 if (isa(I))
996 insertCheck(I.getOperand(1), &I);
997
998 IRB.CreateStore(getCleanShadow(&I), ShadowPtr);
999
1000 setShadow(&I, getCleanShadow(&I));
1001 }
1002
1003 void visitAtomicRMWInst(AtomicRMWInst &I) {
1004 handleCASOrRMW(I);
1005 I.setOrdering(addReleaseOrdering(I.getOrdering()));
1006 }
1007
1008 void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
1009 handleCASOrRMW(I);
1010 I.setOrdering(addReleaseOrdering(I.getOrdering()));
9171011 }
9181012
9191013 // Vector manipulation.
0 ; RUN: opt < %s -msan -msan-check-access-address=0 -S | FileCheck %s
1
2 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-S128"
3 target triple = "x86_64-unknown-linux-gnu"
4
5 ; atomicrmw xchg: store clean shadow, return clean shadow
6
7 define i32 @AtomicRmwXchg(i32* %p, i32 %x) sanitize_memory {
8 entry:
9 %0 = atomicrmw xchg i32* %p, i32 %x seq_cst
10 ret i32 %0
11 }
12
13 ; CHECK: @AtomicRmwXchg
14 ; CHECK: store i32 0,
15 ; CHECK: atomicrmw xchg {{.*}} seq_cst
16 ; CHECK: store i32 0, {{.*}} @__msan_retval_tls
17 ; CHECK: ret i32
18
19
20 ; atomicrmw max: exactly the same as above
21
22 define i32 @AtomicRmwMax(i32* %p, i32 %x) sanitize_memory {
23 entry:
24 %0 = atomicrmw max i32* %p, i32 %x seq_cst
25 ret i32 %0
26 }
27
28 ; CHECK: @AtomicRmwMax
29 ; CHECK: store i32 0,
30 ; CHECK: atomicrmw max {{.*}} seq_cst
31 ; CHECK: store i32 0, {{.*}} @__msan_retval_tls
32 ; CHECK: ret i32
33
34
35 ; cmpxchg: the same as above, but also check %a shadow
36
37 define i32 @Cmpxchg(i32* %p, i32 %a, i32 %b) sanitize_memory {
38 entry:
39 %0 = cmpxchg i32* %p, i32 %a, i32 %b seq_cst
40 ret i32 %0
41 }
42
43 ; CHECK: @Cmpxchg
44 ; CHECK: store i32 0,
45 ; CHECK: icmp
46 ; CHECK: br
47 ; CHECK: @__msan_warning
48 ; CHECK: cmpxchg {{.*}} seq_cst
49 ; CHECK: store i32 0, {{.*}} @__msan_retval_tls
50 ; CHECK: ret i32
51
52
53 ; relaxed cmpxchg: bump up to "release"
54
55 define i32 @CmpxchgMonotonic(i32* %p, i32 %a, i32 %b) sanitize_memory {
56 entry:
57 %0 = cmpxchg i32* %p, i32 %a, i32 %b monotonic
58 ret i32 %0
59 }
60
61 ; CHECK: @CmpxchgMonotonic
62 ; CHECK: store i32 0,
63 ; CHECK: icmp
64 ; CHECK: br
65 ; CHECK: @__msan_warning
66 ; CHECK: cmpxchg {{.*}} release
67 ; CHECK: store i32 0, {{.*}} @__msan_retval_tls
68 ; CHECK: ret i32
69
70
71 ; atomic load: preserve alignment, load shadow value after app value
72
73 define i32 @AtomicLoad(i32* %p) sanitize_memory {
74 entry:
75 %0 = load atomic i32* %p seq_cst, align 16
76 ret i32 %0
77 }
78
79 ; CHECK: @AtomicLoad
80 ; CHECK: load atomic i32* {{.*}} seq_cst, align 16
81 ; CHECK: [[SHADOW:%[01-9a-z_]+]] = load i32* {{.*}}, align 16
82 ; CHECK: store i32 {{.*}}[[SHADOW]], {{.*}} @__msan_retval_tls
83 ; CHECK: ret i32
84
85
86 ; atomic load: preserve alignment, load shadow value after app value
87
88 define i32 @AtomicLoadAcquire(i32* %p) sanitize_memory {
89 entry:
90 %0 = load atomic i32* %p acquire, align 16
91 ret i32 %0
92 }
93
94 ; CHECK: @AtomicLoadAcquire
95 ; CHECK: load atomic i32* {{.*}} acquire, align 16
96 ; CHECK: [[SHADOW:%[01-9a-z_]+]] = load i32* {{.*}}, align 16
97 ; CHECK: store i32 {{.*}}[[SHADOW]], {{.*}} @__msan_retval_tls
98 ; CHECK: ret i32
99
100
101 ; atomic load monotonic: bump up to load acquire
102
103 define i32 @AtomicLoadMonotonic(i32* %p) sanitize_memory {
104 entry:
105 %0 = load atomic i32* %p monotonic, align 16
106 ret i32 %0
107 }
108
109 ; CHECK: @AtomicLoadMonotonic
110 ; CHECK: load atomic i32* {{.*}} acquire, align 16
111 ; CHECK: [[SHADOW:%[01-9a-z_]+]] = load i32* {{.*}}, align 16
112 ; CHECK: store i32 {{.*}}[[SHADOW]], {{.*}} @__msan_retval_tls
113 ; CHECK: ret i32
114
115
116 ; atomic load unordered: bump up to load acquire
117
118 define i32 @AtomicLoadUnordered(i32* %p) sanitize_memory {
119 entry:
120 %0 = load atomic i32* %p unordered, align 16
121 ret i32 %0
122 }
123
124 ; CHECK: @AtomicLoadUnordered
125 ; CHECK: load atomic i32* {{.*}} acquire, align 16
126 ; CHECK: [[SHADOW:%[01-9a-z_]+]] = load i32* {{.*}}, align 16
127 ; CHECK: store i32 {{.*}}[[SHADOW]], {{.*}} @__msan_retval_tls
128 ; CHECK: ret i32
129
130
131 ; atomic store: preserve alignment, store clean shadow value before app value
132
133 define void @AtomicStore(i32* %p, i32 %x) sanitize_memory {
134 entry:
135 store atomic i32 %x, i32* %p seq_cst, align 16
136 ret void
137 }
138
139 ; CHECK: @AtomicStore
140 ; CHECK-NOT: @__msan_param_tls
141 ; CHECK: store i32 0, i32* {{.*}}, align 16
142 ; CHECK: store atomic i32 %x, i32* %p seq_cst, align 16
143 ; CHECK: ret void
144
145
146 ; atomic store: preserve alignment, store clean shadow value before app value
147
148 define void @AtomicStoreRelease(i32* %p, i32 %x) sanitize_memory {
149 entry:
150 store atomic i32 %x, i32* %p release, align 16
151 ret void
152 }
153
154 ; CHECK: @AtomicStoreRelease
155 ; CHECK-NOT: @__msan_param_tls
156 ; CHECK: store i32 0, i32* {{.*}}, align 16
157 ; CHECK: store atomic i32 %x, i32* %p release, align 16
158 ; CHECK: ret void
159
160
161 ; atomic store monotonic: bumped up to store release
162
163 define void @AtomicStoreMonotonic(i32* %p, i32 %x) sanitize_memory {
164 entry:
165 store atomic i32 %x, i32* %p monotonic, align 16
166 ret void
167 }
168
169 ; CHECK: @AtomicStoreMonotonic
170 ; CHECK-NOT: @__msan_param_tls
171 ; CHECK: store i32 0, i32* {{.*}}, align 16
172 ; CHECK: store atomic i32 %x, i32* %p release, align 16
173 ; CHECK: ret void
174
175
176 ; atomic store unordered: bumped up to store release
177
178 define void @AtomicStoreUnordered(i32* %p, i32 %x) sanitize_memory {
179 entry:
180 store atomic i32 %x, i32* %p unordered, align 16
181 ret void
182 }
183
184 ; CHECK: @AtomicStoreUnordered
185 ; CHECK-NOT: @__msan_param_tls
186 ; CHECK: store i32 0, i32* {{.*}}, align 16
187 ; CHECK: store atomic i32 %x, i32* %p release, align 16
188 ; CHECK: ret void
441441 }
442442
443443 ; CHECK: @ShadowLoadAlignmentLarge
444 ; CHECK: load volatile i32* {{.*}} align 64
444445 ; CHECK: load i32* {{.*}} align 64
445 ; CHECK: load volatile i32* {{.*}} align 64
446446 ; CHECK: ret i32
447447
448448 define i32 @ShadowLoadAlignmentSmall() nounwind uwtable sanitize_memory {
452452 }
453453
454454 ; CHECK: @ShadowLoadAlignmentSmall
455 ; CHECK: load volatile i32* {{.*}} align 2
455456 ; CHECK: load i32* {{.*}} align 2
456 ; CHECK: load volatile i32* {{.*}} align 2
457457 ; CHECK: ret i32
458458
459459 ; CHECK-ORIGINS: @ShadowLoadAlignmentSmall
460 ; CHECK-ORIGINS: load volatile i32* {{.*}} align 2
460461 ; CHECK-ORIGINS: load i32* {{.*}} align 2
461462 ; CHECK-ORIGINS: load i32* {{.*}} align 4
462 ; CHECK-ORIGINS: load volatile i32* {{.*}} align 2
463463 ; CHECK-ORIGINS: ret i32
464464
465465
599599 }
600600
601601 ; CHECK: @VectorOfPointers
602 ; CHECK: load <8 x i8*>*
602603 ; CHECK: load <8 x i64>*
603 ; CHECK: load <8 x i8*>*
604604 ; CHECK: store <8 x i64> {{.*}} @__msan_retval_tls
605605 ; CHECK: ret <8 x i8*>
606606