diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index 32db3326af..475e18eada 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -10,50 +10,137 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/Logger.h" #include "phasar/Utils/Printer.h" +#include "phasar/Utils/TypeTraits.h" -#include "llvm/IR/InstrTypes.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Demangle/Demangle.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Value.h" #include #include #include +#include #include -namespace llvm { -class CallBase; -class Instruction; -class Function; -class Value; -} // namespace llvm - namespace psr { class LLVMBasedICFG; class LLVMTypeHierarchy; -struct TypeStateDescription; -struct TypeState { - int State{}; - std::string (*Print)(int) = nullptr; +namespace detail { +class IDETypeStateAnalysisBase { +public: + virtual ~IDETypeStateAnalysisBase() = default; + +protected: + IDETypeStateAnalysisBase(LLVMAliasInfoRef PT) noexcept : PT(PT) {} + + using d_t = const llvm::Value *; + using n_t = const llvm::Instruction *; + using f_t = const llvm::Function *; + using container_type = std::set; + using FlowFunctionPtrType = FlowFunctionPtrType; + + // --- Flow Functions + + FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ); + FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun); + FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, + n_t ExitStmt, n_t RetSite); + FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees); + FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun); + + // --- Utilities + + [[nodiscard]] virtual bool + isAPIFunction(llvm::StringRef Name) const noexcept = 0; + [[nodiscard]] virtual bool + isFactoryFunction(llvm::StringRef Name) const noexcept = 0; + [[nodiscard]] virtual bool + isTypeNameOfInterest(llvm::StringRef Name) const noexcept = 0; + + /** + * @brief Returns all alloca's that are (indirect) aliases of V. + * + * Currently PhASAR's points-to information does not include alloca + * instructions, since alloca instructions, i.e. memory locations, are of + * type T* for a target type T. Thus they do not alias directly. Therefore, + * for each alias of V we collect related alloca instructions by checking + * load and store instructions for used alloca's. + */ + container_type getRelevantAllocas(d_t V); + + /** + * @brief Returns whole-module aliases of V. + * + * This function retrieves whole-module points-to information. We store + * already computed points-to information in a cache to prevent expensive + * recomputation since the whole module points-to graph can be huge. This + * might become unnecessary once PhASAR's AliasGraph starts using a cache + * itself. + */ + container_type getWMAliasSet(d_t V); + + /** + * @brief Provides whole module aliases and relevant alloca's of V. + */ + container_type getWMAliasesAndAllocas(d_t V); + + /** + * @brief Provides local aliases and relevant alloca's of V. + */ + container_type getLocalAliasesAndAllocas(d_t V, llvm::StringRef Fname); + + /** + * @brief Checks if the type machtes the type of interest. + */ + bool hasMatchingType(d_t V); + +private: + FlowFunctionPtrType generateFromZero(d_t FactToGenerate) { + return generateFlow(FactToGenerate, LLVMZeroValue::getInstance()); + } - TypeState() noexcept = default; - TypeState(int State, std::string (*Print)(int)) noexcept - : State(State), Print{Print} {} + bool hasMatchingTypeName(const llvm::Type *Ty); - operator int() const noexcept { return State; } + std::map AliasCache; + LLVMAliasInfoRef PT{}; + std::map> + RelevantAllocaCache; }; +} // namespace detail +template struct IDETypeStateAnalysisDomain : public LLVMAnalysisDomainDefault { - using l_t = TypeState; + using l_t = typename TypeStateDescriptionTy::State; }; +template class IDETypeStateAnalysis - : public IDETabulationProblem { + : public IDETabulationProblem< + IDETypeStateAnalysisDomain>, + private detail::IDETypeStateAnalysisBase { public: - using IDETabProblemType = IDETabulationProblem; + using IDETabProblemType = + IDETabulationProblem>; + using typename IDETabProblemType::container_type; using typename IDETabProblemType::d_t; using typename IDETabProblemType::f_t; using typename IDETabProblemType::i_t; @@ -62,61 +149,317 @@ class IDETypeStateAnalysis using typename IDETabProblemType::t_t; using typename IDETabProblemType::v_t; - using ConfigurationTy = TypeStateDescription; + using typename IDETabProblemType::FlowFunctionPtrType; + using ConfigurationTy = TypeStateDescriptionTy; +private: + static AllBottom + makeAllBottom(const TypeStateDescriptionTy *TSD) noexcept { + if constexpr (HasJoinLatticeTraits) { + return AllBottom{}; + } else { + return AllBottom{TSD->bottom()}; + } + } + template >> + static AllBottom makeAllBottom(EmptyType /*unused*/) noexcept { + return AllBottom{}; + } + static bool isBottom(l_t State, const TypeStateDescriptionTy *TSD) noexcept { + if constexpr (HasJoinLatticeTraits) { + return State == JoinLatticeTraits::bottom(); + } else { + return State == TSD->bottom(); + } + } + template >> + static bool isBottom(l_t State, EmptyType /*unused*/) noexcept { + return State == JoinLatticeTraits::bottom(); + } + + struct TSEdgeFunctionComposer : EdgeFunctionComposer { + TSEdgeFunctionComposer(EdgeFunction First, EdgeFunction Second, + const TypeStateDescriptionTy *TSD) noexcept + : EdgeFunctionComposer{std::move(First), std::move(Second)} { + if constexpr (!HasJoinLatticeTraits) { + BotElement = TSD->bottom(); + } + } + + [[no_unique_address]] std::conditional_t, + EmptyType, l_t> + BotElement{}; + + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + if constexpr (HasJoinLatticeTraits) { + return AllBottom{}; + } else { + return AllBottom{This->BotElement}; + } + } + }; + + struct TSEdgeFunction { + using l_t = l_t; + const TypeStateDescriptionTy *TSD{}; + // XXX: Do we really need a string here? Can't we just use an integer or sth + // else that is cheap? + std::string Token; + const llvm::CallBase *CallSite{}; + + [[nodiscard]] l_t computeTarget(l_t Source) const { + + // assert((Source != TSD->top()) && "Error: call computeTarget with + // TOP\n"); + + auto CurrentState = TSD->getNextState( + Token, Source == TSD->top() ? TSD->uninit() : Source, CallSite); + PHASAR_LOG_LEVEL(DEBUG, "State machine transition: (" + << Token << " , " << LToString(Source) + << ") -> " << LToString(CurrentState)); + return CurrentState; + } + + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + + return TSEdgeFunctionComposer{This, SecondFunction, This->TSD}; + } + + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + + return makeAllBottom(This->TSD); + } + + bool operator==(const TSEdgeFunction &Other) const { + return CallSite == Other.CallSite && Token == Other.Token; + } + + friend llvm::raw_ostream &print(llvm::raw_ostream &OS, + const TSEdgeFunction &TSE) { + return OS << "TSEF(" << TSE.Token << " at " + << llvmIRToShortString(TSE.CallSite) << ")"; + } + }; + + struct TSConstant : ConstantEdgeFunction { + std::conditional_t, EmptyType, + const TypeStateDescriptionTy *> + TSD{}; + + TSConstant(l_t Value, const TypeStateDescriptionTy *TSD) noexcept + : ConstantEdgeFunction{Value} { + if constexpr (!HasJoinLatticeTraits) { + this->TSD = TSD; + } + } + + template >> + TSConstant(l_t Value, EmptyType /*unused*/ = {}) noexcept + : ConstantEdgeFunction{Value} { + if constexpr (!HasJoinLatticeTraits) { + this->TSD = TSD; + } + } + + /// XXX: Cannot default compose() and join(), because l_t does not implement + /// JoinLatticeTraits (because bottom value is not constant) + template + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + + l_t Ret = SecondFunction.computeTarget(This->Value); + if (Ret == This->Value) { + return This; + } + if (isBottom(Ret, This->TSD)) { + return makeAllBottom(This->TSD); + } + + return TSConstant{Ret, This->TSD}; + } + + template + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + + auto Top = [TSD = This->TSD] { + if constexpr (HasJoinLatticeTraits) { + return JoinLatticeTraits::top(); + } else { + return TSD->top(); + } + }(); + if (const auto *C = llvm::dyn_cast(OtherFunction)) { + if (C->Value == This->Value || C->Value == Top) { + return This; + } + if (This->Value == Top) { + return OtherFunction; + } + } + return makeAllBottom(This->TSD); + } + + bool operator==(const TSConstant &Other) const noexcept { + return this->Value == Other.Value; + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const TSConstant &EF) { + return OS << "TSConstant[" << LToString(EF.Value) << "]"; + } + }; + +public: IDETypeStateAnalysis(const LLVMProjectIRDB *IRDB, LLVMAliasInfoRef PT, - const TypeStateDescription *TSD, - std::vector EntryPoints = {"main"}); + const TypeStateDescriptionTy *TSD, + std::vector EntryPoints = {"main"}) + : IDETabProblemType(IRDB, std::move(EntryPoints), createZeroValue()), + IDETypeStateAnalysisBase(PT), TSD(TSD) { + assert(TSD != nullptr); + assert(PT); + } ~IDETypeStateAnalysis() override = default; // start formulating our analysis by specifying the parts required for IFDS - FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override; + FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override { + return detail::IDETypeStateAnalysisBase::getNormalFlowFunction(Curr, Succ); + } - FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override; + FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override { + return detail::IDETypeStateAnalysisBase::getCallFlowFunction(CallSite, + DestFun); + } FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, - n_t ExitStmt, n_t RetSite) override; + n_t ExitStmt, n_t RetSite) override { + + return detail::IDETypeStateAnalysisBase::getRetFlowFunction( + CallSite, CalleeFun, ExitStmt, RetSite); + } FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - llvm::ArrayRef Callees) override; + llvm::ArrayRef Callees) override { + return detail::IDETypeStateAnalysisBase::getCallToRetFlowFunction( + CallSite, RetSite, Callees); + } FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, - f_t DestFun) override; + f_t DestFun) override { + return detail::IDETypeStateAnalysisBase::getSummaryFlowFunction(CallSite, + DestFun); + } - InitialSeeds initialSeeds() override; + InitialSeeds initialSeeds() override { + return this->createDefaultSeeds(); + } - [[nodiscard]] d_t createZeroValue() const; + [[nodiscard]] d_t createZeroValue() const { + return LLVMZeroValue::getInstance(); + } - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const override { + return LLVMZeroValue::isLLVMZeroValue(Fact); + } // in addition provide specifications for the IDE parts - EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode) override; - - EdgeFunction getCallEdgeFunction(n_t CallSite, d_t SrcNode, - f_t DestinationFunction, - d_t DestNode) override; - - EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, - n_t ExitInst, d_t ExitNode, - n_t RetSite, d_t RetNode) override; + EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t /*Succ*/, + d_t SuccNode) override { + // Set alloca instructions of target type to uninitialized. + if (const auto *Alloca = llvm::dyn_cast(Curr)) { + if (hasMatchingType(Alloca)) { + if (LLVMZeroValue::isLLVMZeroValue(CurrNode) && SuccNode == Alloca) { + return TSConstant(TSD->uninit(), TSD); + } + } + } + return EdgeIdentity{}; + } + + EdgeFunction getCallEdgeFunction(n_t /*CallSite*/, d_t /*SrcNode*/, + f_t /*DestinationFunction*/, + d_t /*DestNode*/) override { + return EdgeIdentity{}; + } + + EdgeFunction getReturnEdgeFunction(n_t /*CallSite*/, + f_t /*CalleeFunction*/, + n_t /*ExitInst*/, d_t /*ExitNode*/, + n_t /*RetSite*/, + d_t /*RetNode*/) override { + return EdgeIdentity{}; + } EdgeFunction - getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, + getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t /*RetSite*/, d_t RetSiteNode, - llvm::ArrayRef Callees) override; - - EdgeFunction getSummaryEdgeFunction(n_t CallSite, d_t CallNode, - n_t RetSite, - d_t RetSiteNode) override; - - l_t topElement() override; - - l_t bottomElement() override; + llvm::ArrayRef Callees) override { + const auto *CS = llvm::cast(CallSite); + for (const auto *Callee : Callees) { + std::string DemangledFname = llvm::demangle(Callee->getName().str()); + + // For now we assume that we can only generate from the return value. + // We apply the same edge function for the return value, i.e. callsite. + if (TSD->isFactoryFunction(DemangledFname)) { + PHASAR_LOG_LEVEL(DEBUG, "Processing factory function"); + if (isZeroValue(CallNode) && RetSiteNode == CS) { + return TSConstant{ + TSD->getNextState(DemangledFname, TSD->uninit(), CS), TSD}; + } + } + + // For every consuming parameter and all its aliases and relevant alloca's + // we apply the same edge function. + if (TSD->isConsumingFunction(DemangledFname)) { + PHASAR_LOG_LEVEL(DEBUG, "Processing consuming function"); + for (auto Idx : TSD->getConsumerParamIdx(DemangledFname)) { + const auto &AliasAndAllocas = + getWMAliasesAndAllocas(CS->getArgOperand(Idx)); + + if (CallNode == RetSiteNode && AliasAndAllocas.count(CallNode)) { + return TSEdgeFunction{TSD, DemangledFname, CS}; + } + } + } + } + return EdgeIdentity{}; + } + + EdgeFunction getSummaryEdgeFunction(n_t /*CallSite*/, d_t /*CallNode*/, + n_t /*RetSite*/, + d_t /*RetSiteNode*/) override { + return nullptr; + } + + l_t topElement() override { return TSD->top(); } + + l_t bottomElement() override { return TSD->bottom(); } /** * We have a lattice with BOTTOM representing all information @@ -126,60 +469,124 @@ class IDETypeStateAnalysis * * @note Only one-level lattice's are handled currently */ - l_t join(l_t Lhs, l_t Rhs) override; - - EdgeFunction allTopFunction() override; + l_t join(l_t Lhs, l_t Rhs) override { + if (Lhs == Rhs) { + return Lhs; + } + if (Lhs == TSD->top()) { + return Rhs; + } + if (Rhs == TSD->top()) { + return Lhs; + } + return TSD->bottom(); + } + + EdgeFunction allTopFunction() override { + if constexpr (HasJoinLatticeTraits) { + return AllTop{}; + } else { + return AllTop{topElement()}; + } + } + + [[nodiscard]] bool + isAPIFunction(llvm::StringRef Name) const noexcept override { + return TSD->isAPIFunction(Name); + } + + [[nodiscard]] bool + isFactoryFunction(llvm::StringRef Name) const noexcept override { + return TSD->isFactoryFunction(Name); + } + + [[nodiscard]] bool + isTypeNameOfInterest(llvm::StringRef Name) const noexcept override { + return Name.contains(TSD->getTypeNameOfInterest()); + } void emitTextReport(const SolverResults &SR, - llvm::raw_ostream &OS = llvm::outs()) override; + llvm::raw_ostream &OS = llvm::outs()) override { + LLVMBasedCFG CFG; + OS << "\n======= TYPE STATE RESULTS =======\n"; + for (const auto &F : this->IRDB->getAllFunctions()) { + OS << '\n' << F->getName() << '\n'; + for (const auto &BB : *F) { + for (const auto &I : BB) { + auto Results = SR.resultsAt(&I, true); + if (CFG.isExitInst(&I)) { + OS << "\nAt exit stmt: " << NToString(&I) << '\n'; + for (auto Res : Results) { + if (const auto *Alloca = + llvm::dyn_cast(Res.first)) { + if (Res.second == TSD->error()) { + OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " + << DToString(Res.first) << '\n'; + for (const auto *Pred : CFG.getPredsOf(&I)) { + OS << "\nPredecessor: " << NToString(Pred) << '\n'; + auto PredResults = SR.resultsAt(Pred, true); + for (auto Res : PredResults) { + if (Res.first == Alloca) { + OS << "Pred State: " << LToString(Res.second) << '\n'; + } + } + } + OS << "============================\n"; + } else { + OS << "\nAlloca : " << DToString(Res.first) + << "\nState : " << LToString(Res.second) << '\n'; + } + } else { + OS << "\nInst: " << NToString(&I) << '\n' + << "Fact: " << DToString(Res.first) << '\n' + << "State: " << LToString(Res.second) << '\n'; + } + } + } else { + for (auto Res : Results) { + if (const auto *Alloca = + llvm::dyn_cast(Res.first)) { + if (Res.second == TSD->error()) { + OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " + << DToString(Res.first) << '\n' + << "\nAt IR Inst: " << NToString(&I) << '\n'; + for (const auto *Pred : CFG.getPredsOf(&I)) { + OS << "\nPredecessor: " << NToString(Pred) << '\n'; + auto PredResults = SR.resultsAt(Pred, true); + for (auto Res : PredResults) { + if (Res.first == Alloca) { + OS << "Pred State: " << LToString(Res.second) << '\n'; + } + } + } + OS << "============================\n"; + } + } else { + OS << "\nInst: " << NToString(&I) << '\n' + << "Fact: " << DToString(Res.first) << '\n' + << "State: " << LToString(Res.second) << '\n'; + } + } + } + } + } + OS << "\n--------------------------------------------\n"; + } + } private: - const TypeStateDescription *TSD{}; - std::string (*Print)(int) = nullptr; - std::map AliasCache; - LLVMAliasInfoRef PT{}; - std::map> - RelevantAllocaCache; - - /** - * @brief Returns all alloca's that are (indirect) aliases of V. - * - * Currently PhASAR's points-to information does not include alloca - * instructions, since alloca instructions, i.e. memory locations, are of - * type T* for a target type T. Thus they do not alias directly. Therefore, - * for each alias of V we collect related alloca instructions by checking - * load and store instructions for used alloca's. - */ - std::set getRelevantAllocas(d_t V); - - /** - * @brief Returns whole-module aliases of V. - * - * This function retrieves whole-module points-to information. We store - * already computed points-to information in a cache to prevent expensive - * recomputation since the whole module points-to graph can be huge. This - * might become unnecessary once PhASAR's AliasGraph starts using a cache - * itself. - */ - std::set getWMAliasSet(d_t V); - - /** - * @brief Provides whole module aliases and relevant alloca's of V. - */ - std::set getWMAliasesAndAllocas(d_t V); + const TypeStateDescriptionTy *TSD{}; +}; - /** - * @brief Provides local aliases and relevant alloca's of V. - */ - std::set getLocalAliasesAndAllocas(d_t V, const std::string &Fname); +template +IDETypeStateAnalysis(const LLVMProjectIRDB *, LLVMAliasInfoRef, + const TypeStateDescriptionTy *, + std::vector EntryPoints) + -> IDETypeStateAnalysis; - /** - * @brief Checks if the type machtes the type of interest. - */ - bool hasMatchingType(d_t V); -}; +// class CSTDFILEIOTypeStateDescription; -std::string LToString(TypeState S); +// extern template class IDETypeStateAnalysis; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h index 73095a3b07..1f28206d17 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h @@ -10,6 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" #include @@ -18,24 +19,54 @@ namespace psr { +enum class CSTDFILEIOState { + TOP = 42, + UNINIT = 0, + OPENED = 1, + CLOSED = 2, + ERROR = 3, + BOT = 4 +}; +llvm::StringRef to_string(CSTDFILEIOState State) noexcept; +template <> struct JoinLatticeTraits { + static constexpr CSTDFILEIOState top() noexcept { + return CSTDFILEIOState::TOP; + } + static constexpr CSTDFILEIOState bottom() noexcept { + return CSTDFILEIOState::BOT; + } + static constexpr CSTDFILEIOState join(CSTDFILEIOState L, + CSTDFILEIOState R) noexcept { + if (L == top() || R == bottom()) { + return R; + } + if (L == bottom() || R == top()) { + return L; + } + return bottom(); + } +}; + /** * A type state description for C's file I/O API. The finite state machine * is encoded by a two-dimensional array with rows as function tokens and * columns as states. */ -class CSTDFILEIOTypeStateDescription : public TypeStateDescription { +class CSTDFILEIOTypeStateDescription + : public TypeStateDescription { public: - [[nodiscard]] bool isFactoryFunction(const std::string &F) const override; - [[nodiscard]] bool isConsumingFunction(const std::string &F) const override; - [[nodiscard]] bool isAPIFunction(const std::string &F) const override; + using TypeStateDescription::getNextState; + [[nodiscard]] bool isFactoryFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isConsumingFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; + getNextState(llvm::StringRef Tok, + TypeStateDescription::State S) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - [[nodiscard]] auto getStateToString() const -> std::string (*)(int) override; + getFactoryParamIdx(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State bottom() const override; [[nodiscard]] TypeStateDescription::State top() const override; [[nodiscard]] TypeStateDescription::State uninit() const override; @@ -43,6 +74,8 @@ class CSTDFILEIOTypeStateDescription : public TypeStateDescription { [[nodiscard]] TypeStateDescription::State error() const override; }; +extern template class IDETypeStateAnalysis; + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h index 3fb21c8b7e..081b94a46a 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h @@ -13,7 +13,7 @@ #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" #include "phasar/Domain/AnalysisDomain.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h" -#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h" #include #include @@ -26,32 +26,35 @@ class Value; namespace psr { +/** + * We use the following lattice + * BOT = all information + * + * UNINIT CTX_ATTACHED PARAM_INIT DERIVED ERROR + * + * TOP = no information + */ +enum class OpenSSLEVPKDFCTXState { + TOP = 42, + UNINIT = 5, + CTX_ATTACHED = 1, + PARAM_INIT = 2, + DERIVED = 3, + ERROR = 4, + BOT = 0 // It is VERY IMPORTANT, athat BOT has value 0, since this is the + // default value +}; + +llvm::StringRef to_string(OpenSSLEVPKDFCTXState State) noexcept; + /** * A type state description for OpenSSL's EVP Key Derivation functions. The * finite state machine is encoded by a two-dimensional array with rows as * function tokens and columns as states. */ -class OpenSSLEVPKDFCTXDescription : public TypeStateDescription { +class OpenSSLEVPKDFCTXDescription + : public TypeStateDescription { private: - /** - * We use the following lattice - * BOT = all information - * - * UNINIT CTX_ATTACHED PARAM_INIT DERIVED ERROR - * - * TOP = no information - */ - enum OpenSSLEVPKDFState { - TOP = 42, - UNINIT = 5, - CTX_ATTACHED = 1, - PARAM_INIT = 2, - DERIVED = 3, - ERROR = 4, - BOT = 0 // It is VERY IMPORTANT, athat BOT has value 0, since this is the - // default value - }; - /** * The STAR token represents all functions besides EVP_KDF_fetch(), * EVP_KDF_CTX_new(), EVP_KDF_CTX_set_params() ,derive() and @@ -65,41 +68,40 @@ class OpenSSLEVPKDFCTXDescription : public TypeStateDescription { STAR = 4 }; - static const std::map> OpenSSLEVPKDFFuncs; // Delta matrix to implement the state machine's Delta function - static const OpenSSLEVPKDFState Delta[5][6]; + static const OpenSSLEVPKDFCTXState Delta[5][6]; // std::map, int> // requiredKDFState; - IDESolver &KDFAnalysisResults; - static OpenSSLEVTKDFToken funcNameToToken(const std::string &F); + IDESolver> + &KDFAnalysisResults; + static OpenSSLEVTKDFToken funcNameToToken(llvm::StringRef F); public: + using TypeStateDescription::getNextState; OpenSSLEVPKDFCTXDescription( - IDESolver &KDFAnalysisResults) + IDESolver> + &KDFAnalysisResults) : KDFAnalysisResults(KDFAnalysisResults) {} + [[nodiscard]] bool isFactoryFunction(llvm::StringRef FuncName) const override; [[nodiscard]] bool - isFactoryFunction(const std::string &FuncName) const override; - [[nodiscard]] bool - isConsumingFunction(const std::string &FuncName) const override; - [[nodiscard]] bool isAPIFunction(const std::string &FuncName) const override; - [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; - [[nodiscard]] TypeStateDescription::State - getNextState(const std::string &Tok, TypeStateDescription::State S, + isConsumingFunction(llvm::StringRef FuncName) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef FuncName) const override; + [[nodiscard]] State getNextState(llvm::StringRef Tok, State S) const override; + [[nodiscard]] State + getNextState(llvm::StringRef Tok, State S, const llvm::CallBase *CallSite) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - [[nodiscard]] auto getStateToString() const -> std::string (*)(int) override; - [[nodiscard]] TypeStateDescription::State bottom() const override; - [[nodiscard]] TypeStateDescription::State top() const override; - [[nodiscard]] TypeStateDescription::State uninit() const override; - [[nodiscard]] TypeStateDescription::State start() const override; - [[nodiscard]] TypeStateDescription::State error() const override; + getFactoryParamIdx(llvm::StringRef F) const override; + [[nodiscard]] State bottom() const override; + [[nodiscard]] State top() const override; + [[nodiscard]] State uninit() const override; + [[nodiscard]] State start() const override; + [[nodiscard]] State error() const override; /* /// Checks all callSites, where a EVP_KDF object needs to be in a /// certain state, such that the state transition for EVP_KDF_CTX is valid. diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h index e4a6d39b67..34023c863a 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h @@ -17,24 +17,28 @@ #include namespace psr { -class OpenSSLEVPKDFDescription : public TypeStateDescription { -public: - /** - * We use the following lattice - * BOT = all information - * - * UNINIT KDF_FETCHED ERROR - * - * TOP = no information - */ - enum OpenSSLEVPKDFState { - TOP = 42, - UNINIT = 0, - KDF_FETCHED = 1, - ERROR = 2, - BOT = 3 - }; +/** + * We use the following lattice + * BOT = all information + * + * UNINIT KDF_FETCHED ERROR + * + * TOP = no information + */ +enum class OpenSSLEVPKDFState { + TOP = 42, + UNINIT = 0, + KDF_FETCHED = 1, + ERROR = 2, + BOT = 3 +}; + +llvm::StringRef to_string(OpenSSLEVPKDFState State) noexcept; + +class OpenSSLEVPKDFDescription + : public TypeStateDescription { +public: /** * The STAR token represents all functions besides EVP_KDF_fetch(), * EVP_KDF_fetch() and EVP_KDF_CTX_free(). @@ -45,31 +49,32 @@ class OpenSSLEVPKDFDescription : public TypeStateDescription { STAR = 2 }; + using State = OpenSSLEVPKDFState; + private: - static const std::map> OpenSSLEVPKDFFuncs; // delta matrix to implement the state machine's delta function static const OpenSSLEVPKDFState Delta[3][4]; - static OpenSSLEVTKDFToken funcNameToToken(const std::string &F); + static OpenSSLEVTKDFToken funcNameToToken(llvm::StringRef F); public: - [[nodiscard]] bool isFactoryFunction(const std::string &F) const override; + using TypeStateDescription::getNextState; + [[nodiscard]] bool isFactoryFunction(llvm::StringRef F) const override; - [[nodiscard]] bool isConsumingFunction(const std::string &F) const override; + [[nodiscard]] bool isConsumingFunction(llvm::StringRef F) const override; - [[nodiscard]] bool isAPIFunction(const std::string &F) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; + getNextState(llvm::StringRef Tok, + TypeStateDescription::State S) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - - [[nodiscard]] auto getStateToString() const -> std::string (*)(int) override; + getFactoryParamIdx(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State bottom() const override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h index 83691c3c5a..cb69f4fe7e 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h @@ -18,19 +18,20 @@ #include namespace psr { +enum class OpenSSLSecureHeapState { + TOP = 42, + BOT = 0, + UNINIT = 1, + ALLOCATED = 2, + ZEROED = 3, + FREED = 4, + ERROR = 5 +}; +llvm::StringRef to_string(OpenSSLSecureHeapState State) noexcept; -class OpenSSLSecureHeapDescription : public TypeStateDescription { +class OpenSSLSecureHeapDescription + : public TypeStateDescription { private: - enum OpenSSLSecureHeapState { - TOP = 42, - BOT = 0, - UNINIT = 1, - ALLOCATED = 2, - ZEROED = 3, - FREED = 4, - ERROR = 5 - }; - enum class OpenSSLSecureHeapToken { SECURE_MALLOC = 0, SECURE_ZALLOC = 1, @@ -39,33 +40,33 @@ class OpenSSLSecureHeapDescription : public TypeStateDescription { STAR = 4 }; - static const std::map> OpenSSLSecureHeapFuncs; // Delta matrix to implement the state machine's Delta function static const OpenSSLSecureHeapState Delta[5][6]; IDESolver &SecureHeapPropagationResults; - static OpenSSLSecureHeapToken funcNameToToken(const std::string &F); + static OpenSSLSecureHeapToken funcNameToToken(llvm::StringRef F); public: + using TypeStateDescription::getNextState; OpenSSLSecureHeapDescription(IDESolver &SecureHeapPropagationResults); - [[nodiscard]] bool isFactoryFunction(const std::string &F) const override; - [[nodiscard]] bool isConsumingFunction(const std::string &F) const override; - [[nodiscard]] bool isAPIFunction(const std::string &F) const override; + [[nodiscard]] bool isFactoryFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isConsumingFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; + getNextState(llvm::StringRef Tok, + TypeStateDescription::State S) const override; [[nodiscard]] TypeStateDescription::State - getNextState(const std::string &Tok, TypeStateDescription::State S, + getNextState(llvm::StringRef Tok, TypeStateDescription::State S, const llvm::CallBase *CallSite) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - [[nodiscard]] auto getStateToString() const -> std::string (*)(int) override; + getFactoryParamIdx(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State bottom() const override; [[nodiscard]] TypeStateDescription::State top() const override; [[nodiscard]] TypeStateDescription::State uninit() const override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h index 3eeffdea7d..a1c41d1c27 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h @@ -18,19 +18,24 @@ namespace psr { -class OpenSSLSecureMemoryDescription : public TypeStateDescription { +enum class OpenSSLSecureMemoryState; +llvm::StringRef to_string(OpenSSLSecureMemoryState State) noexcept; + +class OpenSSLSecureMemoryDescription + : public TypeStateDescription { public: - [[nodiscard]] bool isFactoryFunction(const std::string &F) const override; - [[nodiscard]] bool isConsumingFunction(const std::string &F) const override; - [[nodiscard]] bool isAPIFunction(const std::string &F) const override; + using TypeStateDescription::getNextState; + [[nodiscard]] bool isFactoryFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isConsumingFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; + getNextState(llvm::StringRef Tok, + TypeStateDescription::State S) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - [[nodiscard]] auto getStateToString() const -> std::string (*)(int) override; + getFactoryParamIdx(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State bottom() const override; [[nodiscard]] TypeStateDescription::State top() const override; [[nodiscard]] TypeStateDescription::State uninit() const override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h index 37ea136d77..883b1d89d6 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h @@ -17,6 +17,19 @@ namespace psr { +struct TypeStateDescriptionBase { + virtual ~TypeStateDescriptionBase() = default; + + [[nodiscard]] virtual bool isFactoryFunction(llvm::StringRef F) const = 0; + [[nodiscard]] virtual bool isConsumingFunction(llvm::StringRef F) const = 0; + [[nodiscard]] virtual bool isAPIFunction(llvm::StringRef F) const = 0; + [[nodiscard]] virtual std::string getTypeNameOfInterest() const = 0; + [[nodiscard]] virtual std::set + getConsumerParamIdx(llvm::StringRef F) const = 0; + [[nodiscard]] virtual std::set + getFactoryParamIdx(llvm::StringRef F) const = 0; +}; + /** * Interface for a type state problem to be used with the IDETypeStateAnalysis. * It needs to provide a finite state machine to handle state changes and a list @@ -31,32 +44,24 @@ namespace psr { * * @see CSTDFILEIOTypeStateDescription as an example of type state description. */ -struct TypeStateDescription { +template +struct TypeStateDescription : public TypeStateDescriptionBase { /// Type for states of the finite state machine - using State = int; - virtual ~TypeStateDescription() = default; - [[nodiscard]] virtual bool isFactoryFunction(const std::string &F) const = 0; - [[nodiscard]] virtual bool - isConsumingFunction(const std::string &F) const = 0; - [[nodiscard]] virtual bool isAPIFunction(const std::string &F) const = 0; + using State = StateTy; + ~TypeStateDescription() override = default; /** * @brief For a given function name (as a string token) and a state, this * function returns the next state. */ - [[nodiscard]] virtual State getNextState(std::string Tok, State S) const = 0; + [[nodiscard]] virtual State getNextState(llvm::StringRef Tok, + State S) const = 0; [[nodiscard]] virtual State - getNextState(const std::string &Tok, State S, + getNextState(llvm::StringRef Tok, State S, const llvm::CallBase * /*CallSite*/) const { return getNextState(Tok, S); } - [[nodiscard]] virtual std::string getTypeNameOfInterest() const = 0; - [[nodiscard]] virtual std::set - getConsumerParamIdx(const std::string &F) const = 0; - [[nodiscard]] virtual std::set - getFactoryParamIdx(const std::string &F) const = 0; - [[nodiscard]] virtual auto getStateToString() const - -> std::string (*)(int) = 0; + [[nodiscard]] virtual State bottom() const = 0; [[nodiscard]] virtual State top() const = 0; diff --git a/lib/Controller/AnalysisControllerXIDECSTDIOTS.cpp b/lib/Controller/AnalysisControllerXIDECSTDIOTS.cpp index 68cb0c0f42..59bd165343 100644 --- a/lib/Controller/AnalysisControllerXIDECSTDIOTS.cpp +++ b/lib/Controller/AnalysisControllerXIDECSTDIOTS.cpp @@ -15,7 +15,8 @@ namespace psr { void AnalysisController::executeIDECSTDIOTS() { CSTDFILEIOTypeStateDescription TSDesc; - executeIDEAnalysis(&TSDesc, EntryPoints); + executeIDEAnalysis>( + &TSDesc, EntryPoints); } } // namespace psr diff --git a/lib/Controller/AnalysisControllerXIDEOpenSSLTS.cpp b/lib/Controller/AnalysisControllerXIDEOpenSSLTS.cpp index b686680f0b..6c6dba3b45 100644 --- a/lib/Controller/AnalysisControllerXIDEOpenSSLTS.cpp +++ b/lib/Controller/AnalysisControllerXIDEOpenSSLTS.cpp @@ -15,7 +15,8 @@ namespace psr { void AnalysisController::executeIDEOpenSSLTS() { OpenSSLEVPKDFDescription TSDesc; - executeIDEAnalysis(&TSDesc, EntryPoints); + executeIDEAnalysis>( + &TSDesc, EntryPoints); } } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp index f33f9194fd..b646ea57f3 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp @@ -34,244 +34,73 @@ #include #include -namespace psr { +namespace psr::detail { -/// -/// -/// TODO: Make Bottom common across all implementations of TypeStateDescription! -/// then we can factor it out of all edge functions making some of them -/// applicable for small-object optimization! -/// -/// - -// customize the edge function composer -struct TSEdgeFunctionComposer - : EdgeFunctionComposer { - IDETypeStateAnalysisDomain::l_t BotElement; - - static EdgeFunction - join(EdgeFunctionRef This, - const EdgeFunction &OtherFunction) { - if (auto Default = defaultJoinOrNull(This, OtherFunction)) { - return Default; - } - - return AllBottom{This->BotElement}; - } -}; - -struct TSEdgeFunction { - const TypeStateDescription *TSD; - // XXX: Do we really need a string here? Can't we just use an integer or sth - // else that is cheap? - std::string Token; - const llvm::CallBase *CallSite; - - using l_t = IDETypeStateAnalysisDomain ::l_t; - - [[nodiscard]] l_t computeTarget(l_t Source) const { - - // assert((Source != TSD->top()) && "Error: call computeTarget with TOP\n"); - - auto CurrentState = TSD->getNextState( - Token, Source == TSD->top() ? TSD->uninit() : Source, CallSite); - PHASAR_LOG_LEVEL(DEBUG, "State machine transition: (" - << Token << " , " << LToString(Source) - << ") -> " << LToString(CurrentState)); - return {CurrentState, Source.Print}; - } - - static EdgeFunction compose(EdgeFunctionRef This, - const EdgeFunction &SecondFunction) { - if (auto Default = defaultComposeOrNull(This, SecondFunction)) { - return Default; - } - - return TSEdgeFunctionComposer{ - {This, SecondFunction}, - {This->TSD->bottom(), This->TSD->getStateToString()}}; - } - - static EdgeFunction join(EdgeFunctionRef This, - const EdgeFunction &OtherFunction) { - if (auto Default = defaultJoinOrNull(This, OtherFunction)) { - return Default; - } - - return AllBottom{ - {This->TSD->bottom(), This->TSD->getStateToString()}}; - } - - bool operator==(const TSEdgeFunction &Other) const { - return CallSite == Other.CallSite && Token == Other.Token; - } - - friend llvm::raw_ostream &print(llvm::raw_ostream &OS, - const TSEdgeFunction &TSE) { - return OS << "TSEF(" << TSE.Token << " at " - << llvmIRToShortString(TSE.CallSite) << ")"; - } -}; - -struct TSConstant : ConstantEdgeFunction { - const TypeStateDescription *TSD{}; - - /// XXX: Cannot default compose() and join(), because l_t does not implement - /// JoinLatticeTraits (because bottom value is not constant) - template - static EdgeFunction compose(EdgeFunctionRef This, - const EdgeFunction &SecondFunction) { - - if (auto Default = defaultComposeOrNull(This, SecondFunction)) { - return Default; - } - - l_t Ret = SecondFunction.computeTarget(This->Value); - if (Ret == This->Value) { - return This; - } - if (Ret == This->TSD->bottom()) { - return AllBottom{Ret}; - } - - return TSConstant{{Ret}, This->TSD}; - } - - template - static EdgeFunction join(EdgeFunctionRef This, - const EdgeFunction &OtherFunction) { - if (auto Default = defaultJoinOrNull(This, OtherFunction)) { - return Default; - } - - const auto *TSD = This->TSD; - if (const auto *C = llvm::dyn_cast(OtherFunction)) { - if (C->Value == This->Value || C->Value == TSD->top()) { - return This; - } - if (This->Value == TSD->top()) { - return OtherFunction; - } - } - return AllBottom{ - {TSD->bottom(), TSD->getStateToString()}}; - } -}; - -bool operator==(ByConstRef LHS, - ByConstRef RHS) noexcept { - return LHS.Value == RHS.Value; -} - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - ByConstRef EF) { - return OS << "TSConstant[" << LToString(EF.Value) << "]"; -} - -IDETypeStateAnalysis::IDETypeStateAnalysis(const LLVMProjectIRDB *IRDB, - LLVMAliasInfoRef PT, - const TypeStateDescription *TSD, - std::vector EntryPoints) - : IDETabulationProblem(IRDB, std::move(EntryPoints), createZeroValue()), - TSD(TSD), PT(PT) { - assert(TSD != nullptr); - assert(PT); - - Print = TSD->getStateToString(); -} - -// Start formulating our analysis by specifying the parts required for IFDS - -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getNormalFlowFunction( - IDETypeStateAnalysis::n_t Curr, IDETypeStateAnalysis::n_t /*Succ*/) { +auto IDETypeStateAnalysisBase::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) + -> FlowFunctionPtrType { // Check if Alloca's type matches the target type. If so, generate from zero // value. if (const auto *Alloca = llvm::dyn_cast(Curr)) { if (hasMatchingType(Alloca)) { - return generateFromZero(Alloca); + return this->generateFromZero(Alloca); } } - // Check load instructions for target type. Generate from the loaded value and - // kill the load instruction if it was generated previously (strong update!). + // Check load instructions for target type. Generate from the loaded value + // and kill the load instruction if it was generated previously (strong + // update!). if (const auto *Load = llvm::dyn_cast(Curr)) { if (hasMatchingType(Load)) { - struct TSFlowFunction : FlowFunction { - const llvm::LoadInst *Load; - - TSFlowFunction(const llvm::LoadInst *L) : Load(L) {} - ~TSFlowFunction() override = default; - std::set - computeTargets(IDETypeStateAnalysis::d_t Source) override { - if (Source == Load) { - return {}; - } - if (Source == Load->getPointerOperand()) { - return {Source, Load}; - } - return {Source}; - } - }; - return std::make_shared(Load); + return transferFlow(Load, Load->getPointerOperand()); } } if (const auto *Gep = llvm::dyn_cast(Curr)) { if (hasMatchingType(Gep->getPointerOperand())) { - return lambdaFlow([=](d_t Source) -> std::set { - // if (Source == Gep->getPointerOperand()) { - // return {Source, Gep}; - //} - return {Source}; - }); + return identityFlow(); + // return lambdaFlow([=](d_t Source) -> std::set { + // // if (Source == Gep->getPointerOperand()) { + // // return {Source, Gep}; + // //} + // return {Source}; + // }); } } // Check store instructions for target type. Perform a strong update, i.e. - // kill the alloca pointed to by the pointer-operand and all alloca's related - // to the value-operand and then generate them from the value-operand. + // kill the alloca pointed to by the pointer-operand and all alloca's + // related to the value-operand and then generate them from the + // value-operand. if (const auto *Store = llvm::dyn_cast(Curr)) { if (hasMatchingType(Store)) { auto RelevantAliasesAndAllocas = getLocalAliasesAndAllocas( Store->getPointerOperand(), // pointer- or value operand??? // Store->getValueOperand(), - Curr->getParent()->getParent()->getName().str()); - - struct TSFlowFunction : FlowFunction { - const llvm::StoreInst *Store; - std::set AliasesAndAllocas; - TSFlowFunction(const llvm::StoreInst *S, - std::set AA) - : Store(S), AliasesAndAllocas(std::move(AA)) {} - ~TSFlowFunction() override = default; - std::set - computeTargets(IDETypeStateAnalysis::d_t Source) override { - // We kill all relevant loacal aliases and alloca's - if (Source != Store->getValueOperand() && - // AliasesAndAllocas.find(Source) != AliasesAndAllocas.end() - // Is simple comparison sufficient? - Source == Store->getPointerOperand()) { - return {}; - } - // Generate all local aliases and relevant alloca's from the stored - // value - if (Source == Store->getValueOperand()) { - AliasesAndAllocas.insert(Source); - return AliasesAndAllocas; - } - return {Source}; - } - }; - return std::make_shared(Store, RelevantAliasesAndAllocas); + Curr->getFunction()->getName().str()); + + RelevantAliasesAndAllocas.insert(Store->getValueOperand()); + return lambdaFlow( + [Store, AliasesAndAllocas = std::move(RelevantAliasesAndAllocas)]( + d_t Source) -> container_type { + // We kill all relevant loacal aliases and alloca's + if (Source == Store->getPointerOperand()) { + // XXX: later kill must-aliases too + return {}; + } + // Generate all local aliases and relevant alloca's from the + // stored value + if (Source == Store->getValueOperand()) { + return AliasesAndAllocas; + } + return {Source}; + }); } } - return Identity::getInstance(); + return identityFlow(); } -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getCallFlowFunction(IDETypeStateAnalysis::n_t CallSite, - IDETypeStateAnalysis::f_t DestFun) { +auto IDETypeStateAnalysisBase::getCallFlowFunction(n_t CallSite, f_t DestFun) + -> FlowFunctionPtrType { // Kill all data-flow facts if we hit a function of the target API. // Those functions are modled within Call-To-Return. - if (TSD->isAPIFunction(llvm::demangle(DestFun->getName().str()))) { + if (isAPIFunction(llvm::demangle(DestFun->getName().str()))) { return killAllFlows(); } // Otherwise, if we have an ordinary function call, we can just use the @@ -282,128 +111,88 @@ IDETypeStateAnalysis::getCallFlowFunction(IDETypeStateAnalysis::n_t CallSite, llvm::report_fatal_error("callSite not a CallInst nor a InvokeInst"); } -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getRetFlowFunction( - IDETypeStateAnalysis::n_t CallSite, IDETypeStateAnalysis::f_t CalleeFun, - IDETypeStateAnalysis::n_t ExitStmt, IDETypeStateAnalysis::n_t /*RetSite*/) { - // Besides mapping the formal parameter back into the actual parameter and - // propagating the return value into the caller context, we also propagate - // all related alloca's of the formal parameter and the return value. - struct TSFlowFunction : FlowFunction { - const llvm::CallBase *CallSite; - const llvm::Function *CalleeFun; - const llvm::ReturnInst *ExitSite; - IDETypeStateAnalysis *Analysis; - std::vector Actuals; - std::vector Formals; - TSFlowFunction(const llvm::CallBase *CallSite, - const llvm::Function *CalleeFun, - const llvm::Instruction *ExitSite, - IDETypeStateAnalysis *Analysis) - : CallSite(CallSite), CalleeFun(CalleeFun), - ExitSite(llvm::dyn_cast(ExitSite)), - Analysis(Analysis) { - // Set up the actual parameters - for (unsigned Idx = 0; Idx < CallSite->arg_size(); ++Idx) { - Actuals.push_back(CallSite->getArgOperand(Idx)); - } - // Set up the formal parameters - for (unsigned Idx = 0; Idx < CalleeFun->arg_size(); ++Idx) { - Formals.push_back(getNthFunctionArgument(CalleeFun, Idx)); - } - } - - ~TSFlowFunction() override = default; +auto IDETypeStateAnalysisBase::getRetFlowFunction(n_t CallSite, f_t CalleeFun, + n_t ExitStmt, n_t /*RetSite*/) + -> FlowFunctionPtrType { - std::set - computeTargets(IDETypeStateAnalysis::d_t Source) override { - if (!LLVMZeroValue::isLLVMZeroValue(Source)) { - std::set Res; - // Handle C-style varargs functions - if (CalleeFun->isVarArg() && !CalleeFun->isDeclaration()) { - const llvm::Instruction *AllocVarArg; - // Find the allocation of %struct.__va_list_tag - for (const auto &BB : *CalleeFun) { - for (const auto &I : BB) { - if (const auto *Alloc = llvm::dyn_cast(&I)) { - if (Alloc->getAllocatedType()->isArrayTy() && - Alloc->getAllocatedType()->getArrayNumElements() > 0 && - Alloc->getAllocatedType() + /// TODO: Implement return-POI in LLVMFlowFunctions.h + return lambdaFlow([this, CalleeFun, + CS = llvm::cast(CallSite), + Ret = llvm::dyn_cast(ExitStmt)]( + d_t Source) -> container_type { + if (LLVMZeroValue::isLLVMZeroValue(Source)) { + return {Source}; + } + container_type Res; + // Handle C-style varargs functions + if (CalleeFun->isVarArg() && !CalleeFun->isDeclaration()) { + const llvm::Instruction *AllocVarArg; + // Find the allocation of %struct.__va_list_tag + for (const auto &BB : *CalleeFun) { + for (const auto &I : BB) { + if (const auto *Alloc = llvm::dyn_cast(&I)) { + if (Alloc->getAllocatedType()->isArrayTy() && + Alloc->getAllocatedType()->getArrayNumElements() > 0 && + Alloc->getAllocatedType() + ->getArrayElementType() + ->isStructTy() && + Alloc->getAllocatedType() ->getArrayElementType() - ->isStructTy() && - Alloc->getAllocatedType() - ->getArrayElementType() - ->getStructName() == "struct.__va_list_tag") { - AllocVarArg = Alloc; - // TODO break out this nested loop earlier (without goto ;-) - } - } - } - } - // Generate the varargs things by using an over-approximation - if (Source == AllocVarArg) { - for (unsigned Idx = Formals.size(); Idx < Actuals.size(); ++Idx) { - Res.insert(Actuals[Idx]); + ->getStructName() == "struct.__va_list_tag") { + AllocVarArg = Alloc; + // TODO break out this nested loop earlier (without goto ;-) } } } - // Handle ordinary case - // Map formal parameter into corresponding actual parameter. - for (unsigned Idx = 0; Idx < Formals.size(); ++Idx) { - if (Source == Formals[Idx]) { - Res.insert(Actuals[Idx]); // corresponding actual - } - } - // Collect the return value - if (Source == ExitSite->getReturnValue()) { - Res.insert(CallSite); - } - // Collect all relevant alloca's to map into caller context - std::set RelAllocas; - for (const auto *Fact : Res) { - auto Allocas = Analysis->getRelevantAllocas(Fact); - RelAllocas.insert(Allocas.begin(), Allocas.end()); + } + // Generate the varargs things by using an over-approximation + if (Source == AllocVarArg) { + for (unsigned Idx = CalleeFun->arg_size(); Idx < CS->arg_size(); + ++Idx) { + Res.insert(CS->getArgOperand(Idx)); } - Res.insert(RelAllocas.begin(), RelAllocas.end()); - return Res; } - return {Source}; } - }; - return std::make_shared(llvm::cast(CallSite), - CalleeFun, ExitStmt, this); + // Handle ordinary case + // Map formal parameter into corresponding actual parameter. + for (auto [Formal, Actual] : llvm::zip(CalleeFun->args(), CS->args())) { + if (Source == &Formal) { + Res.insert(Actual); // corresponding actual + } + } + + // Collect the return value + if (Ret && Source == Ret->getReturnValue()) { + Res.insert(CS); + } + + // Collect all relevant alloca's to map into caller context + { + container_type RelAllocas; + for (const auto *Fact : Res) { + const auto &Allocas = getRelevantAllocas(Fact); + RelAllocas.insert(Allocas.begin(), Allocas.end()); + } + Res.insert(RelAllocas.begin(), RelAllocas.end()); + } + + return Res; + }); } -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getCallToRetFlowFunction( - IDETypeStateAnalysis::n_t CallSite, IDETypeStateAnalysis::n_t /*RetSite*/, - llvm::ArrayRef Callees) { +auto IDETypeStateAnalysisBase::getCallToRetFlowFunction( + n_t CallSite, n_t /*RetSite*/, llvm::ArrayRef Callees) + -> FlowFunctionPtrType { const auto *CS = llvm::cast(CallSite); for (const auto *Callee : Callees) { std::string DemangledFname = llvm::demangle(Callee->getName().str()); // Generate the return value of factory functions from zero value - if (TSD->isFactoryFunction(DemangledFname)) { - struct TSFlowFunction : FlowFunction { - IDETypeStateAnalysis::d_t CS, ZeroValue; - - TSFlowFunction(IDETypeStateAnalysis::d_t CS, - IDETypeStateAnalysis::d_t Z) - : CS(CS), ZeroValue(Z) {} - ~TSFlowFunction() override = default; - std::set - computeTargets(IDETypeStateAnalysis::d_t Source) override { - if (Source == CS) { - return {}; - } - if (Source == ZeroValue) { - return {Source, CS}; - } - return {Source}; - } - }; - return std::make_shared(CS, getZeroValue()); + if (isFactoryFunction(DemangledFname)) { + return this->generateFromZero(CS); } + /// XXX: Revisit this: + // Handle all functions that are not modeld with special semantics. // Kill actual parameters of target type and all its aliases // and the corresponding alloca(s) as these data-flow facts are @@ -414,7 +203,7 @@ IDETypeStateAnalysis::getCallToRetFlowFunction( // not be killed during call-to-return, since it is not safe to assume // that the return value will be used afterwards, i.e. is stored to memory // pointed to by related alloca's. - if (!TSD->isAPIFunction(DemangledFname) && !Callee->isDeclaration()) { + if (!isAPIFunction(DemangledFname) && !Callee->isDeclaration()) { for (const auto &Arg : CS->args()) { if (hasMatchingType(Arg)) { return killManyFlows(getWMAliasesAndAllocas(Arg.get())); @@ -422,160 +211,21 @@ IDETypeStateAnalysis::getCallToRetFlowFunction( } } } - return Identity::getInstance(); + return identityFlow(); } -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getSummaryFlowFunction( - IDETypeStateAnalysis::n_t /*CallSite*/, - IDETypeStateAnalysis::f_t /*DestFun*/) { +auto IDETypeStateAnalysisBase::getSummaryFlowFunction(n_t /*CallSite*/, + f_t /*DestFun*/) + -> FlowFunctionPtrType { return nullptr; } -InitialSeeds -IDETypeStateAnalysis::initialSeeds() { - // just start in main() - return createDefaultSeeds(); -} - -IDETypeStateAnalysis::d_t IDETypeStateAnalysis::createZeroValue() const { - // create a special value to represent the zero value! - return LLVMZeroValue::getInstance(); -} - -bool IDETypeStateAnalysis::isZeroValue(IDETypeStateAnalysis::d_t Fact) const { - return LLVMZeroValue::isLLVMZeroValue(Fact); -} - -// in addition provide specifications for the IDE parts - -struct TSAllocaEF : TSConstant { - const llvm::AllocaInst *Alloca; - TSAllocaEF(const TypeStateDescription *Tsd, - const llvm::AllocaInst *Alloca) noexcept - : TSConstant{{{Tsd->uninit(), Tsd->getStateToString()}}, Tsd}, - Alloca(Alloca) {} - - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const TSAllocaEF &TSA) { - return OS << "Alloca(" << llvmIRToShortString(TSA.Alloca) << ")"; - } -}; - -auto IDETypeStateAnalysis::getNormalEdgeFunction( - IDETypeStateAnalysis::n_t Curr, IDETypeStateAnalysis::d_t CurrNode, - IDETypeStateAnalysis::n_t /*Succ*/, IDETypeStateAnalysis::d_t SuccNode) - -> EdgeFunction { - // Set alloca instructions of target type to uninitialized. - if (const auto *Alloca = llvm::dyn_cast(Curr)) { - if (hasMatchingType(Alloca)) { - if (CurrNode == getZeroValue() && SuccNode == Alloca) { - return TSAllocaEF(TSD, Alloca); - } - } - } - return EdgeIdentity{}; -} - -auto IDETypeStateAnalysis::getCallEdgeFunction( - IDETypeStateAnalysis::n_t /*CallSite*/, - IDETypeStateAnalysis::d_t /*SrcNode*/, - IDETypeStateAnalysis::f_t /*DestinationFunction*/, - IDETypeStateAnalysis::d_t /*DestNode*/) -> EdgeFunction { - return EdgeIdentity{}; -} - -auto IDETypeStateAnalysis::getReturnEdgeFunction( - IDETypeStateAnalysis::n_t /*CallSite*/, - IDETypeStateAnalysis::f_t /*CalleeFunction*/, - IDETypeStateAnalysis::n_t /*ExitSite*/, - IDETypeStateAnalysis::d_t /*ExitNode*/, - IDETypeStateAnalysis::n_t /*ReSite*/, IDETypeStateAnalysis::d_t /*RetNode*/) - -> EdgeFunction { - return EdgeIdentity{}; -} - -auto IDETypeStateAnalysis::getCallToRetEdgeFunction( - IDETypeStateAnalysis::n_t CallSite, IDETypeStateAnalysis::d_t CallNode, - IDETypeStateAnalysis::n_t /*RetSite*/, - IDETypeStateAnalysis::d_t RetSiteNode, llvm::ArrayRef Callees) - -> EdgeFunction { - const auto *CS = llvm::cast(CallSite); - for (const auto *Callee : Callees) { - std::string DemangledFname = llvm::demangle(Callee->getName().str()); - - // For now we assume that we can only generate from the return value. - // We apply the same edge function for the return value, i.e. callsite. - if (TSD->isFactoryFunction(DemangledFname)) { - PHASAR_LOG_LEVEL(DEBUG, "Processing factory function"); - if (isZeroValue(CallNode) && RetSiteNode == CS) { - return TSConstant{ - {{TSD->getNextState(DemangledFname, TSD->uninit(), CS), Print}}, - TSD}; - } - } - - // For every consuming parameter and all its aliases and relevant alloca's - // we apply the same edge function. - if (TSD->isConsumingFunction(DemangledFname)) { - PHASAR_LOG_LEVEL(DEBUG, "Processing consuming function"); - for (auto Idx : TSD->getConsumerParamIdx(DemangledFname)) { - std::set AliasAndAllocas = - getWMAliasesAndAllocas(CS->getArgOperand(Idx)); - - if (CallNode == RetSiteNode && - AliasAndAllocas.find(CallNode) != AliasAndAllocas.end()) { - return TSEdgeFunction{TSD, DemangledFname, CS}; - } - } - } - } - return EdgeIdentity{}; -} - -auto IDETypeStateAnalysis::getSummaryEdgeFunction( - IDETypeStateAnalysis::n_t /*CallSite*/, - IDETypeStateAnalysis::d_t /*CallNode*/, - IDETypeStateAnalysis::n_t /*RetSite*/, - IDETypeStateAnalysis::d_t /*RetSiteNode*/) -> EdgeFunction { - return nullptr; -} - -IDETypeStateAnalysis::l_t IDETypeStateAnalysis::topElement() { - return {TSD->top(), Print}; -} - -IDETypeStateAnalysis::l_t IDETypeStateAnalysis::bottomElement() { - return {TSD->bottom(), Print}; -} - -IDETypeStateAnalysis::l_t -IDETypeStateAnalysis::join(IDETypeStateAnalysis::l_t Lhs, - IDETypeStateAnalysis::l_t Rhs) { - if (Lhs == Rhs) { - return Lhs; - } - if (Lhs == TSD->top()) { - return Rhs; - } - if (Rhs == TSD->top()) { - return Lhs; - } - return {TSD->bottom(), Print}; -} - -auto IDETypeStateAnalysis::allTopFunction() -> EdgeFunction { - return AllTop{{TSD->top(), Print}}; -} - -std::set -IDETypeStateAnalysis::getRelevantAllocas(IDETypeStateAnalysis::d_t V) { +auto IDETypeStateAnalysisBase::getRelevantAllocas(d_t V) -> container_type { if (RelevantAllocaCache.find(V) != RelevantAllocaCache.end()) { return RelevantAllocaCache[V]; } auto AliasSet = getWMAliasSet(V); - std::set RelevantAllocas; + container_type RelevantAllocas; PHASAR_LOG_LEVEL(DEBUG, "Compute relevant alloca's of " << DToString(V)); for (const auto *Alias : AliasSet) { PHASAR_LOG_LEVEL(DEBUG, "Alias: " << DToString(Alias)); @@ -607,11 +257,9 @@ IDETypeStateAnalysis::getRelevantAllocas(IDETypeStateAnalysis::d_t V) { return RelevantAllocas; } -std::set -IDETypeStateAnalysis::getWMAliasSet(IDETypeStateAnalysis::d_t V) { +auto IDETypeStateAnalysisBase::getWMAliasSet(d_t V) -> container_type { if (AliasCache.find(V) != AliasCache.end()) { - std::set AliasSet(AliasCache[V].begin(), - AliasCache[V].end()); + container_type AliasSet(AliasCache[V].begin(), AliasCache[V].end()); return AliasSet; } auto PTS = PT.getAliasSet(V); @@ -620,28 +268,25 @@ IDETypeStateAnalysis::getWMAliasSet(IDETypeStateAnalysis::d_t V) { AliasCache[Alias] = *PTS; } } - std::set AliasSet(PTS->begin(), PTS->end()); + container_type AliasSet(PTS->begin(), PTS->end()); return AliasSet; } -std::set -IDETypeStateAnalysis::getWMAliasesAndAllocas(IDETypeStateAnalysis::d_t V) { - std::set AliasAndAllocas; - std::set RelevantAllocas = getRelevantAllocas(V); - std::set Aliases = getWMAliasSet(V); +auto IDETypeStateAnalysisBase::getWMAliasesAndAllocas(d_t V) -> container_type { + container_type AliasAndAllocas; + container_type RelevantAllocas = getRelevantAllocas(V); + container_type Aliases = getWMAliasSet(V); AliasAndAllocas.insert(Aliases.begin(), Aliases.end()); AliasAndAllocas.insert(RelevantAllocas.begin(), RelevantAllocas.end()); return AliasAndAllocas; } -std::set -IDETypeStateAnalysis::getLocalAliasesAndAllocas(IDETypeStateAnalysis::d_t V, - const std::string & /*Fname*/) { - std::set AliasAndAllocas; - std::set RelevantAllocas = getRelevantAllocas(V); - std::set - Aliases; // = - // IRDB->getAliasGraph(Fname)->getAliasSet(V); +auto IDETypeStateAnalysisBase::getLocalAliasesAndAllocas( + d_t V, llvm::StringRef /*Fname*/) -> container_type { + container_type AliasAndAllocas; + container_type RelevantAllocas = getRelevantAllocas(V); + container_type Aliases; // = + // IRDB->getAliasGraph(Fname)->getAliasSet(V); for (const auto *Alias : Aliases) { if (hasMatchingType(Alias)) { AliasAndAllocas.insert(Alias); @@ -651,45 +296,38 @@ IDETypeStateAnalysis::getLocalAliasesAndAllocas(IDETypeStateAnalysis::d_t V, AliasAndAllocas.insert(RelevantAllocas.begin(), RelevantAllocas.end()); return AliasAndAllocas; } -bool hasMatchingTypeName(const llvm::Type *Ty, const std::string &Pattern) { + +bool IDETypeStateAnalysisBase::hasMatchingTypeName(const llvm::Type *Ty) { if (const auto *StructTy = llvm::dyn_cast(Ty)) { - return StructTy->getName().contains(Pattern); + return isTypeNameOfInterest(StructTy->getName()); } // primitive type std::string Str; llvm::raw_string_ostream S(Str); S << *Ty; S.flush(); - return Str.find(Pattern) != std::string::npos; + return isTypeNameOfInterest(Str); } -bool IDETypeStateAnalysis::hasMatchingType(IDETypeStateAnalysis::d_t V) { + +bool IDETypeStateAnalysisBase::hasMatchingType(d_t V) { // General case if (V->getType()->isPointerTy()) { - if (hasMatchingTypeName(V->getType()->getPointerElementType(), - TSD->getTypeNameOfInterest())) { + if (hasMatchingTypeName(V->getType()->getPointerElementType())) { return true; } } if (const auto *Alloca = llvm::dyn_cast(V)) { if (Alloca->getAllocatedType()->isPointerTy()) { if (hasMatchingTypeName( - Alloca->getAllocatedType()->getPointerElementType(), - TSD->getTypeNameOfInterest())) { + Alloca->getAllocatedType()->getPointerElementType())) { return true; } } return false; } if (const auto *Load = llvm::dyn_cast(V)) { - if (Load->getPointerOperand() - ->getType() - ->getPointerElementType() - ->isPointerTy()) { - if (hasMatchingTypeName(Load->getPointerOperand() - ->getType() - ->getPointerElementType() - ->getPointerElementType(), - TSD->getTypeNameOfInterest())) { + if (Load->getType()->isPointerTy()) { + if (hasMatchingTypeName(Load->getType()->getPointerElementType())) { return true; } } @@ -698,8 +336,7 @@ bool IDETypeStateAnalysis::hasMatchingType(IDETypeStateAnalysis::d_t V) { if (const auto *Store = llvm::dyn_cast(V)) { if (Store->getValueOperand()->getType()->isPointerTy()) { if (hasMatchingTypeName( - Store->getValueOperand()->getType()->getPointerElementType(), - TSD->getTypeNameOfInterest())) { + Store->getValueOperand()->getType()->getPointerElementType())) { return true; } } @@ -708,85 +345,4 @@ bool IDETypeStateAnalysis::hasMatchingType(IDETypeStateAnalysis::d_t V) { return false; } -void IDETypeStateAnalysis::emitTextReport( - const SolverResults &SR, - llvm::raw_ostream &OS) { - - LLVMBasedCFG CFG; - OS << "\n======= TYPE STATE RESULTS =======\n"; - for (const auto &F : IRDB->getAllFunctions()) { - OS << '\n' << getFunctionNameFromIR(F) << '\n'; - for (const auto &BB : *F) { - for (const auto &I : BB) { - auto Results = SR.resultsAt(&I, true); - if (CFG.isExitInst(&I)) { - OS << "\nAt exit stmt: " << NToString(&I) << '\n'; - for (auto Res : Results) { - if (const auto *Alloca = - llvm::dyn_cast(Res.first)) { - if (Res.second == TSD->error()) { - OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " - << DToString(Res.first) << '\n'; - for (const auto *Pred : CFG.getPredsOf(&I)) { - OS << "\nPredecessor: " << NToString(Pred) << '\n'; - auto PredResults = SR.resultsAt(Pred, true); - for (auto Res : PredResults) { - if (Res.first == Alloca) { - OS << "Pred State: " << LToString(Res.second) << '\n'; - } - } - } - OS << "============================\n"; - } else { - OS << "\nAlloca : " << DToString(Res.first) - << "\nState : " << LToString(Res.second) << '\n'; - } - } else { - OS << "\nInst: " << NToString(&I) << '\n' - << "Fact: " << DToString(Res.first) << '\n' - << "State: " << LToString(Res.second) << '\n'; - } - } - } else { - for (auto Res : Results) { - if (const auto *Alloca = - llvm::dyn_cast(Res.first)) { - if (Res.second == TSD->error()) { - OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " - << DToString(Res.first) << '\n' - << "\nAt IR Inst: " << NToString(&I) << '\n'; - for (const auto *Pred : CFG.getPredsOf(&I)) { - OS << "\nPredecessor: " << NToString(Pred) << '\n'; - auto PredResults = SR.resultsAt(Pred, true); - for (auto Res : PredResults) { - if (Res.first == Alloca) { - OS << "Pred State: " << LToString(Res.second) << '\n'; - } - } - } - OS << "============================\n"; - } - } else { - OS << "\nInst: " << NToString(&I) << '\n' - << "Fact: " << DToString(Res.first) << '\n' - << "State: " << LToString(Res.second) << '\n'; - } - } - } - } - } - OS << "\n--------------------------------------------\n"; - } -} - -} // namespace psr - -std::string psr::LToString(TypeState S) { - if (!S.Print) { - PHASAR_LOG_LEVEL(WARNING, "Printing default constructed TypeState"); - return "TOP"; - } - - return S.Print(S.State); -} +} // namespace psr::detail diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp index e7ac81794f..ba640d0bab 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp @@ -9,14 +9,14 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" + #include "llvm/ADT/StringMap.h" #include "llvm/Support/ErrorHandling.h" #include namespace psr { - -namespace { /** * We use the following lattice * BOT = all information @@ -25,14 +25,16 @@ namespace { * * TOP = no information */ -enum CSTDFILEIOState { - TOP = 42, - UNINIT = 0, - OPENED = 1, - CLOSED = 2, - ERROR = 3, - BOT = 4 -}; +// enum class CSTDFILEIOState { +// TOP = 42, +// UNINIT = 0, +// OPENED = 1, +// CLOSED = 2, +// ERROR = 3, +// BOT = 4 +// }; + +namespace { /** * The STAR token represents all API functions besides fopen(), fdopen() and @@ -71,7 +73,7 @@ const llvm::StringMap> &getStdFileIOFuncs() noexcept { return StdFileIOFuncs; } -CSTDFILEIOToken funcNameToToken(const std::string &F) { +CSTDFILEIOToken funcNameToToken(llvm::StringRef F) { if (F == "fopen" || F == "fdopen") { return CSTDFILEIOToken::FOPEN; } @@ -88,7 +90,7 @@ CSTDFILEIOToken funcNameToToken(const std::string &F) { // States: UNINIT = 0, OPENED = 1, CLOSED = 2, ERROR = 3, BOT = 4 bool CSTDFILEIOTypeStateDescription::isFactoryFunction( - const std::string &F) const { + llvm::StringRef F) const { if (isAPIFunction(F)) { return getStdFileIOFuncs().lookup(F).count(-1); } @@ -96,24 +98,25 @@ bool CSTDFILEIOTypeStateDescription::isFactoryFunction( } bool CSTDFILEIOTypeStateDescription::isConsumingFunction( - const std::string &F) const { + llvm::StringRef F) const { if (isAPIFunction(F)) { return !getStdFileIOFuncs().lookup(F).count(-1); } return false; } -bool CSTDFILEIOTypeStateDescription::isAPIFunction(const std::string &F) const { +bool CSTDFILEIOTypeStateDescription::isAPIFunction(llvm::StringRef F) const { return getStdFileIOFuncs().count(F); } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::getNextState( - std::string Tok, TypeStateDescription::State S) const { +CSTDFILEIOState +CSTDFILEIOTypeStateDescription::getNextState(llvm::StringRef Tok, + State S) const { if (isAPIFunction(Tok)) { auto X = static_cast>( funcNameToToken(Tok)); - auto Ret = Delta[X][S]; + auto Ret = Delta[X][int(S)]; // if (ret == error()) { // std::cerr << "getNextState(" << Tok << ", " << stateToString(S) // << ") = " << stateToString(Ret) << std::endl; @@ -127,8 +130,8 @@ std::string CSTDFILEIOTypeStateDescription::getTypeNameOfInterest() const { return "struct._IO_FILE"; } -std::set CSTDFILEIOTypeStateDescription::getConsumerParamIdx( - const std::string &F) const { +std::set +CSTDFILEIOTypeStateDescription::getConsumerParamIdx(llvm::StringRef F) const { if (isConsumingFunction(F)) { return getStdFileIOFuncs().lookup(F); } @@ -136,7 +139,7 @@ std::set CSTDFILEIOTypeStateDescription::getConsumerParamIdx( } std::set -CSTDFILEIOTypeStateDescription::getFactoryParamIdx(const std::string &F) const { +CSTDFILEIOTypeStateDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -144,53 +147,51 @@ CSTDFILEIOTypeStateDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -auto CSTDFILEIOTypeStateDescription::getStateToString() const - -> std::string (*)(int) { - return [](TypeStateDescription::State S) -> std::string { - switch (S) { - case CSTDFILEIOState::TOP: - return "TOP"; - break; - case CSTDFILEIOState::UNINIT: - return "UNINIT"; - break; - case CSTDFILEIOState::OPENED: - return "OPENED"; - break; - case CSTDFILEIOState::CLOSED: - return "CLOSED"; - break; - case CSTDFILEIOState::ERROR: - return "ERROR"; - break; - case CSTDFILEIOState::BOT: - return "BOT"; - break; - default: - llvm::report_fatal_error("received unknown state!"); - break; - } - }; +llvm::StringRef to_string(CSTDFILEIOState State) noexcept { + switch (State) { + case CSTDFILEIOState::TOP: + return "TOP"; + break; + case CSTDFILEIOState::UNINIT: + return "UNINIT"; + break; + case CSTDFILEIOState::OPENED: + return "OPENED"; + break; + case CSTDFILEIOState::CLOSED: + return "CLOSED"; + break; + case CSTDFILEIOState::ERROR: + return "ERROR"; + break; + case CSTDFILEIOState::BOT: + return "BOT"; + break; + } + + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::bottom() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::bottom() const { return CSTDFILEIOState::BOT; } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::top() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::top() const { return CSTDFILEIOState::TOP; } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::uninit() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::uninit() const { return CSTDFILEIOState::UNINIT; } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::start() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::start() const { return CSTDFILEIOState::OPENED; } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::error() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::error() const { return CSTDFILEIOState::ERROR; } +template class IDETypeStateAnalysis; + } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp index 7708a7c23d..df37f0bcb6 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp @@ -21,12 +21,11 @@ namespace psr { // Return value is modeled as -1 -const std::map> - OpenSSLEVPKDFCTXDescription::OpenSSLEVPKDFFuncs = { - {"EVP_KDF_CTX_new", {-1}}, - {"EVP_KDF_CTX_set_params", {0}}, - {"EVP_KDF_derive", {0}}, - {"EVP_KDF_CTX_free", {0}} +static const std::map> OpenSSLEVPKDFFuncs = { + {"EVP_KDF_CTX_new", {-1}}, + {"EVP_KDF_CTX_set_params", {0}}, + {"EVP_KDF_derive", {0}}, + {"EVP_KDF_CTX_free", {0}} }; @@ -39,86 +38,82 @@ const std::map> // // States: UNINIT = 5, CTX_ATTACHED =1, PARAM_INIT = 2, // DERIVED = 3, ERROR = 4, BOT = 0 -const OpenSSLEVPKDFCTXDescription::OpenSSLEVPKDFState - OpenSSLEVPKDFCTXDescription::Delta[5][6] = { - - /* EVP_KDF_CTX_NEW */ - {OpenSSLEVPKDFState::CTX_ATTACHED, OpenSSLEVPKDFState::CTX_ATTACHED, - OpenSSLEVPKDFState::CTX_ATTACHED, OpenSSLEVPKDFState::CTX_ATTACHED, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::CTX_ATTACHED}, - /* EVP_KDF_CTX_SET_PARAMS */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::PARAM_INIT, - OpenSSLEVPKDFState::PARAM_INIT, OpenSSLEVPKDFState::PARAM_INIT, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR}, - /* DERIVE */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR, - OpenSSLEVPKDFState::DERIVED, OpenSSLEVPKDFState::DERIVED, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR}, - /* EVP_KDF_CTX_FREE */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::UNINIT, - OpenSSLEVPKDFState::UNINIT, OpenSSLEVPKDFState::UNINIT, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR}, - - /* STAR */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::CTX_ATTACHED, - OpenSSLEVPKDFState::PARAM_INIT, OpenSSLEVPKDFState::DERIVED, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR}, +const OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::Delta[5][6] = { + + /* EVP_KDF_CTX_NEW */ + {OpenSSLEVPKDFCTXState::CTX_ATTACHED, OpenSSLEVPKDFCTXState::CTX_ATTACHED, + OpenSSLEVPKDFCTXState::CTX_ATTACHED, OpenSSLEVPKDFCTXState::CTX_ATTACHED, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + /* EVP_KDF_CTX_SET_PARAMS */ + {OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::PARAM_INIT, + OpenSSLEVPKDFCTXState::PARAM_INIT, OpenSSLEVPKDFCTXState::PARAM_INIT, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR}, + /* DERIVE */ + {OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR, + OpenSSLEVPKDFCTXState::DERIVED, OpenSSLEVPKDFCTXState::DERIVED, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR}, + /* EVP_KDF_CTX_FREE */ + {OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::UNINIT, + OpenSSLEVPKDFCTXState::UNINIT, OpenSSLEVPKDFCTXState::UNINIT, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR}, + + /* STAR */ + {OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::CTX_ATTACHED, + OpenSSLEVPKDFCTXState::PARAM_INIT, OpenSSLEVPKDFCTXState::DERIVED, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR}, }; -bool OpenSSLEVPKDFCTXDescription::isFactoryFunction( - const std::string &F) const { +bool OpenSSLEVPKDFCTXDescription::isFactoryFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLEVPKDFFuncs.at(F).find(-1) != OpenSSLEVPKDFFuncs.at(F).end(); } return false; } -bool OpenSSLEVPKDFCTXDescription::isConsumingFunction( - const std::string &F) const { +bool OpenSSLEVPKDFCTXDescription::isConsumingFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLEVPKDFFuncs.at(F).find(-1) == OpenSSLEVPKDFFuncs.at(F).end(); } return false; } -bool OpenSSLEVPKDFCTXDescription::isAPIFunction(const std::string &F) const { +bool OpenSSLEVPKDFCTXDescription::isAPIFunction(llvm::StringRef F) const { return OpenSSLEVPKDFFuncs.find(F) != OpenSSLEVPKDFFuncs.end(); } -TypeStateDescription::State -OpenSSLEVPKDFCTXDescription::getNextState(std::string Tok, +OpenSSLEVPKDFCTXState +OpenSSLEVPKDFCTXDescription::getNextState(llvm::StringRef Tok, TypeStateDescription::State S) const { if (isAPIFunction(Tok)) { auto NameToTok = funcNameToToken(Tok); auto Ret = Delta[static_cast>( - NameToTok)][S]; + NameToTok)][int(S)]; // std::cout << "delta[" << Tok << ", " << stateToString(S) // << "] = " << stateToString(ret) << std::endl; return Ret; } - return OpenSSLEVPKDFState::BOT; + return OpenSSLEVPKDFCTXState::BOT; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::getNextState( - const std::string &Tok, TypeStateDescription::State S, +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::getNextState( + llvm::StringRef Tok, TypeStateDescription::State S, const llvm::CallBase *CallSite) const { if (isAPIFunction(Tok)) { auto NameToTok = funcNameToToken(Tok); auto Ret = Delta[static_cast>( - NameToTok)][S]; + NameToTok)][int(S)]; if (NameToTok == OpenSSLEVTKDFToken::EVP_KDF_CTX_NEW) { // require the kdf here to be in KDF_FETCHED state // requiredKDFState[make_pair(CS.getInstruction(), CS.getArgOperand(0))] = - // (OpenSSLEVPKDFDescription::OpenSSLEVPKDFState::KDF_FETCHED); + // (OpenSSLEVPKDFDescription::OpenSSLEVPKDFCTXState::KDF_FETCHED); // cout << "## Factory-Call: "; // cout.flush(); // cout << llvmIRToShortString(CS.getInstruction()) << endl; auto KdfState = KDFAnalysisResults.resultAt(CallSite, CallSite->getArgOperand(0)); - if (KdfState != - OpenSSLEVPKDFDescription::OpenSSLEVPKDFState::KDF_FETCHED) { + if (KdfState != OpenSSLEVPKDFState::KDF_FETCHED) { return error(); } } @@ -126,7 +121,7 @@ TypeStateDescription::State OpenSSLEVPKDFCTXDescription::getNextState( // << "] = " << stateToString(ret) << std::endl; return Ret; } - return OpenSSLEVPKDFState::BOT; + return OpenSSLEVPKDFCTXState::BOT; } std::string OpenSSLEVPKDFCTXDescription::getTypeNameOfInterest() const { @@ -134,7 +129,7 @@ std::string OpenSSLEVPKDFCTXDescription::getTypeNameOfInterest() const { } std::set -OpenSSLEVPKDFCTXDescription::getConsumerParamIdx(const std::string &F) const { +OpenSSLEVPKDFCTXDescription::getConsumerParamIdx(llvm::StringRef F) const { if (isConsumingFunction(F)) { return OpenSSLEVPKDFFuncs.at(F); } @@ -142,7 +137,7 @@ OpenSSLEVPKDFCTXDescription::getConsumerParamIdx(const std::string &F) const { } std::set -OpenSSLEVPKDFCTXDescription::getFactoryParamIdx(const std::string &F) const { +OpenSSLEVPKDFCTXDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -150,61 +145,57 @@ OpenSSLEVPKDFCTXDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -auto OpenSSLEVPKDFCTXDescription::getStateToString() const - -> std::string (*)(int) { - return [](TypeStateDescription::State S) -> std::string { - switch (S) { - case OpenSSLEVPKDFState::TOP: - return "TOP"; - break; - case OpenSSLEVPKDFState::UNINIT: - return "UNINIT"; - break; - - case OpenSSLEVPKDFState::CTX_ATTACHED: - return "CTX_ATTACHED"; - break; - case OpenSSLEVPKDFState::PARAM_INIT: - return "PARAM_INIT"; - break; - case OpenSSLEVPKDFState::DERIVED: - return "DERIVED"; - break; - case OpenSSLEVPKDFState::ERROR: - return "ERROR"; - break; - case OpenSSLEVPKDFState::BOT: - return "BOT"; - break; - default: - llvm::report_fatal_error("received unknown state!"); - break; - } - }; +llvm::StringRef to_string(OpenSSLEVPKDFCTXState State) noexcept { + switch (State) { + case OpenSSLEVPKDFCTXState::TOP: + return "TOP"; + break; + case OpenSSLEVPKDFCTXState::UNINIT: + return "UNINIT"; + break; + + case OpenSSLEVPKDFCTXState::CTX_ATTACHED: + return "CTX_ATTACHED"; + break; + case OpenSSLEVPKDFCTXState::PARAM_INIT: + return "PARAM_INIT"; + break; + case OpenSSLEVPKDFCTXState::DERIVED: + return "DERIVED"; + break; + case OpenSSLEVPKDFCTXState::ERROR: + return "ERROR"; + break; + case OpenSSLEVPKDFCTXState::BOT: + return "BOT"; + break; + } + + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::bottom() const { - return OpenSSLEVPKDFState::BOT; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::bottom() const { + return OpenSSLEVPKDFCTXState::BOT; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::top() const { - return OpenSSLEVPKDFState::TOP; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::top() const { + return OpenSSLEVPKDFCTXState::TOP; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::uninit() const { - return OpenSSLEVPKDFState::UNINIT; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::uninit() const { + return OpenSSLEVPKDFCTXState::UNINIT; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::start() const { - return OpenSSLEVPKDFState::CTX_ATTACHED; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::start() const { + return OpenSSLEVPKDFCTXState::CTX_ATTACHED; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::error() const { - return OpenSSLEVPKDFState::ERROR; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::error() const { + return OpenSSLEVPKDFCTXState::ERROR; } OpenSSLEVPKDFCTXDescription::OpenSSLEVTKDFToken -OpenSSLEVPKDFCTXDescription::funcNameToToken(const std::string &F) { +OpenSSLEVPKDFCTXDescription::funcNameToToken(llvm::StringRef F) { if (F == "EVP_KDF_CTX_new") { return OpenSSLEVTKDFToken::EVP_KDF_CTX_NEW; } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp index c7ba38c397..4c0973cf7e 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp @@ -18,9 +18,8 @@ namespace psr { // Return value is modeled as -1 -const std::map> - OpenSSLEVPKDFDescription::OpenSSLEVPKDFFuncs = {{"EVP_KDF_fetch", {-1}}, - {"EVP_KDF_free", {0}} +static const std::map> OpenSSLEVPKDFFuncs = { + {"EVP_KDF_fetch", {-1}}, {"EVP_KDF_free", {0}} }; @@ -30,44 +29,43 @@ const std::map> // STAR = 2 // // States: UNINIT = 0, KDF_FETCHED = 1, ERROR = 2, BOT = 3 -const OpenSSLEVPKDFDescription::OpenSSLEVPKDFState - OpenSSLEVPKDFDescription::Delta[3][4] = { - /* EVP_KDF_FETCH */ - {OpenSSLEVPKDFState::KDF_FETCHED, OpenSSLEVPKDFState::ERROR, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::KDF_FETCHED}, - /* EVP_KDF_CTX_FREE */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::UNINIT, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::BOT}, - - /* STAR */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::KDF_FETCHED, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::BOT}, +const OpenSSLEVPKDFState OpenSSLEVPKDFDescription::Delta[3][4] = { + /* EVP_KDF_FETCH */ + {OpenSSLEVPKDFState::KDF_FETCHED, OpenSSLEVPKDFState::ERROR, + OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::KDF_FETCHED}, + /* EVP_KDF_CTX_FREE */ + {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::UNINIT, + OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::BOT}, + + /* STAR */ + {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::KDF_FETCHED, + OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::BOT}, }; -bool OpenSSLEVPKDFDescription::isFactoryFunction(const std::string &F) const { +bool OpenSSLEVPKDFDescription::isFactoryFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLEVPKDFFuncs.at(F).find(-1) != OpenSSLEVPKDFFuncs.at(F).end(); } return false; } -bool OpenSSLEVPKDFDescription::isConsumingFunction(const std::string &F) const { +bool OpenSSLEVPKDFDescription::isConsumingFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLEVPKDFFuncs.at(F).find(-1) == OpenSSLEVPKDFFuncs.at(F).end(); } return false; } -bool OpenSSLEVPKDFDescription::isAPIFunction(const std::string &F) const { +bool OpenSSLEVPKDFDescription::isAPIFunction(llvm::StringRef F) const { return OpenSSLEVPKDFFuncs.find(F) != OpenSSLEVPKDFFuncs.end(); } -TypeStateDescription::State -OpenSSLEVPKDFDescription::getNextState(std::string Tok, +OpenSSLEVPKDFState +OpenSSLEVPKDFDescription::getNextState(llvm::StringRef Tok, TypeStateDescription::State S) const { if (isAPIFunction(Tok)) { auto Ret = Delta[static_cast>( - funcNameToToken(Tok))][S]; + funcNameToToken(Tok))][int(S)]; // std::cout << "Delta[" << Tok << ", " << stateToString(S) // << "] = " << stateToString(ret) << std::endl; return Ret; @@ -80,7 +78,7 @@ std::string OpenSSLEVPKDFDescription::getTypeNameOfInterest() const { } std::set -OpenSSLEVPKDFDescription::getConsumerParamIdx(const std::string &F) const { +OpenSSLEVPKDFDescription::getConsumerParamIdx(llvm::StringRef F) const { if (isConsumingFunction(F)) { return OpenSSLEVPKDFFuncs.at(F); } @@ -88,7 +86,7 @@ OpenSSLEVPKDFDescription::getConsumerParamIdx(const std::string &F) const { } std::set -OpenSSLEVPKDFDescription::getFactoryParamIdx(const std::string &F) const { +OpenSSLEVPKDFDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -96,49 +94,44 @@ OpenSSLEVPKDFDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -auto OpenSSLEVPKDFDescription::getStateToString() const - -> std::string (*)(int) { - return [](TypeStateDescription::State S) -> std::string { - switch (S) { - case OpenSSLEVPKDFState::TOP: - return "TOP"; - case OpenSSLEVPKDFState::UNINIT: - return "UNINIT"; - case OpenSSLEVPKDFState::KDF_FETCHED: - return "KDF_FETCHED"; - case OpenSSLEVPKDFState::ERROR: - return "ERROR"; - case OpenSSLEVPKDFState::BOT: - return "BOT"; - default: - llvm::report_fatal_error("received unknown state!"); - break; - } - }; +llvm::StringRef to_string(OpenSSLEVPKDFState State) noexcept { + switch (State) { + case OpenSSLEVPKDFState::TOP: + return "TOP"; + case OpenSSLEVPKDFState::UNINIT: + return "UNINIT"; + case OpenSSLEVPKDFState::KDF_FETCHED: + return "KDF_FETCHED"; + case OpenSSLEVPKDFState::ERROR: + return "ERROR"; + case OpenSSLEVPKDFState::BOT: + return "BOT"; + } + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State OpenSSLEVPKDFDescription::bottom() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::bottom() const { return OpenSSLEVPKDFState::BOT; } -TypeStateDescription::State OpenSSLEVPKDFDescription::top() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::top() const { return OpenSSLEVPKDFState::TOP; } -TypeStateDescription::State OpenSSLEVPKDFDescription::uninit() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::uninit() const { return OpenSSLEVPKDFState::UNINIT; } -TypeStateDescription::State OpenSSLEVPKDFDescription::start() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::start() const { return OpenSSLEVPKDFState::KDF_FETCHED; } -TypeStateDescription::State OpenSSLEVPKDFDescription::error() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::error() const { return OpenSSLEVPKDFState::ERROR; } OpenSSLEVPKDFDescription::OpenSSLEVTKDFToken -OpenSSLEVPKDFDescription::funcNameToToken(const std::string &FuncName) { +OpenSSLEVPKDFDescription::funcNameToToken(llvm::StringRef FuncName) { if (FuncName == "EVP_KDF_fetch") { return OpenSSLEVTKDFToken::EVP_KDF_FETCH; } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp index c954f1e39d..3c0a90a67f 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp @@ -18,48 +18,45 @@ using namespace psr; namespace psr { // Return value is modeled as -1 -const std::map> - OpenSSLSecureHeapDescription::OpenSSLSecureHeapFuncs = { - {"CRYPTO_secure_malloc", {-1}}, - {"CRYPTO_secure_zalloc", {-1}}, - {"CRYPTO_secure_free", {0}}, - {"CRYPTO_secure_clear_free", {0}}}; +static const std::map> OpenSSLSecureHeapFuncs = { + {"CRYPTO_secure_malloc", {-1}}, + {"CRYPTO_secure_zalloc", {-1}}, + {"CRYPTO_secure_free", {0}}, + {"CRYPTO_secure_clear_free", {0}}}; // delta[Token][State] = next State // Token: SECURE_MALLOC = 0, SECURE_ZALLOC = 1, SECURE_FREE = 2, // SECURE_CLEAR_FREE = 3, STAR = 4 // // States: BOT = 0, UNINIT = 1, ALLOCATED = 2, ZEROED = 3, FREED = 4, ERROR = 5 -const OpenSSLSecureHeapDescription::OpenSSLSecureHeapState - OpenSSLSecureHeapDescription::Delta[5][6] = { - // SECURE_MALLOC - {OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED, - OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED, - OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED}, - // SECURE_ZALLOC - {OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED, - OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED, - OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED}, - // SECURE_FREE - {OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR, - OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::FREED, - OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR}, - // SECURE_CLEAR_FREE - {OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR, - OpenSSLSecureHeapState::FREED, OpenSSLSecureHeapState::FREED, - OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR}, - // STAR - {OpenSSLSecureHeapState::BOT, OpenSSLSecureHeapState::UNINIT, - OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ZEROED, - OpenSSLSecureHeapState::FREED, OpenSSLSecureHeapState::ERROR}, +const OpenSSLSecureHeapState OpenSSLSecureHeapDescription::Delta[5][6] = { + // SECURE_MALLOC + {OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED, + OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED, + OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED}, + // SECURE_ZALLOC + {OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED, + OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED, + OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED}, + // SECURE_FREE + {OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR, + OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::FREED, + OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR}, + // SECURE_CLEAR_FREE + {OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR, + OpenSSLSecureHeapState::FREED, OpenSSLSecureHeapState::FREED, + OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR}, + // STAR + {OpenSSLSecureHeapState::BOT, OpenSSLSecureHeapState::UNINIT, + OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ZEROED, + OpenSSLSecureHeapState::FREED, OpenSSLSecureHeapState::ERROR}, }; OpenSSLSecureHeapDescription::OpenSSLSecureHeapDescription( IDESolver &SecureHeapPropagationResults) : SecureHeapPropagationResults(SecureHeapPropagationResults) {} -bool OpenSSLSecureHeapDescription::isFactoryFunction( - const std::string &F) const { +bool OpenSSLSecureHeapDescription::isFactoryFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLSecureHeapFuncs.at(F).find(-1) != OpenSSLSecureHeapFuncs.at(F).end(); @@ -68,7 +65,7 @@ bool OpenSSLSecureHeapDescription::isFactoryFunction( } bool OpenSSLSecureHeapDescription::isConsumingFunction( - const std::string &F) const { + llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLSecureHeapFuncs.at(F).find(-1) == OpenSSLSecureHeapFuncs.at(F).end(); @@ -76,23 +73,23 @@ bool OpenSSLSecureHeapDescription::isConsumingFunction( return false; } -bool OpenSSLSecureHeapDescription::isAPIFunction(const std::string &F) const { +bool OpenSSLSecureHeapDescription::isAPIFunction(llvm::StringRef F) const { return OpenSSLSecureHeapFuncs.find(F) != OpenSSLSecureHeapFuncs.end(); } -TypeStateDescription::State OpenSSLSecureHeapDescription::getNextState( - std::string Tok, TypeStateDescription::State S) const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::getNextState( + llvm::StringRef Tok, TypeStateDescription::State S) const { if (isAPIFunction(Tok)) { auto Ftok = static_cast>( funcNameToToken(Tok)); - return Delta[Ftok][S]; + return Delta[Ftok][int(S)]; } return OpenSSLSecureHeapState::BOT; } -TypeStateDescription::State OpenSSLSecureHeapDescription::getNextState( - const std::string &Tok, TypeStateDescription::State S, +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::getNextState( + llvm::StringRef Tok, TypeStateDescription::State S, const llvm::CallBase *CallSite) const { if (isAPIFunction(Tok)) { auto Ftok = static_cast>( @@ -104,7 +101,7 @@ TypeStateDescription::State OpenSSLSecureHeapDescription::getNextState( // << llvmIRToShortString(CS.getInstruction()) << std::endl; return error(); } - return Delta[Ftok][S]; + return Delta[Ftok][int(S)]; } return error(); } @@ -114,7 +111,7 @@ std::string OpenSSLSecureHeapDescription::getTypeNameOfInterest() const { } set -OpenSSLSecureHeapDescription::getConsumerParamIdx(const std::string &F) const { +OpenSSLSecureHeapDescription::getConsumerParamIdx(llvm::StringRef F) const { if (isConsumingFunction(F)) { return OpenSSLSecureHeapFuncs.at(F); } @@ -122,7 +119,7 @@ OpenSSLSecureHeapDescription::getConsumerParamIdx(const std::string &F) const { } set -OpenSSLSecureHeapDescription::getFactoryParamIdx(const std::string &F) const { +OpenSSLSecureHeapDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -130,52 +127,49 @@ OpenSSLSecureHeapDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -auto OpenSSLSecureHeapDescription::getStateToString() const - -> std::string (*)(int) { - return [](TypeStateDescription::State S) -> std::string { - switch (S) { - case OpenSSLSecureHeapState::TOP: - return "TOP"; - case OpenSSLSecureHeapState::BOT: - return "BOT"; - case OpenSSLSecureHeapState::ALLOCATED: - return "ALLOCATED"; - case OpenSSLSecureHeapState::UNINIT: - return "UNINIT"; - case OpenSSLSecureHeapState::FREED: - return "FREED"; - case OpenSSLSecureHeapState::ERROR: - return "ERROR"; - default: - llvm::report_fatal_error("received unknown state!"); - break; - } - }; +llvm::StringRef to_string(OpenSSLSecureHeapState State) noexcept { + switch (State) { + case OpenSSLSecureHeapState::TOP: + return "TOP"; + case OpenSSLSecureHeapState::BOT: + return "BOT"; + case OpenSSLSecureHeapState::ALLOCATED: + return "ALLOCATED"; + case OpenSSLSecureHeapState::UNINIT: + return "UNINIT"; + case OpenSSLSecureHeapState::FREED: + return "FREED"; + case OpenSSLSecureHeapState::ERROR: + return "ERROR"; + case OpenSSLSecureHeapState::ZEROED: + return "ZEROED"; + } + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State OpenSSLSecureHeapDescription::bottom() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::bottom() const { return OpenSSLSecureHeapState::BOT; } -TypeStateDescription::State OpenSSLSecureHeapDescription::top() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::top() const { return OpenSSLSecureHeapState::TOP; } -TypeStateDescription::State OpenSSLSecureHeapDescription::start() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::start() const { llvm::report_fatal_error("TypeStateDescription::start() is deprecated"); return OpenSSLSecureHeapState::BOT; } -TypeStateDescription::State OpenSSLSecureHeapDescription::uninit() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::uninit() const { return OpenSSLSecureHeapState::UNINIT; } -TypeStateDescription::State OpenSSLSecureHeapDescription::error() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::error() const { return OpenSSLSecureHeapState::ERROR; } OpenSSLSecureHeapDescription::OpenSSLSecureHeapToken -OpenSSLSecureHeapDescription::funcNameToToken(const std::string &F) { +OpenSSLSecureHeapDescription::funcNameToToken(llvm::StringRef F) { return llvm::StringSwitch(F) .Case("CRYPTO_secure_malloc", OpenSSLSecureHeapToken::SECURE_MALLOC) .Case("CRYPTO_secure_zalloc", OpenSSLSecureHeapToken::SECURE_ZALLOC) diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp index 434b0ae004..e71e30b0ea 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp @@ -21,9 +21,7 @@ using namespace std; using namespace psr; namespace psr { - -namespace { -enum OpenSSLSecureMemoryState { +enum class OpenSSLSecureMemoryState { TOP = 42, BOT = 0, ZEROED = 1, @@ -32,6 +30,8 @@ enum OpenSSLSecureMemoryState { ALLOCATED = 4 }; +namespace { + enum class OpenSSLSecureMemoryToken { CRYPTO_MALLOC = 0, CRYPTO_ZALLOC = 1, @@ -73,7 +73,7 @@ constexpr OpenSSLSecureMemoryState Delta[6][7] = { OpenSSLSecureMemoryState::FREED, OpenSSLSecureMemoryState::ERROR, OpenSSLSecureMemoryState::ALLOCATED}}; -OpenSSLSecureMemoryToken funcNameToToken(const std::string &F) { +OpenSSLSecureMemoryToken funcNameToToken(llvm::StringRef F) { return llvm::StringSwitch(F) .Case("CRYPTO_malloc", OpenSSLSecureMemoryToken::CRYPTO_MALLOC) .Case("CRYPTO_zalloc", OpenSSLSecureMemoryToken::CRYPTO_ZALLOC) @@ -85,27 +85,27 @@ OpenSSLSecureMemoryToken funcNameToToken(const std::string &F) { } // namespace bool OpenSSLSecureMemoryDescription::isFactoryFunction( - const std::string &F) const { + llvm::StringRef F) const { return llvm::is_contained(FactoryFuncs, F); } bool OpenSSLSecureMemoryDescription::isConsumingFunction( - const std::string &F) const { + llvm::StringRef F) const { return llvm::find_if(ConsumingFuncs, [&F](const auto &Pair) { return F == Pair.first; }) != ConsumingFuncs.end(); } -bool OpenSSLSecureMemoryDescription::isAPIFunction(const std::string &F) const { +bool OpenSSLSecureMemoryDescription::isAPIFunction(llvm::StringRef F) const { return funcNameToToken(F) != OpenSSLSecureMemoryToken::STAR; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::getNextState( - std::string Tok, TypeStateDescription::State S) const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::getNextState( + llvm::StringRef Tok, TypeStateDescription::State S) const { auto Token = funcNameToToken(Tok); if (Token != OpenSSLSecureMemoryToken::STAR) { return Delta[static_cast>( - Token)][S]; + Token)][int(S)]; } return OpenSSLSecureMemoryState::BOT; } @@ -114,8 +114,8 @@ std::string OpenSSLSecureMemoryDescription::getTypeNameOfInterest() const { return "i8"; // NOT SURE WHAT TO DO WITH THIS } -set OpenSSLSecureMemoryDescription::getConsumerParamIdx( - const std::string &F) const { +set +OpenSSLSecureMemoryDescription::getConsumerParamIdx(llvm::StringRef F) const { if (const auto *It = llvm::find_if( ConsumingFuncs, [&F](const auto &Pair) { return F == Pair.first; }); It != ConsumingFuncs.end()) { @@ -125,7 +125,7 @@ set OpenSSLSecureMemoryDescription::getConsumerParamIdx( } set -OpenSSLSecureMemoryDescription::getFactoryParamIdx(const std::string &F) const { +OpenSSLSecureMemoryDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -133,46 +133,41 @@ OpenSSLSecureMemoryDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -auto OpenSSLSecureMemoryDescription::getStateToString() const - -> std::string (*)(int) { - return [](TypeStateDescription::State S) -> std::string { - switch (S) { - case OpenSSLSecureMemoryState::TOP: - return "TOP"; - case OpenSSLSecureMemoryState::BOT: - return "BOT"; - case OpenSSLSecureMemoryState::ALLOCATED: - return "ALLOCATED"; - case OpenSSLSecureMemoryState::FREED: - return "FREED"; - case OpenSSLSecureMemoryState::ZEROED: - return "ZEROED"; - case OpenSSLSecureMemoryState::ERROR: - return "ERROR"; - default: - llvm::report_fatal_error("received unknown state!"); - break; - } - }; +llvm::StringRef to_string(OpenSSLSecureMemoryState State) noexcept { + switch (State) { + case OpenSSLSecureMemoryState::TOP: + return "TOP"; + case OpenSSLSecureMemoryState::BOT: + return "BOT"; + case OpenSSLSecureMemoryState::ALLOCATED: + return "ALLOCATED"; + case OpenSSLSecureMemoryState::FREED: + return "FREED"; + case OpenSSLSecureMemoryState::ZEROED: + return "ZEROED"; + case OpenSSLSecureMemoryState::ERROR: + return "ERROR"; + } + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State OpenSSLSecureMemoryDescription::bottom() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::bottom() const { return OpenSSLSecureMemoryState::BOT; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::top() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::top() const { return OpenSSLSecureMemoryState::TOP; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::start() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::start() const { return OpenSSLSecureMemoryState::ALLOCATED; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::uninit() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::uninit() const { return OpenSSLSecureMemoryState::BOT; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::error() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::error() const { return OpenSSLSecureMemoryState::ERROR; } diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp index a8bf83d155..0b2d4fa52e 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp @@ -37,7 +37,7 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { std::optional HA; CSTDFILEIOTypeStateDescription CSTDFILEIODesc{}; - std::optional TSProblem; + std::optional> TSProblem; enum IOSTATE { TOP = 42, UNINIT = 0, @@ -53,7 +53,8 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { void initialize(const llvm::Twine &IRFile) { HA.emplace(IRFile, EntryPoints); - TSProblem = createAnalysisProblem( + TSProblem = createAnalysisProblem< + IDETypeStateAnalysis>( *HA, &CSTDFILEIODesc, EntryPoints); } @@ -69,7 +70,8 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { */ void compareResults( const std::map> &GroundTruth, - IDESolver_P &Solver) { + IDESolver_P> + &Solver) { for (const auto &InstToGroundTruth : GroundTruth) { const auto *Inst = HA->getProjectIRDB().getInstruction(InstToGroundTruth.first); @@ -80,7 +82,7 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { for (auto Result : Solver.resultsAt(Inst, true)) { if (GT.find(getMetaDataID(Result.first)) != GT.end()) { Results.insert(std::pair( - getMetaDataID(Result.first), Result.second)); + getMetaDataID(Result.first), int(Result.second))); } } EXPECT_EQ(Results, GT) << "At " << llvmIRToShortString(Inst); diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLEVPKDFTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLEVPKDFTest.cpp index c02802f96e..bc74fadfda 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLEVPKDFTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLEVPKDFTest.cpp @@ -20,6 +20,7 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "TestConfig.h" #include "gtest/gtest.h" #include @@ -30,44 +31,51 @@ using namespace psr; /* ============== TEST FIXTURE ============== */ class IDETSAnalysisOpenSSLEVPKDFTest : public ::testing::Test { protected: - const std::string PathToLlFiles = - PhasarConfig::PhasarDirectory() + - "build/test/llvm_test_code/openssl/key_derivation/"; + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("openssl/key_derivation/"); const std::vector EntryPoints = {"main"}; std::optional HA; std::optional OpenSSLEVPKeyDerivationDesc; OpenSSLEVPKDFDescription OpenSSLEVPKDFDesc{}; - std::optional TSProblem, TSKDFProblem; - unique_ptr> Llvmtssolver, KdfSolver; - - enum OpenSSLEVPKeyDerivationState { - TOP = 42, - UNINIT = 5, - CTX_ATTACHED = 1, - PARAM_INIT = 2, - DERIVED = 3, - ERROR = 4, - BOT = 0 - }; + std::optional> TSProblem; + std::optional> TSKDFProblem; + unique_ptr>> + Llvmtssolver; + unique_ptr>> + KdfSolver; + + // enum OpenSSLEVPKDFCTXState { + // TOP = 42, + // UNINIT = 5, + // CTX_ATTACHED = 1, + // PARAM_INIT = 2, + // DERIVED = 3, + // ERROR = 4, + // BOT = 0 + // }; IDETSAnalysisOpenSSLEVPKDFTest() = default; ~IDETSAnalysisOpenSSLEVPKDFTest() override = default; - void initialize(const std::string &IRFile) { - HA.emplace(IRFile, EntryPoints); + void initialize(const llvm::Twine &IRFile) { + HA.emplace(PathToLlFiles + IRFile, EntryPoints); - TSKDFProblem = createAnalysisProblem( - *HA, &OpenSSLEVPKDFDesc, EntryPoints); + TSKDFProblem = + createAnalysisProblem>( + *HA, &OpenSSLEVPKDFDesc, EntryPoints); - KdfSolver = make_unique>( + KdfSolver = make_unique< + IDESolver>>( *TSKDFProblem, &HA->getICFG()); OpenSSLEVPKeyDerivationDesc.emplace(*KdfSolver); - TSProblem = createAnalysisProblem( + TSProblem = createAnalysisProblem< + IDETypeStateAnalysis>( *HA, &*OpenSSLEVPKeyDerivationDesc, EntryPoints); - Llvmtssolver = make_unique>( + Llvmtssolver = make_unique< + IDESolver>>( *TSProblem, &HA->getICFG()); KdfSolver->solve(); Llvmtssolver->solve(); @@ -85,16 +93,17 @@ class IDETSAnalysisOpenSSLEVPKDFTest : public ::testing::Test { * @param solver provides the results */ void compareResults( - const std::map> &GroundTruth) { + const std::map> + &GroundTruth) { for (const auto &InstToGroundTruth : GroundTruth) { const auto *Inst = HA->getProjectIRDB().getInstruction(InstToGroundTruth.first); auto GT = InstToGroundTruth.second; - std::map Results; + std::map Results; for (auto Result : Llvmtssolver->resultsAt(Inst, true)) { - if (Result.second != OpenSSLEVPKeyDerivationState::BOT && + if (Result.second != OpenSSLEVPKDFCTXState::BOT && GT.count(getMetaDataID(Result.first))) { - Results.insert(std::pair( + Results.insert(std::pair( getMetaDataID(Result.first), Result.second)); } } @@ -104,234 +113,234 @@ class IDETSAnalysisOpenSSLEVPKDFTest : public ::testing::Test { }; // Test Fixture TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation1) { - initialize({PathToLlFiles + "key-derivation1_c.ll"}); + initialize("key-derivation1_c.ll"); // llvmtssolver->printReport(); - std::map> Gt; - - Gt[48] = {{"46", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"20", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[50] = {{"46", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"20", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - - Gt[92] = {{"46", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"20", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"88", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[98] = {{"95", OpenSSLEVPKeyDerivationState::DERIVED}, - {"46", OpenSSLEVPKeyDerivationState::DERIVED}, - {"20", OpenSSLEVPKeyDerivationState::DERIVED}, - {"88", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[146] = {{"144", OpenSSLEVPKeyDerivationState::UNINIT}, - {"95", OpenSSLEVPKeyDerivationState::UNINIT}, - {"46", OpenSSLEVPKeyDerivationState::UNINIT}, - {"20", OpenSSLEVPKeyDerivationState::UNINIT}, - {"88", OpenSSLEVPKeyDerivationState::UNINIT}}; + std::map> Gt; + + Gt[48] = {{"46", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"20", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[50] = {{"46", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"20", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + + Gt[92] = {{"46", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"20", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"88", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[98] = {{"95", OpenSSLEVPKDFCTXState::DERIVED}, + {"46", OpenSSLEVPKDFCTXState::DERIVED}, + {"20", OpenSSLEVPKDFCTXState::DERIVED}, + {"88", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[146] = {{"144", OpenSSLEVPKDFCTXState::UNINIT}, + {"95", OpenSSLEVPKDFCTXState::UNINIT}, + {"46", OpenSSLEVPKDFCTXState::UNINIT}, + {"20", OpenSSLEVPKDFCTXState::UNINIT}, + {"88", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation2) { - initialize({PathToLlFiles + "key-derivation2_c.ll"}); + initialize("key-derivation2_c.ll"); - std::map> Gt; - // gt[40] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}}; // killed by + std::map> Gt; + // gt[40] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}}; // killed by // null-initialization - // gt[57] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}}; // killed by + // gt[57] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}}; // killed by // null-initialization - Gt[60] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"103", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[106] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[112] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"110", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[113] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[160] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}, - {"159", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[161] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}, - {"58", OpenSSLEVPKeyDerivationState::UNINIT}, - {"103", OpenSSLEVPKeyDerivationState::UNINIT}, - {"110", OpenSSLEVPKeyDerivationState::UNINIT}, - {"159", OpenSSLEVPKeyDerivationState::UNINIT}}; + Gt[60] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"103", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[106] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[112] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"110", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[113] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[160] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}, + {"159", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[161] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}, + {"58", OpenSSLEVPKDFCTXState::UNINIT}, + {"103", OpenSSLEVPKDFCTXState::UNINIT}, + {"110", OpenSSLEVPKDFCTXState::UNINIT}, + {"159", OpenSSLEVPKDFCTXState::UNINIT}}; // Fails due to merge conflicts: ID43 and ID162 have both value UNINIT on 22, // but it is implicit at ID43, so merging gives BOT - // gt[164] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}}; + // gt[164] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation3) { - initialize({PathToLlFiles + "key-derivation3_c.ll"}); - std::map> Gt; + initialize("key-derivation3_c.ll"); + std::map> Gt; - // gt[56] = {{"21", OpenSSLEVPKeyDerivationState::UNINIT}}; // + // gt[56] = {{"21", OpenSSLEVPKDFCTXState::UNINIT}}; // // null-initialization kills 21 - Gt[58] = {{"56", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[93] = {{"56", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"91", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[94] = {{"56", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"21", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"91", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[100] = {{"56", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"21", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"91", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"98", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[101] = {{"56", OpenSSLEVPKeyDerivationState::DERIVED}, - {"21", OpenSSLEVPKeyDerivationState::DERIVED}, - {"91", OpenSSLEVPKeyDerivationState::DERIVED}, - {"98", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[148] = {{"56", OpenSSLEVPKeyDerivationState::DERIVED}, - {"21", OpenSSLEVPKeyDerivationState::DERIVED}, - {"91", OpenSSLEVPKeyDerivationState::DERIVED}, - {"98", OpenSSLEVPKeyDerivationState::DERIVED}, - {"147", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[149] = {{"56", OpenSSLEVPKeyDerivationState::UNINIT}, - {"21", OpenSSLEVPKeyDerivationState::UNINIT}, - {"91", OpenSSLEVPKeyDerivationState::UNINIT}, - {"98", OpenSSLEVPKeyDerivationState::UNINIT}, - {"147", OpenSSLEVPKeyDerivationState::UNINIT}}; + Gt[58] = {{"56", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[93] = {{"56", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"91", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[94] = {{"56", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"21", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"91", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[100] = {{"56", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"21", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"91", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"98", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[101] = {{"56", OpenSSLEVPKDFCTXState::DERIVED}, + {"21", OpenSSLEVPKDFCTXState::DERIVED}, + {"91", OpenSSLEVPKDFCTXState::DERIVED}, + {"98", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[148] = {{"56", OpenSSLEVPKDFCTXState::DERIVED}, + {"21", OpenSSLEVPKDFCTXState::DERIVED}, + {"91", OpenSSLEVPKDFCTXState::DERIVED}, + {"98", OpenSSLEVPKDFCTXState::DERIVED}, + {"147", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[149] = {{"56", OpenSSLEVPKDFCTXState::UNINIT}, + {"21", OpenSSLEVPKDFCTXState::UNINIT}, + {"91", OpenSSLEVPKDFCTXState::UNINIT}, + {"98", OpenSSLEVPKDFCTXState::UNINIT}, + {"147", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation4) { - initialize({PathToLlFiles + "key-derivation4_c.ll"}); + initialize("key-derivation4_c.ll"); - std::map> Gt; + std::map> Gt; - // gt[57] = {{"21", OpenSSLEVPKeyDerivationState::UNINIT}}; // + // gt[57] = {{"21", OpenSSLEVPKDFCTXState::UNINIT}}; // // null-initialization kills 21 - Gt[59] = {{"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"57", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[104] = {{"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"57", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"102", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"21", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"57", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"102", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; + Gt[59] = {{"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"57", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[104] = {{"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"57", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"102", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"21", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"57", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"102", OpenSSLEVPKDFCTXState::PARAM_INIT}}; // TODO: Should FREE on PARAM_INIT result in UNINIT, or in ERROR? (currently // it is UNINIT) - Gt[152] = {{"21", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"57", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"102", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"151", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[153] = {{"21", OpenSSLEVPKeyDerivationState::UNINIT}, - {"57", OpenSSLEVPKeyDerivationState::UNINIT}, - {"102", OpenSSLEVPKeyDerivationState::UNINIT}, - {"151", OpenSSLEVPKeyDerivationState::UNINIT}}; + Gt[152] = {{"21", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"57", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"102", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"151", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[153] = {{"21", OpenSSLEVPKDFCTXState::UNINIT}, + {"57", OpenSSLEVPKDFCTXState::UNINIT}, + {"102", OpenSSLEVPKDFCTXState::UNINIT}, + {"151", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation5) { - initialize({PathToLlFiles + "key-derivation5_c.ll"}); + initialize("key-derivation5_c.ll"); - std::map> Gt; + std::map> Gt; - // gt[58] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}};// + // gt[58] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}};// // null-initialization kills 22 - Gt[60] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"103", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[106] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[112] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"110", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[113] = Gt[160] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}}; + Gt[60] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"103", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[106] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[112] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"110", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[113] = Gt[160] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}}; // should report an error at 160? (kdf_ctx is not freed) compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, DISABLED_KeyDerivation6) { - initialize({PathToLlFiles + "key-derivation6_c.ll"}); + initialize("key-derivation6_c.ll"); // llvmtssolver->printReport(); - std::map> Gt; - Gt[102] = {{"100", OpenSSLEVPKeyDerivationState::BOT}, - {"22", OpenSSLEVPKeyDerivationState::BOT}}; - Gt[103] = {{"100", OpenSSLEVPKeyDerivationState::ERROR}, - {"22", OpenSSLEVPKeyDerivationState::ERROR}}; - Gt[109] = Gt[110] = {{"100", OpenSSLEVPKeyDerivationState::ERROR}, - {"22", OpenSSLEVPKeyDerivationState::ERROR}, - {"107", OpenSSLEVPKeyDerivationState::ERROR}}; + std::map> Gt; + Gt[102] = {{"100", OpenSSLEVPKDFCTXState::BOT}, + {"22", OpenSSLEVPKDFCTXState::BOT}}; + Gt[103] = {{"100", OpenSSLEVPKDFCTXState::ERROR}, + {"22", OpenSSLEVPKDFCTXState::ERROR}}; + Gt[109] = Gt[110] = {{"100", OpenSSLEVPKDFCTXState::ERROR}, + {"22", OpenSSLEVPKDFCTXState::ERROR}, + {"107", OpenSSLEVPKDFCTXState::ERROR}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation7) { - initialize({PathToLlFiles + "key-derivation7_c.ll"}); + initialize("key-derivation7_c.ll"); // llvmtssolver->printReport(); - std::map> Gt; + std::map> Gt; - // gt[57] = {{"21", OpenSSLEVPKeyDerivationState::UNINIT}}; // + // gt[57] = {{"21", OpenSSLEVPKDFCTXState::UNINIT}}; // // null-initialization kills 21 - Gt[59] = {{"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"57", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[104] = {{"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"57", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"102", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"21", OpenSSLEVPKeyDerivationState::ERROR}, - {"57", OpenSSLEVPKeyDerivationState::ERROR}, - {"102", OpenSSLEVPKeyDerivationState::ERROR}}; - Gt[152] = Gt[153] = {{"21", OpenSSLEVPKeyDerivationState::ERROR}, - {"57", OpenSSLEVPKeyDerivationState::ERROR}, - {"102", OpenSSLEVPKeyDerivationState::ERROR}, - {"151", OpenSSLEVPKeyDerivationState::ERROR}}; + Gt[59] = {{"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"57", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[104] = {{"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"57", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"102", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"21", OpenSSLEVPKDFCTXState::ERROR}, + {"57", OpenSSLEVPKDFCTXState::ERROR}, + {"102", OpenSSLEVPKDFCTXState::ERROR}}; + Gt[152] = Gt[153] = {{"21", OpenSSLEVPKDFCTXState::ERROR}, + {"57", OpenSSLEVPKDFCTXState::ERROR}, + {"102", OpenSSLEVPKDFCTXState::ERROR}, + {"151", OpenSSLEVPKDFCTXState::ERROR}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation8) { - initialize({PathToLlFiles + "key-derivation8_c.ll"}); + initialize("key-derivation8_c.ll"); // llvmtssolver->printReport(); - std::map> Gt; + std::map> Gt; - // gt[58] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}}; // + // gt[58] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}}; // // null-initialization kills 22 - Gt[60] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"103", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[107] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[112] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"110", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[113] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[160] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}, - {"159", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[161] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}, - {"58", OpenSSLEVPKeyDerivationState::UNINIT}, - {"103", OpenSSLEVPKeyDerivationState::UNINIT}, - {"110", OpenSSLEVPKeyDerivationState::UNINIT}, - {"159", OpenSSLEVPKeyDerivationState::UNINIT}}; + Gt[60] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"103", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[107] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[112] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"110", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[113] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[160] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}, + {"159", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[161] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}, + {"58", OpenSSLEVPKDFCTXState::UNINIT}, + {"103", OpenSSLEVPKDFCTXState::UNINIT}, + {"110", OpenSSLEVPKDFCTXState::UNINIT}, + {"159", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureHeapTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureHeapTest.cpp index 4546dc44c8..a4cc5eb869 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureHeapTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureHeapTest.cpp @@ -22,6 +22,7 @@ #include "llvm/ADT/Twine.h" +#include "TestConfig.h" #include "gtest/gtest.h" #include @@ -33,17 +34,18 @@ using namespace psr; /* ============== TEST FIXTURE ============== */ class IDETSAnalysisOpenSSLSecureHeapTest : public ::testing::Test { protected: - const std::string PathToLlFiles = - PhasarConfig::PhasarDirectory() + - "build/test/llvm_test_code/openssl/secure_heap/"; + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("openssl/secure_heap/"); const std::vector EntryPoints = {"main"}; std::optional HA; std::optional Desc; - std::optional TSProblem; + std::optional> TSProblem; std::optional SecureHeapPropagationProblem; - unique_ptr> Llvmtssolver; + unique_ptr< + IDESolver>> + Llvmtssolver; unique_ptr> SecureHeapPropagationResults; enum OpenSSLSecureHeapState { @@ -58,7 +60,7 @@ class IDETSAnalysisOpenSSLSecureHeapTest : public ::testing::Test { IDETSAnalysisOpenSSLSecureHeapTest() = default; ~IDETSAnalysisOpenSSLSecureHeapTest() override = default; - void initialize(const std::string &IRFile) { + void initialize(const llvm::Twine &IRFile) { HA.emplace(IRFile, EntryPoints); SecureHeapPropagationProblem = @@ -68,9 +70,11 @@ class IDETSAnalysisOpenSSLSecureHeapTest : public ::testing::Test { *SecureHeapPropagationProblem, &HA->getICFG()); Desc.emplace(*SecureHeapPropagationResults); - TSProblem = - createAnalysisProblem(*HA, &*Desc, EntryPoints); - Llvmtssolver = make_unique>( + TSProblem = createAnalysisProblem< + IDETypeStateAnalysis>(*HA, &*Desc, + EntryPoints); + Llvmtssolver = make_unique< + IDESolver>>( *TSProblem, &HA->getICFG()); SecureHeapPropagationResults->solve(); @@ -97,7 +101,7 @@ class IDETSAnalysisOpenSSLSecureHeapTest : public ::testing::Test { for (auto Result : Llvmtssolver->resultsAt(Inst, true)) { if (GT.find(getMetaDataID(Result.first)) != GT.end()) { Results.insert(std::pair( - getMetaDataID(Result.first), Result.second)); + getMetaDataID(Result.first), int(Result.second))); } // else { // std::cout << "Unused result at " << InstToGroundTruth.first << ": " // << llvmIRToShortString(Result.first) << " => " diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp index 3006943b71..558c8007c4 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp @@ -19,6 +19,7 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "TestConfig.h" #include "gtest/gtest.h" #include @@ -30,15 +31,15 @@ using namespace psr; /* ============== TEST FIXTURE ============== */ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { protected: - const std::string PathToLlFiles = - PhasarConfig::PhasarDirectory() + - "build/test/llvm_test_code/openssl/secure_memory/"; + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("openssl/secure_memory/"); const std::vector EntryPoints = {"main"}; std::optional HA; OpenSSLSecureMemoryDescription Desc{}; - std::optional TSProblem; - unique_ptr> Llvmtssolver; + std::optional> TSProblem; + unique_ptr>> + Llvmtssolver; enum OpenSSLSecureMemoryState { TOP = 42, @@ -51,12 +52,14 @@ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { IDETSAnalysisOpenSSLSecureMemoryTest() = default; ~IDETSAnalysisOpenSSLSecureMemoryTest() override = default; - void initialize(const std::string &IRFile) { + void initialize(const llvm::Twine &&IRFile) { HA.emplace(IRFile, EntryPoints); - TSProblem = - createAnalysisProblem(*HA, &Desc, EntryPoints); - Llvmtssolver = make_unique>( + TSProblem = createAnalysisProblem< + IDETypeStateAnalysis>(*HA, &Desc, + EntryPoints); + Llvmtssolver = make_unique< + IDESolver_P>>( *TSProblem, &HA->getICFG()); Llvmtssolver->solve(); @@ -82,7 +85,7 @@ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { for (auto Result : Llvmtssolver->resultsAt(Inst, true)) { if (GT.find(getMetaDataID(Result.first)) != GT.end()) { Results.insert(std::pair( - getMetaDataID(Result.first), Result.second)); + getMetaDataID(Result.first), int(Result.second))); } // else { // std::cout << "Unused result at " << InstToGroundTruth.first << ": " // << llvmIRToShortString(Result.first) << " => "