diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/StackProtector.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/CodeGen/StackProtector.cpp | 93 |
1 files changed, 58 insertions, 35 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/StackProtector.cpp b/contrib/llvm-project/llvm/lib/CodeGen/StackProtector.cpp index fca822a485ca..3ec70083b704 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/StackProtector.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/StackProtector.cpp @@ -14,12 +14,12 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/StackProtector.h" -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetPassConfig.h" @@ -76,7 +76,7 @@ static bool InsertStackProtectors(const TargetMachine *TM, Function *F, /// CreateFailBB - Create a basic block to jump to when the stack protector /// check fails. -static BasicBlock *CreateFailBB(Function *F, const Triple &Trip); +static BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI); bool SSPLayoutInfo::shouldEmitSDCheck(const BasicBlock &BB) const { return HasPrologue && !HasIRCheck && isa<ReturnInst>(BB.getTerminator()); @@ -136,7 +136,8 @@ PreservedAnalyses StackProtectorPass::run(Function &F, bool Changed = InsertStackProtectors(TM, &F, DT ? &DTU : nullptr, Info.HasPrologue, Info.HasIRCheck); #ifdef EXPENSIVE_CHECKS - assert((!DT || DT->verify(DominatorTree::VerificationLevel::Full)) && + assert((!DT || + DTU.getDomTree().verify(DominatorTree::VerificationLevel::Full)) && "Failed to maintain validity of domtree!"); #endif @@ -217,7 +218,7 @@ static bool ContainsProtectableArray(Type *Ty, Module *M, unsigned SSPBufferSize // add stack protectors unless the array is a character array. // However, in strong mode any array, regardless of type and size, // triggers a protector. - if (!Strong && (InStruct || !Triple(M->getTargetTriple()).isOSDarwin())) + if (!Strong && (InStruct || !M->getTargetTriple().isOSDarwin())) return false; } @@ -251,10 +252,21 @@ static bool ContainsProtectableArray(Type *Ty, Module *M, unsigned SSPBufferSize return NeedsProtector; } +/// Maximum remaining allocation size observed for a phi node, and how often +/// the allocation size has already been decreased. We only allow a limited +/// number of decreases. +struct PhiInfo { + TypeSize AllocSize; + unsigned NumDecreased = 0; + static constexpr unsigned MaxNumDecreased = 3; + PhiInfo(TypeSize AllocSize) : AllocSize(AllocSize) {} +}; +using PhiMap = SmallDenseMap<const PHINode *, PhiInfo, 16>; + /// Check whether a stack allocation has its address taken. static bool HasAddressTaken(const Instruction *AI, TypeSize AllocSize, Module *M, - SmallPtrSet<const PHINode *, 16> &VisitedPHIs) { + PhiMap &VisitedPHIs) { const DataLayout &DL = M->getDataLayout(); for (const User *U : AI->users()) { const auto *I = cast<Instruction>(U); @@ -275,6 +287,10 @@ static bool HasAddressTaken(const Instruction *AI, TypeSize AllocSize, if (AI == cast<AtomicCmpXchgInst>(I)->getNewValOperand()) return true; break; + case Instruction::AtomicRMW: + if (AI == cast<AtomicRMWInst>(I)->getValOperand()) + return true; + break; case Instruction::PtrToInt: if (AI == cast<PtrToIntInst>(I)->getOperand(0)) return true; @@ -321,19 +337,26 @@ static bool HasAddressTaken(const Instruction *AI, TypeSize AllocSize, // Keep track of what PHI nodes we have already visited to ensure // they are only visited once. const auto *PN = cast<PHINode>(I); - if (VisitedPHIs.insert(PN).second) - if (HasAddressTaken(PN, AllocSize, M, VisitedPHIs)) + auto [It, Inserted] = VisitedPHIs.try_emplace(PN, AllocSize); + if (!Inserted) { + if (TypeSize::isKnownGE(AllocSize, It->second.AllocSize)) + break; + + // Check again with smaller size. + if (It->second.NumDecreased == PhiInfo::MaxNumDecreased) return true; + + It->second.AllocSize = AllocSize; + ++It->second.NumDecreased; + } + if (HasAddressTaken(PN, AllocSize, M, VisitedPHIs)) + return true; break; } case Instruction::Load: - case Instruction::AtomicRMW: case Instruction::Ret: // These instructions take an address operand, but have load-like or // other innocuous behavior that should not trigger a stack protector. - // atomicrmw conceptually has both load and store semantics, but the - // value being stored must be integer; so if a pointer is being stored, - // we'll catch it in the PtrToInt case above. break; default: // Conservatively return true for any instruction that takes an address @@ -377,7 +400,7 @@ bool SSPLayoutAnalysis::requiresStackProtector(Function *F, // The set of PHI nodes visited when determining if a variable's reference has // been taken. This set is maintained to ensure we don't visit the same PHI // node multiple times. - SmallPtrSet<const PHINode *, 16> VisitedPHIs; + PhiMap VisitedPHIs; unsigned SSPBufferSize = F->getFnAttributeAsParsedInteger( "stack-protector-buffer-size", SSPLayoutInfo::DefaultSSPBufferSize); @@ -519,7 +542,7 @@ static Value *getStackGuard(const TargetLoweringBase *TLI, Module *M, if (SupportsSelectionDAGSP) *SupportsSelectionDAGSP = true; TLI->insertSSPDeclarations(*M); - return B.CreateCall(Intrinsic::getDeclaration(M, Intrinsic::stackguard)); + return B.CreateIntrinsic(Intrinsic::stackguard, {}); } /// Insert code into the entry block that stores the stack guard @@ -540,8 +563,7 @@ static bool CreatePrologue(Function *F, Module *M, Instruction *CheckLoc, AI = B.CreateAlloca(PtrTy, nullptr, "StackGuardSlot"); Value *GuardSlot = getStackGuard(TLI, M, B, &SupportsSelectionDAGSP); - B.CreateCall(Intrinsic::getDeclaration(M, Intrinsic::stackprotector), - {GuardSlot, AI}); + B.CreateIntrinsic(Intrinsic::stackprotector, {GuardSlot, AI}); return SupportsSelectionDAGSP; } @@ -603,18 +625,11 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F, HasIRCheck = true; // If we're instrumenting a block with a tail call, the check has to be - // inserted before the call rather than between it and the return. The - // verifier guarantees that a tail call is either directly before the - // return or with a single correct bitcast of the return value in between so - // we don't need to worry about many situations here. + // inserted before the call rather than between it and the return. Instruction *Prev = CheckLoc->getPrevNonDebugInstruction(); - if (Prev && isa<CallInst>(Prev) && cast<CallInst>(Prev)->isTailCall()) - CheckLoc = Prev; - else if (Prev) { - Prev = Prev->getPrevNonDebugInstruction(); - if (Prev && isa<CallInst>(Prev) && cast<CallInst>(Prev)->isTailCall()) + if (auto *CI = dyn_cast_if_present<CallInst>(Prev)) + if (CI->isTailCall() && isInTailCallPosition(*CI, *TM)) CheckLoc = Prev; - } // Generate epilogue instrumentation. The epilogue intrumentation can be // function-based or inlined depending on which mechanism the target is @@ -658,7 +673,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F, // merge pass will merge together all of the various BB into one including // fail BB generated by the stack protector pseudo instruction. if (!FailBB) - FailBB = CreateFailBB(F, TM->getTargetTriple()); + FailBB = CreateFailBB(F, *TLI); IRBuilder<> B(CheckLoc); Value *Guard = getStackGuard(TLI, M, B); @@ -691,7 +706,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F, return HasPrologue; } -BasicBlock *CreateFailBB(Function *F, const Triple &Trip) { +BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI) { auto *M = F->getParent(); LLVMContext &Context = F->getContext(); BasicBlock *FailBB = BasicBlock::Create(Context, "CallStackCheckFailBlk", F); @@ -701,17 +716,25 @@ BasicBlock *CreateFailBB(Function *F, const Triple &Trip) { DILocation::get(Context, 0, 0, F->getSubprogram())); FunctionCallee StackChkFail; SmallVector<Value *, 1> Args; - if (Trip.isOSOpenBSD()) { - StackChkFail = M->getOrInsertFunction("__stack_smash_handler", - Type::getVoidTy(Context), + + if (const char *ChkFailName = + TLI.getLibcallName(RTLIB::STACKPROTECTOR_CHECK_FAIL)) { + StackChkFail = + M->getOrInsertFunction(ChkFailName, Type::getVoidTy(Context)); + } else if (const char *SSHName = + TLI.getLibcallName(RTLIB::STACK_SMASH_HANDLER)) { + StackChkFail = M->getOrInsertFunction(SSHName, Type::getVoidTy(Context), PointerType::getUnqual(Context)); - Args.push_back(B.CreateGlobalStringPtr(F->getName(), "SSH")); + Args.push_back(B.CreateGlobalString(F->getName(), "SSH")); } else { - StackChkFail = - M->getOrInsertFunction("__stack_chk_fail", Type::getVoidTy(Context)); + Context.emitError("no libcall available for stack protector"); + } + + if (StackChkFail) { + cast<Function>(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn); + B.CreateCall(StackChkFail, Args); } - cast<Function>(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn); - B.CreateCall(StackChkFail, Args); + B.CreateUnreachable(); return FailBB; } |
