diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -47,6 +47,11 @@ using namespace clang; using namespace CodeGen; +// Experiment to make sanitizers easier to debug +static llvm::cl::opt ClSanitizeDebugDeoptimization( + "sanitizer-de-opt-traps", llvm::cl::Optional, + llvm::cl::desc("Deoptimize traps for sanitizers"), llvm::cl::init(false)); + //===--------------------------------------------------------------------===// // Miscellaneous Helper Methods //===--------------------------------------------------------------------===// @@ -3568,22 +3573,20 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID) { - llvm::BasicBlock *Cont = createBasicBlock("cont"); + if (ClSanitizeDebugDeoptimization) { + llvm::BasicBlock *Cont = createBasicBlock("cont"); - // If we're optimizing, collapse all calls to trap down to just one per - // check-type per function to save on code size. - if (TrapBBs.size() <= CheckHandlerID) - TrapBBs.resize(CheckHandlerID + 1); - llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID]; + if (TrapBBs.size() <= CheckHandlerID) + TrapBBs.resize(CheckHandlerID + 1); + llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID]; - if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB) { TrapBB = createBasicBlock("trap"); Builder.CreateCondBr(Checked, Cont, TrapBB); EmitBlock(TrapBB); llvm::CallInst *TrapCall = Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap), - llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID)); + llvm::ConstantInt::get(CGM.Int8Ty, TrapBB->getParent()->size())); if (!CGM.getCodeGenOpts().TrapFuncName.empty()) { auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name", @@ -3593,16 +3596,46 @@ TrapCall->setDoesNotReturn(); TrapCall->setDoesNotThrow(); Builder.CreateUnreachable(); + + EmitBlock(Cont); } else { - auto Call = TrapBB->begin(); - assert(isa(Call) && "Expected call in trap BB"); + llvm::BasicBlock *Cont = createBasicBlock("cont"); + + // If we're optimizing, collapse all calls to trap down to just one per + // check-type per function to save on code size. + if (TrapBBs.size() <= CheckHandlerID) + TrapBBs.resize(CheckHandlerID + 1); + llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID]; + + if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB || + (CurCodeDecl && CurCodeDecl->hasAttr())) { + TrapBB = createBasicBlock("trap"); + Builder.CreateCondBr(Checked, Cont, TrapBB); + EmitBlock(TrapBB); + + llvm::CallInst *TrapCall = Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::ubsantrap), + llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID)); + + if (!CGM.getCodeGenOpts().TrapFuncName.empty()) { + auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name", + CGM.getCodeGenOpts().TrapFuncName); + TrapCall->addFnAttr(A); + } + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + } else { + auto Call = TrapBB->begin(); + assert(isa(Call) && "Expected call in trap BB"); - Call->applyMergedLocation(Call->getDebugLoc(), - Builder.getCurrentDebugLocation()); - Builder.CreateCondBr(Checked, Cont, TrapBB); - } + Call->applyMergedLocation(Call->getDebugLoc(), + Builder.getCurrentDebugLocation()); + Builder.CreateCondBr(Checked, Cont, TrapBB); + } - EmitBlock(Cont); + EmitBlock(Cont); + } } llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) { diff --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp --- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -39,6 +39,10 @@ static cl::opt SingleTrapBB("bounds-checking-single-trap", cl::desc("Use one trap block per function")); +static cl::opt + DebugTrapBB("bounds-checking-debug-trap", + cl::desc("Use one trap block per check despite optimizations")); + STATISTIC(ChecksAdded, "Bounds checks added"); STATISTIC(ChecksSkipped, "Bounds checks skipped"); STATISTIC(ChecksUnable, "Bounds checks unable to add"); @@ -181,24 +185,39 @@ // will create a fresh block every time it is called. BasicBlock *TrapBB = nullptr; auto GetTrapBB = [&TrapBB](BuilderTy &IRB) { - if (TrapBB && SingleTrapBB) - return TrapBB; - - Function *Fn = IRB.GetInsertBlock()->getParent(); - // FIXME: This debug location doesn't make a lot of sense in the - // `SingleTrapBB` case. - auto DebugLoc = IRB.getCurrentDebugLocation(); - IRBuilder<>::InsertPointGuard Guard(IRB); - TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn); - IRB.SetInsertPoint(TrapBB); - - auto *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap); - CallInst *TrapCall = IRB.CreateCall(F, {}); - TrapCall->setDoesNotReturn(); - TrapCall->setDoesNotThrow(); - TrapCall->setDebugLoc(DebugLoc); - IRB.CreateUnreachable(); - + if (DebugTrapBB) { + Function *Fn = IRB.GetInsertBlock()->getParent(); + auto DebugLoc = IRB.getCurrentDebugLocation(); + IRBuilder<>::InsertPointGuard Guard(IRB); + TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn); + IRB.SetInsertPoint(TrapBB); + auto *F = + Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::ubsantrap); + CallInst *TrapCall = + IRB.CreateCall(F, ConstantInt::get(IRB.getInt8Ty(), Fn->size())); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + TrapCall->setDebugLoc(DebugLoc); + IRB.CreateUnreachable(); + } else { + if (TrapBB && SingleTrapBB) + return TrapBB; + + Function *Fn = IRB.GetInsertBlock()->getParent(); + // FIXME: This debug location doesn't make a lot of sense in the + // `SingleTrapBB` case. + auto DebugLoc = IRB.getCurrentDebugLocation(); + IRBuilder<>::InsertPointGuard Guard(IRB); + TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn); + IRB.SetInsertPoint(TrapBB); + + auto *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap); + CallInst *TrapCall = IRB.CreateCall(F, {}); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + TrapCall->setDebugLoc(DebugLoc); + IRB.CreateUnreachable(); + } return TrapBB; };