88
99#include " llvm/Transforms/Instrumentation/BoundsChecking.h"
1010#include " llvm/ADT/Statistic.h"
11+ #include " llvm/ADT/StringRef.h"
1112#include " llvm/ADT/Twine.h"
1213#include " llvm/Analysis/MemoryBuiltins.h"
1314#include " llvm/Analysis/ScalarEvolution.h"
@@ -104,6 +105,30 @@ static Value *getBoundsCheckCond(Value *Ptr, Value *InstVal,
104105 return Or;
105106}
106107
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+
107132// / Adds run-time bounds checks to memory accessing instructions.
108133// /
109134// / \p Or is the condition that should guard the trap.
@@ -126,20 +151,53 @@ static void insertBoundsCheck(Value *Or, BuilderTy &IRB, GetTrapBBT GetTrapBB) {
126151 BasicBlock *Cont = OldBB->splitBasicBlock (SplitI);
127152 OldBB->getTerminator ()->eraseFromParent ();
128153
154+ BasicBlock *TrapBB = GetTrapBB (IRB, Cont);
155+
129156 if (C) {
130157 // If we have a constant zero, unconditionally branch.
131158 // FIXME: We should really handle this differently to bypass the splitting
132159 // the block.
133- BranchInst::Create (GetTrapBB (IRB) , OldBB);
160+ BranchInst::Create (TrapBB , OldBB);
134161 return ;
135162 }
136163
137164 // Create the conditional branch.
138- BranchInst::Create (GetTrapBB (IRB) , Cont, Or, OldBB);
165+ BranchInst::Create (TrapBB , Cont, Or, OldBB);
139166}
140167
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+
141199static bool addBoundsChecking (Function &F, TargetLibraryInfo &TLI,
142- ScalarEvolution &SE) {
200+ ScalarEvolution &SE, const ReportingOpts &Opts ) {
143201 if (F.hasFnAttribute (Attribute::NoSanitizeBounds))
144202 return false ;
145203
@@ -180,39 +238,44 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
180238 // Create a trapping basic block on demand using a callback. Depending on
181239 // flags, this will either create a single block for the entire function or
182240 // 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 ) {
185243 Function *Fn = IRB.GetInsertBlock ()->getParent ();
186244 auto DebugLoc = IRB.getCurrentDebugLocation ();
187245 IRBuilder<>::InsertPointGuard Guard (IRB);
188246
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;
191252
192- TrapBB = BasicBlock::Create (Fn->getContext (), " trap" , Fn);
253+ BasicBlock * TrapBB = BasicBlock::Create (Fn->getContext (), " trap" , Fn);
193254 IRB.SetInsertPoint (TrapBB);
194255
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 ) ;
198259 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.
202261 TrapCall->addFnAttr (llvm::Attribute::NoMerge);
203- } else {
204- TrapCall = IRB.CreateIntrinsic (IntrID, {}, {});
205262 }
206263
207- TrapCall->setDoesNotReturn ();
208264 TrapCall->setDoesNotThrow ();
209265 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;
211275
212276 return TrapBB;
213277 };
214278
215- // Add the checks.
216279 for (const auto &Entry : TrapInfo) {
217280 Instruction *Inst = Entry.first ;
218281 BuilderTy IRB (Inst->getParent (), BasicBlock::iterator (Inst), TargetFolder (DL));
@@ -226,7 +289,7 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &
226289 auto &TLI = AM.getResult <TargetLibraryAnalysis>(F);
227290 auto &SE = AM.getResult <ScalarEvolutionAnalysis>(F);
228291
229- if (!addBoundsChecking (F, TLI, SE))
292+ if (!addBoundsChecking (F, TLI, SE, ReportingOpts (Mode) ))
230293 return PreservedAnalyses::all ();
231294
232295 return PreservedAnalyses::none ();
0 commit comments