diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/StackSafetyAnalysis.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Analysis/StackSafetyAnalysis.cpp | 118 |
1 files changed, 76 insertions, 42 deletions
diff --git a/contrib/llvm-project/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/contrib/llvm-project/llvm/lib/Analysis/StackSafetyAnalysis.cpp index 76f195fedf31..74cc39b7f2c0 100644 --- a/contrib/llvm-project/llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ b/contrib/llvm-project/llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <memory> +#include <tuple> using namespace llvm; @@ -116,6 +117,7 @@ template <typename CalleeTy> struct UseInfo { // Access range if the address (alloca or parameters). // It is allowed to be empty-set when there are no known accesses. ConstantRange Range; + std::map<const Instruction *, ConstantRange> Accesses; // List of calls which pass address as an argument. // Value is offset range of address from base address (alloca or calling @@ -129,6 +131,12 @@ template <typename CalleeTy> struct UseInfo { UseInfo(unsigned PointerSize) : Range{PointerSize, false} {} void updateRange(const ConstantRange &R) { Range = unionNoWrap(Range, R); } + void addRange(const Instruction *I, const ConstantRange &R) { + auto Ins = Accesses.emplace(I, R); + if (!Ins.second) + Ins.first->second = unionNoWrap(Ins.first->second, R); + updateRange(R); + } }; template <typename CalleeTy> @@ -146,7 +154,7 @@ raw_ostream &operator<<(raw_ostream &OS, const UseInfo<CalleeTy> &U) { ConstantRange getStaticAllocaSizeRange(const AllocaInst &AI) { const DataLayout &DL = AI.getModule()->getDataLayout(); TypeSize TS = DL.getTypeAllocSize(AI.getAllocatedType()); - unsigned PointerSize = DL.getMaxPointerSizeInBits(); + unsigned PointerSize = DL.getPointerTypeSizeInBits(AI.getType()); // Fallback to empty range for alloca size. ConstantRange R = ConstantRange::getEmpty(PointerSize); if (TS.isScalable()) @@ -167,7 +175,7 @@ ConstantRange getStaticAllocaSizeRange(const AllocaInst &AI) { if (Overflow) return R; } - R = ConstantRange(APInt::getNullValue(PointerSize), APSize); + R = ConstantRange(APInt::getZero(PointerSize), APSize); assert(!isUnsafe(R)); return R; } @@ -208,7 +216,6 @@ template <typename CalleeTy> struct FunctionInfo { } else { assert(Allocas.empty()); } - O << "\n"; } }; @@ -223,6 +230,7 @@ struct StackSafetyInfo::InfoTy { struct StackSafetyGlobalInfo::InfoTy { GVToSSI Info; SmallPtrSet<const AllocaInst *, 8> SafeAllocas; + std::map<const Instruction *, bool> AccessIsUnsafe; }; namespace { @@ -242,7 +250,7 @@ class StackSafetyLocalAnalysis { ConstantRange getMemIntrinsicAccessRange(const MemIntrinsic *MI, const Use &U, Value *Base); - bool analyzeAllUses(Value *Ptr, UseInfo<GlobalValue> &AS, + void analyzeAllUses(Value *Ptr, UseInfo<GlobalValue> &AS, const StackLifetime &SL); public: @@ -297,8 +305,8 @@ ConstantRange StackSafetyLocalAnalysis::getAccessRange(Value *Addr, Value *Base, APInt APSize(PointerSize, Size.getFixedSize(), true); if (APSize.isNegative()) return UnknownRange; - return getAccessRange( - Addr, Base, ConstantRange(APInt::getNullValue(PointerSize), APSize)); + return getAccessRange(Addr, Base, + ConstantRange(APInt::getZero(PointerSize), APSize)); } ConstantRange StackSafetyLocalAnalysis::getMemIntrinsicAccessRange( @@ -321,14 +329,13 @@ ConstantRange StackSafetyLocalAnalysis::getMemIntrinsicAccessRange( if (Sizes.getUpper().isNegative() || isUnsafe(Sizes)) return UnknownRange; Sizes = Sizes.sextOrTrunc(PointerSize); - ConstantRange SizeRange(APInt::getNullValue(PointerSize), - Sizes.getUpper() - 1); + ConstantRange SizeRange(APInt::getZero(PointerSize), Sizes.getUpper() - 1); return getAccessRange(U, Base, SizeRange); } /// The function analyzes all local uses of Ptr (alloca or argument) and /// calculates local access range and all function calls where it was used. -bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, +void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, UseInfo<GlobalValue> &US, const StackLifetime &SL) { SmallPtrSet<const Value *, 16> Visited; @@ -349,11 +356,11 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, switch (I->getOpcode()) { case Instruction::Load: { if (AI && !SL.isAliveAfter(AI, I)) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } - US.updateRange( - getAccessRange(UI, Ptr, DL.getTypeStoreSize(I->getType()))); + US.addRange(I, + getAccessRange(UI, Ptr, DL.getTypeStoreSize(I->getType()))); break; } @@ -363,15 +370,16 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, case Instruction::Store: { if (V == I->getOperand(0)) { // Stored the pointer - conservatively assume it may be unsafe. - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } if (AI && !SL.isAliveAfter(AI, I)) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } - US.updateRange(getAccessRange( - UI, Ptr, DL.getTypeStoreSize(I->getOperand(0)->getType()))); + US.addRange( + I, getAccessRange( + UI, Ptr, DL.getTypeStoreSize(I->getOperand(0)->getType()))); break; } @@ -379,8 +387,8 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, // Information leak. // FIXME: Process parameters correctly. This is a leak only if we return // alloca. - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; case Instruction::Call: case Instruction::Invoke: { @@ -388,25 +396,31 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, break; if (AI && !SL.isAliveAfter(AI, I)) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) { - US.updateRange(getMemIntrinsicAccessRange(MI, UI, Ptr)); + US.addRange(I, getMemIntrinsicAccessRange(MI, UI, Ptr)); break; } const auto &CB = cast<CallBase>(*I); + if (CB.getReturnedArgOperand() == V) { + if (Visited.insert(I).second) + WorkList.push_back(cast<const Instruction>(I)); + } + if (!CB.isArgOperand(&UI)) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } unsigned ArgNo = CB.getArgOperandNo(&UI); if (CB.isByValArgument(ArgNo)) { - US.updateRange(getAccessRange( - UI, Ptr, DL.getTypeStoreSize(CB.getParamByValType(ArgNo)))); + US.addRange(I, getAccessRange( + UI, Ptr, + DL.getTypeStoreSize(CB.getParamByValType(ArgNo)))); break; } @@ -416,8 +430,8 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, const GlobalValue *Callee = dyn_cast<GlobalValue>(CB.getCalledOperand()->stripPointerCasts()); if (!Callee) { - US.updateRange(UnknownRange); - return false; + US.addRange(I, UnknownRange); + break; } assert(isa<Function>(Callee) || isa<GlobalAlias>(Callee)); @@ -435,8 +449,6 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, } } } - - return true; } FunctionInfo<GlobalValue> StackSafetyLocalAnalysis::run() { @@ -468,7 +480,7 @@ FunctionInfo<GlobalValue> StackSafetyLocalAnalysis::run() { } LLVM_DEBUG(Info.print(dbgs(), F.getName(), &F)); - LLVM_DEBUG(dbgs() << "[StackSafety] done\n"); + LLVM_DEBUG(dbgs() << "\n[StackSafety] done\n"); return Info; } @@ -588,8 +600,7 @@ void StackSafetyDataFlowAnalysis<CalleeTy>::runDataFlow() { updateAllNodes(); while (!WorkList.empty()) { - const CalleeTy *Callee = WorkList.back(); - WorkList.pop_back(); + const CalleeTy *Callee = WorkList.pop_back_val(); updateOneNode(Callee); } } @@ -674,7 +685,7 @@ const Function *findCalleeInModule(const GlobalValue *GV) { const GlobalAlias *A = dyn_cast<GlobalAlias>(GV); if (!A) return nullptr; - GV = A->getBaseObject(); + GV = A->getAliaseeObject(); if (GV == A) return nullptr; } @@ -741,10 +752,8 @@ GVToSSI createGlobalStackSafetyInfo( KV.second.Calls.clear(); } - uint32_t PointerSize = Copy.begin() - ->first->getParent() - ->getDataLayout() - .getMaxPointerSizeInBits(); + uint32_t PointerSize = + Copy.begin()->first->getParent()->getDataLayout().getPointerSizeInBits(); StackSafetyDataFlowAnalysis<GlobalValue> SSDFA(PointerSize, std::move(Copy)); for (auto &F : SSDFA.run()) { @@ -794,6 +803,7 @@ const StackSafetyInfo::InfoTy &StackSafetyInfo::getInfo() const { void StackSafetyInfo::print(raw_ostream &O) const { getInfo().Info.print(O, F->getName(), dyn_cast<Function>(F)); + O << "\n"; } const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const { @@ -806,17 +816,22 @@ const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const { } } Info.reset(new InfoTy{ - createGlobalStackSafetyInfo(std::move(Functions), Index), {}}); + createGlobalStackSafetyInfo(std::move(Functions), Index), {}, {}}); + for (auto &FnKV : Info->Info) { for (auto &KV : FnKV.second.Allocas) { ++NumAllocaTotal; const AllocaInst *AI = KV.first; - if (getStaticAllocaSizeRange(*AI).contains(KV.second.Range)) { + auto AIRange = getStaticAllocaSizeRange(*AI); + if (AIRange.contains(KV.second.Range)) { Info->SafeAllocas.insert(AI); ++NumAllocaStackSafe; } + for (const auto &A : KV.second.Accesses) + Info->AccessIsUnsafe[A.first] |= !AIRange.contains(A.second); } } + if (StackSafetyPrint) print(errs()); } @@ -886,6 +901,15 @@ bool StackSafetyGlobalInfo::isSafe(const AllocaInst &AI) const { return Info.SafeAllocas.count(&AI); } +bool StackSafetyGlobalInfo::stackAccessIsSafe(const Instruction &I) const { + const auto &Info = getInfo(); + auto It = Info.AccessIsUnsafe.find(&I); + if (It == Info.AccessIsUnsafe.end()) { + return true; + } + return !It->second; +} + void StackSafetyGlobalInfo::print(raw_ostream &O) const { auto &SSI = getInfo().Info; if (SSI.empty()) @@ -894,6 +918,16 @@ void StackSafetyGlobalInfo::print(raw_ostream &O) const { for (auto &F : M.functions()) { if (!F.isDeclaration()) { SSI.find(&F)->second.print(O, F.getName(), &F); + O << " safe accesses:" + << "\n"; + for (const auto &I : instructions(F)) { + const CallInst *Call = dyn_cast<CallInst>(&I); + if ((isa<StoreInst>(I) || isa<LoadInst>(I) || isa<MemIntrinsic>(I) || + (Call && Call->hasByValArgument())) && + stackAccessIsSafe(I)) { + O << " " << I << "\n"; + } + } O << "\n"; } } |