4141#include " llvm/IR/IRBuilder.h"
4242#include " llvm/IR/Instructions.h"
4343#include " llvm/IR/IntrinsicInst.h"
44+ #include " llvm/Support/CommandLine.h"
4445#include " llvm/Transforms/Utils/BasicBlockUtils.h"
4546#include " llvm/Transforms/Utils/Cloning.h"
4647
@@ -50,6 +51,10 @@ using namespace llvm;
5051
5152STATISTIC (NumIsolatedBlocks, " Number of isolated blocks" );
5253
54+ static cl::opt<bool > ConvertUBToTrapUnreachable (
55+ " isolate-ub-path-to-trap-unreachable" , cl::init(false ), cl::Hidden,
56+ cl::desc(" Isolate the UB path into one with a 'trap-unreachable' pair." ));
57+
5358// / Look through GEPs to see if the nullptr is accessed.
5459static bool HasUBAccess (BasicBlock *Parent, GetElementPtrInst *GEP) {
5560 for (Value *V : GEP->materialized_users ()) {
@@ -152,81 +157,86 @@ bool IsolatePathPass::ProcessPointerUndefinedBehavior(BasicBlock *BB,
152157 else
153158 NonUBPhiPreds.insert (FirstUBPhiNode->getIncomingBlock (Index++));
154159
160+ if (NonUBPhiPreds.empty ())
161+ // All paths have undefined behavior. Other passes will deal with this
162+ // code.
163+ return false ;
164+
155165 SmallVector<DominatorTree::UpdateType, 8 > Updates;
156166 BasicBlock *UBBlock = nullptr ;
157- if (NonUBPhiPreds.empty ()) {
158- // All PHI node values cause UB in the block. Just add the 'trap'
159- // instruction without cloning.
160- UBBlock = BB;
161-
162- // Remove the block from any successors.
163- for (BasicBlock *Succ : successors (BB)) {
164- Succ->removePredecessor (BB);
165- Updates.push_back ({DominatorTree::Delete, BB, Succ});
166- }
167- } else {
168- // Clone the block, isolating the UB instructions on their own path.
169- ValueToValueMapTy VMap;
170- UBBlock = CloneBasicBlock (BB, VMap, " .ub.path" , BB->getParent ());
171- VMap[BB] = UBBlock;
172- ++NumIsolatedBlocks;
173-
174- // Replace the UB predecessors' terminators' targets with the new block.
175- llvm::for_each (UBPhiPreds, [&](BasicBlock *Pred) {
176- Pred->getTerminator ()->replaceSuccessorWith (BB, UBBlock);
167+
168+ // Clone the block, isolating the UB instructions on their own path.
169+ ValueToValueMapTy VMap;
170+ UBBlock = CloneBasicBlock (BB, VMap, " .ub.path" , BB->getParent ());
171+ VMap[BB] = UBBlock;
172+ ++NumIsolatedBlocks;
173+
174+ // Replace the UB predecessors' terminators' targets with the new block.
175+ llvm::for_each (UBPhiPreds, [&](BasicBlock *Pred) {
176+ Pred->getTerminator ()->replaceSuccessorWith (BB, UBBlock);
177+ });
178+
179+ // Remove predecessors of isolated paths from the original PHI nodes.
180+ for (PHINode &PN : BB->phis ())
181+ PN.removeIncomingValueIf ([&](unsigned I) {
182+ return UBPhiPreds.contains (PN.getIncomingBlock (I));
177183 });
178184
179- // Remove predecessors of isolated paths from the original PHI nodes.
180- for (PHINode &PN : BB->phis ())
181- PN.removeIncomingValueIf ([&](unsigned I) {
182- return UBPhiPreds.contains (PN.getIncomingBlock (I));
183- });
184-
185- // Remove predecessors of valid paths from the isolated path PHI nodes.
186- for (PHINode &PN : UBBlock->phis ())
187- PN.removeIncomingValueIf ([&](unsigned I) {
188- return NonUBPhiPreds.contains (PN.getIncomingBlock (I));
189- });
190-
191- // Rewrite the instructions in the cloned block to refer to the instructions
192- // in the cloned block.
193- for (auto &I : *UBBlock) {
194- RemapDbgRecordRange (BB->getModule (), I.getDbgRecordRange (), VMap,
195- RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
196- RemapInstruction (&I, VMap,
197- RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
198- }
185+ // Remove predecessors of valid paths from the isolated path PHI nodes.
186+ for (PHINode &PN : UBBlock->phis ())
187+ PN.removeIncomingValueIf ([&](unsigned I) {
188+ return NonUBPhiPreds.contains (PN.getIncomingBlock (I));
189+ });
199190
200- // Update the dominator tree.
201- for (auto *Pred : UBPhiPreds) {
202- Updates.push_back ({DominatorTree::Insert, Pred, UBBlock});
203- Updates.push_back ({DominatorTree::Delete, Pred, BB});
204- }
191+ // Rewrite the instructions in the cloned block to refer to the instructions
192+ // in the cloned block.
193+ for (auto &I : *UBBlock) {
194+ RemapDbgRecordRange (BB->getModule (), I.getDbgRecordRange (), VMap,
195+ RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
196+ RemapInstruction (&I, VMap,
197+ RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
205198 }
206199
207- // Get the index into the block of the first UB instruction.
208- unsigned UBIndex = 0 ;
209- for (auto Iter = BB->begin (); Iter != BB->end (); ++Iter, ++UBIndex)
210- if (&*Iter == FirstUBInst) {
211- if (isa<LoadInst>(FirstUBInst))
212- ++UBIndex;
213- break ;
214- }
200+ // Update the dominator tree.
201+ for (auto *Pred : UBPhiPreds) {
202+ Updates.push_back ({DominatorTree::Insert, Pred, UBBlock});
203+ Updates.push_back ({DominatorTree::Delete, Pred, BB});
204+ }
205+
206+ if (ConvertUBToTrapUnreachable) {
207+ // Isolate the UB path into a trap-unreachable instruction.
208+ unsigned UBIndex = 0 ;
215209
216- // Remove the instructions following the nullptr dereference.
217- for (unsigned Index = UBBlock->size (); Index > UBIndex; --Index)
218- UBBlock->rbegin ()->eraseFromParent ();
210+ // Get the index into the block of the first UB instruction.
211+ for (auto Iter = BB->begin (); Iter != BB->end (); ++Iter, ++UBIndex)
212+ if (&*Iter == FirstUBInst) {
213+ if (isa<LoadInst>(FirstUBInst))
214+ ++UBIndex;
215+ break ;
216+ }
219217
220- // Allow the NULL dereference to actually occur so that code that wishes to
221- // catch the signal can do so.
222- if (const auto *LI = dyn_cast<LoadInst>(&*UBBlock->rbegin ()))
223- const_cast <LoadInst *>(LI)->setVolatile (true );
218+ // Remove the instructions following the nullptr dereference.
219+ for (unsigned Index = UBBlock->size (); Index > UBIndex; --Index)
220+ UBBlock->rbegin ()->eraseFromParent ();
221+
222+ // Allow the NULL dereference to actually occur so that code that wishes to
223+ // catch the signal can do so.
224+ if (const auto *LI = dyn_cast<LoadInst>(&*UBBlock->rbegin ()))
225+ const_cast <LoadInst *>(LI)->setVolatile (true );
226+
227+ // Add a 'trap()' call.
228+ IRBuilder<> Builder (UBBlock);
229+ Function *TrapDecl =
230+ Intrinsic::getOrInsertDeclaration (BB->getModule (), Intrinsic::trap);
231+ Builder.CreateCall (TrapDecl);
232+ } else {
233+ // Remove all instructions.
234+ for (unsigned Index = UBBlock->size (); Index > 0 ; --Index)
235+ UBBlock->rbegin ()->eraseFromParent ();
236+ }
224237
225- // Add a 'trap()' call followed by an 'unreachable' terminator .
238+ // End in an 'unreachable' instruction .
226239 IRBuilder<> Builder (UBBlock);
227- Function *TrapDecl =
228- Intrinsic::getOrInsertDeclaration (BB->getModule (), Intrinsic::trap);
229- Builder.CreateCall (TrapDecl);
230240 Builder.CreateUnreachable ();
231241
232242 if (!Updates.empty ())
0 commit comments