11
11
#include " llvm/ADT/Statistic.h"
12
12
#include " llvm/ADT/Twine.h"
13
13
#include " llvm/Analysis/MemoryBuiltins.h"
14
+ #include " llvm/Analysis/ScalarEvolution.h"
14
15
#include " llvm/Analysis/TargetFolder.h"
15
16
#include " llvm/Analysis/TargetLibraryInfo.h"
16
17
#include " llvm/IR/BasicBlock.h"
@@ -59,8 +60,8 @@ template <typename GetTrapBBT>
59
60
static bool instrumentMemAccess (Value *Ptr, Value *InstVal,
60
61
const DataLayout &DL, TargetLibraryInfo &TLI,
61
62
ObjectSizeOffsetEvaluator &ObjSizeEval,
62
- BuilderTy &IRB,
63
- GetTrapBBT GetTrapBB ) {
63
+ BuilderTy &IRB, GetTrapBBT GetTrapBB,
64
+ ScalarEvolution &SE ) {
64
65
uint64_t NeededSize = DL.getTypeStoreSize (InstVal->getType ());
65
66
LLVM_DEBUG (dbgs () << " Instrument " << *Ptr << " for " << Twine (NeededSize)
66
67
<< " bytes\n " );
@@ -79,6 +80,10 @@ static bool instrumentMemAccess(Value *Ptr, Value *InstVal,
79
80
Type *IntTy = DL.getIntPtrType (Ptr->getType ());
80
81
Value *NeededSizeVal = ConstantInt::get (IntTy, NeededSize);
81
82
83
+ auto SizeRange = SE.getUnsignedRange (SE.getSCEV (Size));
84
+ auto OffsetRange = SE.getUnsignedRange (SE.getSCEV (Offset));
85
+ auto NeededSizeRange = SE.getUnsignedRange (SE.getSCEV (NeededSizeVal));
86
+
82
87
// three checks are required to ensure safety:
83
88
// . Offset >= 0 (since the offset is given from the base ptr)
84
89
// . Size >= Offset (unsigned)
@@ -87,10 +92,17 @@ static bool instrumentMemAccess(Value *Ptr, Value *InstVal,
87
92
// optimization: if Size >= 0 (signed), skip 1st check
88
93
// FIXME: add NSW/NUW here? -- we dont care if the subtraction overflows
89
94
Value *ObjSize = IRB.CreateSub (Size, Offset);
90
- Value *Cmp2 = IRB.CreateICmpULT (Size, Offset);
91
- Value *Cmp3 = IRB.CreateICmpULT (ObjSize, NeededSizeVal);
95
+ Value *Cmp2 = SizeRange.getUnsignedMin ().uge (OffsetRange.getUnsignedMax ())
96
+ ? ConstantInt::getFalse (Ptr->getContext ())
97
+ : IRB.CreateICmpULT (Size, Offset);
98
+ Value *Cmp3 = SizeRange.sub (OffsetRange)
99
+ .getUnsignedMin ()
100
+ .uge (NeededSizeRange.getUnsignedMax ())
101
+ ? ConstantInt::getFalse (Ptr->getContext ())
102
+ : IRB.CreateICmpULT (ObjSize, NeededSizeVal);
92
103
Value *Or = IRB.CreateOr (Cmp2, Cmp3);
93
- if (!SizeCI || SizeCI->getValue ().slt (0 )) {
104
+ if ((!SizeCI || SizeCI->getValue ().slt (0 )) &&
105
+ !SizeRange.getSignedMin ().isNonNegative ()) {
94
106
Value *Cmp1 = IRB.CreateICmpSLT (Offset, ConstantInt::get (IntTy, 0 ));
95
107
Or = IRB.CreateOr (Cmp1, Or);
96
108
}
@@ -123,7 +135,8 @@ static bool instrumentMemAccess(Value *Ptr, Value *InstVal,
123
135
return true ;
124
136
}
125
137
126
- static bool addBoundsChecking (Function &F, TargetLibraryInfo &TLI) {
138
+ static bool addBoundsChecking (Function &F, TargetLibraryInfo &TLI,
139
+ ScalarEvolution &SE) {
127
140
const DataLayout &DL = F.getParent ()->getDataLayout ();
128
141
ObjectSizeOffsetEvaluator ObjSizeEval (DL, &TLI, F.getContext (),
129
142
/* RoundToAlign=*/ true );
@@ -168,19 +181,19 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI) {
168
181
BuilderTy IRB (Inst->getParent (), BasicBlock::iterator (Inst), TargetFolder (DL));
169
182
if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
170
183
MadeChange |= instrumentMemAccess (LI->getPointerOperand (), LI, DL, TLI,
171
- ObjSizeEval, IRB, GetTrapBB);
184
+ ObjSizeEval, IRB, GetTrapBB, SE );
172
185
} else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
173
186
MadeChange |=
174
187
instrumentMemAccess (SI->getPointerOperand (), SI->getValueOperand (),
175
- DL, TLI, ObjSizeEval, IRB, GetTrapBB);
188
+ DL, TLI, ObjSizeEval, IRB, GetTrapBB, SE );
176
189
} else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(Inst)) {
177
190
MadeChange |=
178
191
instrumentMemAccess (AI->getPointerOperand (), AI->getCompareOperand (),
179
- DL, TLI, ObjSizeEval, IRB, GetTrapBB);
192
+ DL, TLI, ObjSizeEval, IRB, GetTrapBB, SE );
180
193
} else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(Inst)) {
181
194
MadeChange |=
182
195
instrumentMemAccess (AI->getPointerOperand (), AI->getValOperand (), DL,
183
- TLI, ObjSizeEval, IRB, GetTrapBB);
196
+ TLI, ObjSizeEval, IRB, GetTrapBB, SE );
184
197
} else {
185
198
llvm_unreachable (" unknown Instruction type" );
186
199
}
@@ -190,8 +203,9 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI) {
190
203
191
204
PreservedAnalyses BoundsCheckingPass::run (Function &F, FunctionAnalysisManager &AM) {
192
205
auto &TLI = AM.getResult <TargetLibraryAnalysis>(F);
206
+ auto &SE = AM.getResult <ScalarEvolutionAnalysis>(F);
193
207
194
- if (!addBoundsChecking (F, TLI))
208
+ if (!addBoundsChecking (F, TLI, SE ))
195
209
return PreservedAnalyses::all ();
196
210
197
211
return PreservedAnalyses::none ();
@@ -207,11 +221,13 @@ struct BoundsCheckingLegacyPass : public FunctionPass {
207
221
208
222
bool runOnFunction (Function &F) override {
209
223
auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI ();
210
- return addBoundsChecking (F, TLI);
224
+ auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE ();
225
+ return addBoundsChecking (F, TLI, SE);
211
226
}
212
227
213
228
void getAnalysisUsage (AnalysisUsage &AU) const override {
214
229
AU.addRequired <TargetLibraryInfoWrapperPass>();
230
+ AU.addRequired <ScalarEvolutionWrapperPass>();
215
231
}
216
232
};
217
233
} // namespace
0 commit comments