8
8
9
9
#include " llvm/Transforms/Instrumentation/BoundsChecking.h"
10
10
#include " llvm/ADT/Statistic.h"
11
+ #include " llvm/ADT/StringRef.h"
11
12
#include " llvm/ADT/Twine.h"
12
13
#include " llvm/Analysis/MemoryBuiltins.h"
13
14
#include " llvm/Analysis/ScalarEvolution.h"
@@ -104,6 +105,30 @@ static Value *getBoundsCheckCond(Value *Ptr, Value *InstVal,
104
105
return Or;
105
106
}
106
107
108
+ static CallInst *InsertTrap (BuilderTy &IRB) {
109
+ if (!DebugTrapBB)
110
+ return IRB.CreateIntrinsic (Intrinsic::trap, {}, {});
111
+ // FIXME: Ideally we would use the SanitizerHandler::OutOfBounds constant.
112
+ return IRB.CreateIntrinsic (
113
+ Intrinsic::ubsantrap, {},
114
+ ConstantInt::get (IRB.getInt8Ty (),
115
+ IRB.GetInsertBlock ()->getParent ()->size ()));
116
+ }
117
+
118
+ static CallInst *InsertCall (BuilderTy &IRB, bool MayReturn, StringRef Name) {
119
+ Function *Fn = IRB.GetInsertBlock ()->getParent ();
120
+ LLVMContext &Ctx = Fn->getContext ();
121
+ llvm::AttrBuilder B (Ctx);
122
+ B.addAttribute (llvm::Attribute::NoUnwind);
123
+ if (!MayReturn)
124
+ B.addAttribute (llvm::Attribute::NoReturn);
125
+ FunctionCallee Callee = Fn->getParent ()->getOrInsertFunction (
126
+ Name,
127
+ llvm::AttributeList::get (Ctx, llvm::AttributeList::FunctionIndex, B),
128
+ Type::getVoidTy (Ctx));
129
+ return IRB.CreateCall (Callee);
130
+ }
131
+
107
132
// / Adds run-time bounds checks to memory accessing instructions.
108
133
// /
109
134
// / \p Or is the condition that should guard the trap.
@@ -126,20 +151,53 @@ static void insertBoundsCheck(Value *Or, BuilderTy &IRB, GetTrapBBT GetTrapBB) {
126
151
BasicBlock *Cont = OldBB->splitBasicBlock (SplitI);
127
152
OldBB->getTerminator ()->eraseFromParent ();
128
153
154
+ BasicBlock *TrapBB = GetTrapBB (IRB, Cont);
155
+
129
156
if (C) {
130
157
// If we have a constant zero, unconditionally branch.
131
158
// FIXME: We should really handle this differently to bypass the splitting
132
159
// the block.
133
- BranchInst::Create (GetTrapBB (IRB) , OldBB);
160
+ BranchInst::Create (TrapBB , OldBB);
134
161
return ;
135
162
}
136
163
137
164
// Create the conditional branch.
138
- BranchInst::Create (GetTrapBB (IRB) , Cont, Or, OldBB);
165
+ BranchInst::Create (TrapBB , Cont, Or, OldBB);
139
166
}
140
167
168
+ struct ReportingOpts {
169
+ bool MayReturn = false ;
170
+ bool UseTrap = false ;
171
+ bool MinRuntime = false ;
172
+ StringRef Name;
173
+
174
+ ReportingOpts (BoundsCheckingPass::ReportingMode Mode) {
175
+ switch (Mode) {
176
+ case BoundsCheckingPass::ReportingMode::Trap:
177
+ UseTrap = true ;
178
+ break ;
179
+ case BoundsCheckingPass::ReportingMode::MinRuntime:
180
+ Name = " __ubsan_handle_local_out_of_bounds_minimal" ;
181
+ MinRuntime = true ;
182
+ MayReturn = true ;
183
+ break ;
184
+ case BoundsCheckingPass::ReportingMode::MinRuntimeAbort:
185
+ Name = " __ubsan_handle_local_out_of_bounds_minimal_abort" ;
186
+ MinRuntime = true ;
187
+ break ;
188
+ case BoundsCheckingPass::ReportingMode::FullRuntime:
189
+ Name = " __ubsan_handle_local_out_of_bounds" ;
190
+ MayReturn = true ;
191
+ break ;
192
+ case BoundsCheckingPass::ReportingMode::FullRuntimeAbort:
193
+ Name = " __ubsan_handle_local_out_of_bounds_abort" ;
194
+ break ;
195
+ }
196
+ }
197
+ };
198
+
141
199
static bool addBoundsChecking (Function &F, TargetLibraryInfo &TLI,
142
- ScalarEvolution &SE) {
200
+ ScalarEvolution &SE, const ReportingOpts &Opts ) {
143
201
if (F.hasFnAttribute (Attribute::NoSanitizeBounds))
144
202
return false ;
145
203
@@ -180,39 +238,44 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
180
238
// Create a trapping basic block on demand using a callback. Depending on
181
239
// flags, this will either create a single block for the entire function or
182
240
// will create a fresh block every time it is called.
183
- BasicBlock *TrapBB = nullptr ;
184
- auto GetTrapBB = [&TrapBB ](BuilderTy &IRB) {
241
+ BasicBlock *ReuseTrapBB = nullptr ;
242
+ auto GetTrapBB = [&ReuseTrapBB, &Opts ](BuilderTy &IRB, BasicBlock *Cont ) {
185
243
Function *Fn = IRB.GetInsertBlock ()->getParent ();
186
244
auto DebugLoc = IRB.getCurrentDebugLocation ();
187
245
IRBuilder<>::InsertPointGuard Guard (IRB);
188
246
189
- if (TrapBB && SingleTrapBB && !DebugTrapBB)
190
- return TrapBB;
247
+ // Create a trapping basic block on demand using a callback. Depending on
248
+ // flags, this will either create a single block for the entire function or
249
+ // will create a fresh block every time it is called.
250
+ if (ReuseTrapBB)
251
+ return ReuseTrapBB;
191
252
192
- TrapBB = BasicBlock::Create (Fn->getContext (), " trap" , Fn);
253
+ BasicBlock * TrapBB = BasicBlock::Create (Fn->getContext (), " trap" , Fn);
193
254
IRB.SetInsertPoint (TrapBB);
194
255
195
- Intrinsic::ID IntrID = DebugTrapBB ? Intrinsic::ubsantrap : Intrinsic::trap;
196
-
197
- CallInst *TrapCall ;
256
+ CallInst *TrapCall = Opts. UseTrap
257
+ ? InsertTrap (IRB)
258
+ : InsertCall (IRB, Opts. MayReturn , Opts. Name ) ;
198
259
if (DebugTrapBB) {
199
- // Ideally we would use the SanitizerHandler::OutOfBounds constant
200
- TrapCall = IRB.CreateIntrinsic (
201
- IntrID, {}, ConstantInt::get (IRB.getInt8Ty (), Fn->size ()));
260
+ // FIXME: Pass option form clang.
202
261
TrapCall->addFnAttr (llvm::Attribute::NoMerge);
203
- } else {
204
- TrapCall = IRB.CreateIntrinsic (IntrID, {}, {});
205
262
}
206
263
207
- TrapCall->setDoesNotReturn ();
208
264
TrapCall->setDoesNotThrow ();
209
265
TrapCall->setDebugLoc (DebugLoc);
210
- IRB.CreateUnreachable ();
266
+ if (Opts.MayReturn ) {
267
+ IRB.CreateBr (Cont);
268
+ } else {
269
+ TrapCall->setDoesNotReturn ();
270
+ IRB.CreateUnreachable ();
271
+ }
272
+
273
+ if (!Opts.MayReturn && SingleTrapBB && !DebugTrapBB)
274
+ ReuseTrapBB = TrapBB;
211
275
212
276
return TrapBB;
213
277
};
214
278
215
- // Add the checks.
216
279
for (const auto &Entry : TrapInfo) {
217
280
Instruction *Inst = Entry.first ;
218
281
BuilderTy IRB (Inst->getParent (), BasicBlock::iterator (Inst), TargetFolder (DL));
@@ -226,7 +289,7 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &
226
289
auto &TLI = AM.getResult <TargetLibraryAnalysis>(F);
227
290
auto &SE = AM.getResult <ScalarEvolutionAnalysis>(F);
228
291
229
- if (!addBoundsChecking (F, TLI, SE))
292
+ if (!addBoundsChecking (F, TLI, SE, ReportingOpts (Mode) ))
230
293
return PreservedAnalyses::all ();
231
294
232
295
return PreservedAnalyses::none ();
0 commit comments