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,29 @@ 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+ return IRB.CreateIntrinsic (
112+ Intrinsic::ubsantrap, {},
113+ ConstantInt::get (IRB.getInt8Ty (),
114+ IRB.GetInsertBlock ()->getParent ()->size ()));
115+ }
116+
117+ static CallInst *InsertCall (BuilderTy &IRB, bool MayReturn, StringRef Name) {
118+ Function *Fn = IRB.GetInsertBlock ()->getParent ();
119+ LLVMContext &Ctx = Fn->getContext ();
120+ llvm::AttrBuilder B (Ctx);
121+ B.addAttribute (llvm::Attribute::NoUnwind);
122+ if (!MayReturn)
123+ B.addAttribute (llvm::Attribute::NoReturn);
124+ FunctionCallee Callee = Fn->getParent ()->getOrInsertFunction (
125+ Name,
126+ llvm::AttributeList::get (Ctx, llvm::AttributeList::FunctionIndex, B),
127+ Type::getVoidTy (Ctx));
128+ return IRB.CreateCall (Callee);
129+ }
130+
107131// / Adds run-time bounds checks to memory accessing instructions.
108132// /
109133// / \p Or is the condition that should guard the trap.
@@ -126,20 +150,53 @@ static void insertBoundsCheck(Value *Or, BuilderTy &IRB, GetTrapBBT GetTrapBB) {
126150 BasicBlock *Cont = OldBB->splitBasicBlock (SplitI);
127151 OldBB->getTerminator ()->eraseFromParent ();
128152
153+ BasicBlock *TrapBB = GetTrapBB (IRB, Cont);
154+
129155 if (C) {
130156 // If we have a constant zero, unconditionally branch.
131157 // FIXME: We should really handle this differently to bypass the splitting
132158 // the block.
133- BranchInst::Create (GetTrapBB (IRB) , OldBB);
159+ BranchInst::Create (TrapBB , OldBB);
134160 return ;
135161 }
136162
137163 // Create the conditional branch.
138- BranchInst::Create (GetTrapBB (IRB) , Cont, Or, OldBB);
164+ BranchInst::Create (TrapBB , Cont, Or, OldBB);
139165}
140166
167+ struct ReportingOpts {
168+ bool MayReturn = false ;
169+ bool UseTrap = false ;
170+ bool MinRuntime = false ;
171+ StringRef Name;
172+
173+ ReportingOpts (BoundsCheckingPass::ReportingMode Mode) {
174+ switch (Mode) {
175+ case BoundsCheckingPass::ReportingMode::Trap:
176+ UseTrap = true ;
177+ break ;
178+ case BoundsCheckingPass::ReportingMode::MinRuntime:
179+ Name = " __ubsan_handle_local_out_of_bounds_minimal" ;
180+ MinRuntime = true ;
181+ MayReturn = true ;
182+ break ;
183+ case BoundsCheckingPass::ReportingMode::MinRuntimeAbort:
184+ Name = " __ubsan_handle_local_out_of_bounds_minimal_abort" ;
185+ MinRuntime = true ;
186+ break ;
187+ case BoundsCheckingPass::ReportingMode::FullRuntime:
188+ Name = " __ubsan_handle_local_out_of_bounds" ;
189+ MayReturn = true ;
190+ break ;
191+ case BoundsCheckingPass::ReportingMode::FullRuntimeAbort:
192+ Name = " __ubsan_handle_local_out_of_bounds_abort" ;
193+ break ;
194+ }
195+ }
196+ };
197+
141198static bool addBoundsChecking (Function &F, TargetLibraryInfo &TLI,
142- ScalarEvolution &SE) {
199+ ScalarEvolution &SE, const ReportingOpts &Opts ) {
143200 if (F.hasFnAttribute (Attribute::NoSanitizeBounds))
144201 return false ;
145202
@@ -180,37 +237,40 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
180237 // Create a trapping basic block on demand using a callback. Depending on
181238 // flags, this will either create a single block for the entire function or
182239 // will create a fresh block every time it is called.
183- BasicBlock *TrapBB = nullptr ;
184- auto GetTrapBB = [&TrapBB ](BuilderTy &IRB) {
240+ BasicBlock *ReuseTrapBB = nullptr ;
241+ auto GetTrapBB = [&ReuseTrapBB, &Opts ](BuilderTy &IRB, BasicBlock *Cont ) {
185242 Function *Fn = IRB.GetInsertBlock ()->getParent ();
186243 auto DebugLoc = IRB.getCurrentDebugLocation ();
187244 IRBuilder<>::InsertPointGuard Guard (IRB);
188245
189- if (TrapBB && SingleTrapBB && !DebugTrapBB)
190- return TrapBB;
246+ // Create a trapping basic block on demand using a callback. Depending on
247+ // flags, this will either create a single block for the entire function or
248+ // will create a fresh block every time it is called.
249+ if (ReuseTrapBB)
250+ return ReuseTrapBB;
191251
192- TrapBB = BasicBlock::Create (Fn->getContext (), " trap" , Fn);
252+ BasicBlock * TrapBB = BasicBlock::Create (Fn->getContext (), " trap" , Fn);
193253 IRB.SetInsertPoint (TrapBB);
194254
195- Intrinsic::ID IntrID = DebugTrapBB ? Intrinsic::ubsantrap : Intrinsic::trap;
255+ CallInst *TrapCall = Opts.UseTrap
256+ ? InsertTrap (IRB)
257+ : InsertCall (IRB, Opts.MayReturn , Opts.Name );
196258
197- CallInst * TrapCall;
198- if (DebugTrapBB) {
199- TrapCall = IRB. CreateIntrinsic (
200- IntrID, {}, ConstantInt::get ( IRB.getInt8Ty (), Fn-> size ()) );
259+ TrapCall-> setDoesNotThrow () ;
260+ TrapCall-> setDebugLoc (DebugLoc);
261+ if (Opts. MayReturn ) {
262+ IRB.CreateBr (Cont );
201263 } else {
202- TrapCall = IRB.CreateIntrinsic (IntrID, {}, {});
264+ TrapCall->setDoesNotReturn ();
265+ IRB.CreateUnreachable ();
203266 }
204267
205- TrapCall->setDoesNotReturn ();
206- TrapCall->setDoesNotThrow ();
207- TrapCall->setDebugLoc (DebugLoc);
208- IRB.CreateUnreachable ();
268+ if (!Opts.MayReturn && SingleTrapBB && !DebugTrapBB)
269+ ReuseTrapBB = TrapBB;
209270
210271 return TrapBB;
211272 };
212273
213- // Add the checks.
214274 for (const auto &Entry : TrapInfo) {
215275 Instruction *Inst = Entry.first ;
216276 BuilderTy IRB (Inst->getParent (), BasicBlock::iterator (Inst), TargetFolder (DL));
@@ -224,7 +284,7 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &
224284 auto &TLI = AM.getResult <TargetLibraryAnalysis>(F);
225285 auto &SE = AM.getResult <ScalarEvolutionAnalysis>(F);
226286
227- if (!addBoundsChecking (F, TLI, SE))
287+ if (!addBoundsChecking (F, TLI, SE, ReportingOpts (Mode) ))
228288 return PreservedAnalyses::all ();
229289
230290 return PreservedAnalyses::none ();
@@ -251,4 +311,4 @@ void BoundsCheckingPass::printPipeline(
251311 OS << " <rt-abort>" ;
252312 break ;
253313 }
254- }
314+ }
0 commit comments