From 1a96918e614043196f8049f506d487203c735b83 Mon Sep 17 00:00:00 2001 From: Benedict Smit Date: Tue, 24 Sep 2024 12:12:03 +0200 Subject: [PATCH] Added a uninit variables analysis with indexes The added analysis exists as a seperate tool and does the same as the ifds-uninit analysis in phaser-cli but also remembers which indices are initialized. --- .../IFDSUninitializedVariablesIndexed.h | 102 +++++ include/phasar/Utils/IndexWrapper.h | 188 ++++++++ .../IFDSUninitializedVariablesIndexed.cpp | 412 ++++++++++++++++++ tools/CMakeLists.txt | 1 + tools/indexed-uninit-analysis/CMakeLists.txt | 31 ++ ...SUninitializedVaraiblesIndexedAnalysis.cpp | 45 ++ 6 files changed, 779 insertions(+) create mode 100644 include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.h create mode 100644 include/phasar/Utils/IndexWrapper.h create mode 100644 lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.cpp create mode 100644 tools/indexed-uninit-analysis/CMakeLists.txt create mode 100644 tools/indexed-uninit-analysis/IFDSUninitializedVaraiblesIndexedAnalysis.cpp diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.h new file mode 100644 index 000000000..4a13c7ed3 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.h @@ -0,0 +1,102 @@ +/****************************************************************************** + * Copyright (c) 2017 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Philipp Schubert and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSUninitializedVariablesStructs_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSUninitializedVariablesStructs_H + +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/Utils/IndexWrapper.h" + +#include + +#include + +#include + +#include + +#include +#include +#include +#include + +namespace psr { + +struct LLVMAnalysisDomainIndexed : public AnalysisDomain { + public: + using d_t = IndexWrapper; + using n_t = const llvm::Instruction *; + using f_t = const llvm::Function *; + using t_t = const llvm::StructType *; + using v_t = const llvm::Value *; + using c_t = LLVMBasedCFG; + using i_t = LLVMBasedICFG; + using db_t = LLVMProjectIRDB; +}; + +using LLVMIFDSAnalysisDomainIndexed = + WithBinaryValueDomain; + +class IFDSUninitializedVariablesIndexed + : public IFDSTabulationProblem { + struct UninitResult { + UninitResult() = default; + unsigned int Line = 0; + std::string FuncName; + std::string FilePath; + std::string SrcCode; + std::vector VarNames; + std::map> + IRTrace; + [[nodiscard]] bool empty() const; + void print(llvm::raw_ostream &OS); + }; + +public: + IFDSUninitializedVariablesIndexed(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); + + ~IFDSUninitializedVariablesIndexed() override = default; + + FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override; + + FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override; + + FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, + n_t ExitStmt, n_t RetSite) override; + + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; + + FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, + f_t DestFun) override; + + InitialSeeds initialSeeds() override; + + [[nodiscard]] d_t createZeroValue() const; + + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; + + void emitTextReport(const SolverResults &Results, + llvm::raw_ostream &OS = llvm::outs()) override; + + [[nodiscard]] const std::map> &getAllUndefUses() const; + + std::vector aggregateResults(); + +private: + std::map> UndefValueUses; +}; + +} // namespace psr + +#endif diff --git a/include/phasar/Utils/IndexWrapper.h b/include/phasar/Utils/IndexWrapper.h new file mode 100644 index 000000000..2c65bb93d --- /dev/null +++ b/include/phasar/Utils/IndexWrapper.h @@ -0,0 +1,188 @@ +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IndexWrapper_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IndexWrapper_H + +#include "phasar/Utils/Printer.h" +#include +#include +#include +#include + +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" + + +#include +#include +#include + +namespace psr { +/** + * @brief A wrapper around llvm::Value objects to include an indexing into the + * object + * + */ +template struct IndexWrapper { + + T const *Value; + std::vector Indices; + +public: + IndexWrapper() : Value(nullptr), Indices({}){}; + IndexWrapper(const IndexWrapper & Other) : Value(Other.Value), Indices(Other.Indices){}; + IndexWrapper(IndexWrapper && Other) noexcept : Value(Other.Value), Indices(std::move(Other.Indices)){}; + IndexWrapper &operator=(const IndexWrapper & Other) { + if (this == Other) { + return *this; + } + this->Value = Other.Value; + this->Indices = Other.Indices; + return *this; + }; + IndexWrapper &operator=(IndexWrapper && Other) noexcept { + if (this == &Other) { + return *this; // Handle self-assignment + } + // Move members from Other to this + Value = Other.Value; // Move the pointer + Indices = std::move(Other.Indices); // Move the vector + + Other.Value = nullptr; // Nullify the moved-from object's Value + return *this; + }; + IndexWrapper(T const *Value, std::vector *Indices) + : Value(Value), Indices(*Indices){}; + IndexWrapper(T const *Value, std::vector Indices) + : Value(Value), Indices(std::move(Indices)){}; + IndexWrapper(T const *Value) : Value(Value), Indices({}){}; + ~IndexWrapper() {}; + T const *getValue() const { return Value; }; + + [[nodiscard]] std::vector getIndices() const { + return Indices; + }; + + std::set> + excluded(const llvm::ArrayRef &ExcludedIndex) const { + if (this->indexContains(ExcludedIndex)) { + std::set> Result = {}; + std::vector PrefixVector = {}; + llvm::Type *Ty = this->Value->getType(); + for (unsigned int I : this->Indices) { + if (auto *StructType = llvm::dyn_cast(Ty)) { + for (unsigned int J = 0; J < StructType->getNumElements(); ++I) { + if (I != J) { + PrefixVector.push_back(I); + auto Index = std::vector(PrefixVector); + PrefixVector.pop_back(); + Result.insert(IndexWrapper(this->Value, Index)); + } + } + Ty = StructType->getTypeAtIndex(I); + } + if (auto *ArrayType = llvm::dyn_cast(Ty)) { + for (unsigned int J = 0; J < ArrayType->getNumElements(); ++I) { + if (I != J) { + PrefixVector.push_back(I); + auto Index = std::vector(PrefixVector); + PrefixVector.pop_back(); + Result.insert(IndexWrapper(this->Value, Index)); + } + } + Ty = ArrayType->getElementType(); + } + } + return Result; + } + return {*this}; + }; + + bool contains(const IndexWrapper &Other) const { + return this->Value == Other.Value && this->indexContains(Other); + }; + + [[nodiscard]] bool + contains(const llvm::ExtractValueInst &ExtractValue) const { + return this->Value == ExtractValue.getAggregateOperand() && + this->indexContains(ExtractValue.getIndices()); + }; + + [[nodiscard]] bool + contains(const llvm::GetElementPtrInst &GetElementPtr) const { + if (this->Value == GetElementPtr.getPointerOperand() && + GetElementPtr.hasIndices() && + this->Indices.size() <= GetElementPtr.getNumIndices()) { + for (size_t I = 0; I < this->Indices.size(); ++I) { + llvm::Value *OtherI = GetElementPtr.getOperand(I + 1); + if (auto *ConstantIndex = llvm::dyn_cast(OtherI)) { + if ((this->Indices)[I] != ConstantIndex->getZExtValue()) { + return false; + } + } else { + return false; + } + } + return true; + } + return false; + } + + bool indexContains(const IndexWrapper &Other) const { + return indexContains(Other.Indices); + }; + + [[nodiscard]] bool + indexContains(const llvm::ArrayRef &OtherIndices) const { + if (this->Indices.size() <= OtherIndices.size()) { + for (size_t I = 0; I < this->Indices.size(); ++I) { + if ((this->Indices)[I] != OtherIndices[I]) { + return false; + } + } + return true; + } + return false; + }; + + bool operator<(const IndexWrapper &Other) const { + if (this->Value < Other.Value) { + return true; + } + for (size_t I = 0; I < this->Indices.size(); ++I) { + if ((this->Indices)[I] < (Other.Indices)[I]) { + return true; + } + if ((this->Indices)[I] > (Other.Indices)[I]) { + return false; + } + } + return false; + }; + + bool operator==(const IndexWrapper &Other) const { + return (this->Value == Other.Value) && (this->Indices == Other.Indices); + }; + std::string str() const { + return "NOT YET IMPLEMENTED"; + } + +}; + + +} // namespace psr + +// Specialize std::hash for IndexWrapper +namespace std { + template + struct hash> { + std::size_t operator()(const psr::IndexWrapper &IW) const { + std::size_t HashValue = std::hash()(IW.Value); + + for (const auto &Index : IW.Indices) { + HashValue ^= std::hash()(Index) + 0x9e3779b9 + (HashValue << 6) + (HashValue >> 2); + } + + return HashValue; + } + }; +} // namespace std + +#endif \ No newline at end of file diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.cpp new file mode 100644 index 000000000..a60f94484 --- /dev/null +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.cpp @@ -0,0 +1,412 @@ +/****************************************************************************** + * Copyright (c) 2017 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Philipp Schubert and others + *****************************************************************************/ + +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.h" + +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/IndexWrapper.h" +#include "phasar/Utils/Logger.h" +#include "phasar/Utils/Printer.h" + +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +#include + +namespace psr { + +IFDSUninitializedVariablesIndexed::IFDSUninitializedVariablesIndexed( + const LLVMProjectIRDB *IRDB, std::vector EntryPoints) + : IFDSTabulationProblem(IRDB, std::move(EntryPoints), createZeroValue()) {} + +IFDSUninitializedVariablesIndexed::FlowFunctionPtrType +IFDSUninitializedVariablesIndexed::getNormalFlowFunction(n_t Curr, + n_t /*Succ*/) { + auto Zero = getZeroValue(); + /** + * an ExtractValueInst will become Source if some Source Fact contains the + * extracted Value + */ + if (const auto *ExtractValue = llvm::dyn_cast(Curr)) { + return lambdaFlow([ExtractValue](const d_t &Source) -> std::set { + if (Source.contains(*ExtractValue)) { + return {Source, IndexWrapper(ExtractValue)}; + } + return {Source}; + }); + } + if (const auto *GetElementPtr = + llvm::dyn_cast(Curr)) { + return lambdaFlow([GetElementPtr](const d_t &Source) -> std::set { + if (Source.contains(*GetElementPtr)) { + return {Source, IndexWrapper(GetElementPtr)}; + } + return {Source}; + }); + } + /** + * We have to distinghuishe the cases that something gets inserted in some + * undefined/Source Value, or som undegined/Source Value gets inserted into + * something If both are undefined the whole object gets undefined by the + * IndexWrapper(InsertValue) fact It is important to notice, that this dosn't + * prevent additional indexed Facts to be generated because the Sources "don't + * know of each other" If something defined gets inserted into something + * undefined/source we generate a Source fact for all indices but the one + * inserted If something undefined/source gets inserted into something defined + * we only generate the Source fact for this index + */ + if (const auto *InsertValue = llvm::dyn_cast(Curr)) { + return lambdaFlow([InsertValue, Zero](const d_t &Source) -> std::set { + const llvm::Value *AggregatOperand = InsertValue->getAggregateOperand(); + const auto *InsertOperand = InsertValue->getInsertedValueOperand(); + std::set ReturnSet = {Source}; + auto Indices = InsertValue->getIndices(); + + if ((Source.getValue() == Zero.getValue() && + llvm::isa(AggregatOperand)) || + Source.getValue() == AggregatOperand) { + if ((Source.getValue() == Zero.getValue() && + llvm::isa(InsertOperand)) || + Source.getValue() == InsertOperand) { + // IsertOperand and AggregateOperand are both undefined so the whole + // InsertValue becomes source + ReturnSet.insert(IndexWrapper(InsertValue)); + } else { + // only AggregateOperand is undefined so we have to exclude the + // inserted value + auto Excluded = + IndexWrapper(InsertValue).excluded(Indices); + ReturnSet.insert(Excluded.begin(), Excluded.end()); + } + } else if ((Source.getValue() == Zero.getValue() && + llvm::isa(InsertOperand)) || + Source.getValue() == InsertOperand) { + // only the InsertOperand is undefiend so only this becomes source + ReturnSet.insert(IndexWrapper(InsertValue, Indices.vec())); + }; + + return ReturnSet; + }); + } + // check the store instructions and kill initialized variables + if (const auto *Store = llvm::dyn_cast(Curr)) { + return lambdaFlow([Store, Zero](const d_t &Source) -> std::set { + if (Source.getValue() == Store->getValueOperand() || + (Source.getValue() == Zero.getValue() && + llvm::isa(Store->getValueOperand()))) { + d_t PointerOperand = IndexWrapper(Store->getPointerOperand()); + return {Source, PointerOperand}; + } + if (Source.getValue() == Store->getPointerOperand() && + !llvm::isa( + Store->getValueOperand())) { // storing an initialized value + // kills the variable as it is + // now initialized too + return {}; + } + // pass all other facts as identity + return {Source}; + }); + } + if (const auto *Alloc = llvm::dyn_cast(Curr)) { + return lambdaFlow([Alloc, this](const d_t &Source) -> std::set { + if (isZeroValue(Source)) { + if (Alloc->getAllocatedType()->isIntegerTy() || + Alloc->getAllocatedType()->isFloatingPointTy() || + Alloc->getAllocatedType()->isPointerTy() || + Alloc->getAllocatedType()->isArrayTy() || + Alloc->getAllocatedType()->isStructTy()) { + // generate the alloca + return {Source, IndexWrapper(Alloc)}; + } + } + // otherwise propagate all facts + return {Source}; + }); + } + const llvm::Instruction *Inst = Curr; + return lambdaFlow([Inst, this](const d_t &Source) -> std::set { + for (const auto &Operand : Inst->operands()) { + if (Operand == Source.getValue() || + llvm::isa(Operand)) { + if (!llvm::isa(Inst) && + !llvm::isa(Inst) && + !llvm::isa(Inst)) { + UndefValueUses[Inst].insert(IndexWrapper(Operand)); + } + return {Source, IndexWrapper(Inst)}; + } + } + return {Source}; + }); +} + +IFDSUninitializedVariablesIndexed::FlowFunctionPtrType +IFDSUninitializedVariablesIndexed::getCallFlowFunction(n_t CallSite, + f_t DestFun) { + if (llvm::isa(CallSite) || + llvm::isa(CallSite)) { + const auto *CS = llvm::cast(CallSite); + const auto *Zerovalue = getZeroValue().getValue(); + std::vector Actuals; + std::vector Formals; + // set up the actual parameters + for (unsigned Idx = 0; Idx < CS->arg_size(); ++Idx) { + Actuals.push_back(CS->getArgOperand(Idx)); + } + // set up the formal parameters + /*for (unsigned idx = 0; idx < destFun->arg_size(); ++idx) { + formals.push_back(getNthFunctionArgument(destFun, idx)); + }*/ + for (const auto &Arg : DestFun->args()) { + Formals.push_back(&Arg); + } + return lambdaFlow( + [Zerovalue, Actuals, Formals](const d_t &Source) -> std::set { + // perform parameter passing + if (Source.getValue() != Zerovalue) { + std::set Res; + // do the mapping from actual to formal parameters + // caution: the loop iterates from 0 to formals.size(), + // rather than actuals.size() as we may have more actual + // than formal arguments in case of C-style varargs + for (unsigned Idx = 0; Idx < Formals.size(); ++Idx) { + if (Source.getValue() == Actuals[Idx]) { + Res.insert(IndexWrapper(Formals[Idx])); + } + } + return Res; + } + return {Source}; + }); + } + return identityFlow(); +} + +IFDSUninitializedVariablesIndexed::FlowFunctionPtrType +IFDSUninitializedVariablesIndexed::getRetFlowFunction(n_t CallSite, + f_t /*CalleeFun*/, + n_t ExitStmt, + n_t /*RetSite*/) { + if (llvm::isa(CallSite) || + llvm::isa(CallSite)) { + const auto *CS = llvm::cast(CallSite); + return lambdaFlow([CS, ExitStmt](const d_t &Source) -> std::set { + std::set Ret; + if (ExitStmt->getNumOperands() > 0 && + ExitStmt->getOperand(0) == Source.getValue()) { + Ret.insert(IndexWrapper(CS)); + } + //---------------------------------------------------------------------- + // Handle pointer/reference parameters + //---------------------------------------------------------------------- + if (CS->getCalledFunction()) { + unsigned I = 0; + for (const auto &Arg : CS->getCalledFunction()->args()) { + // auto arg = getNthFunctionArgument(call.getCalledFunction(), i); + if (&Arg == Source.getValue() && Arg.getType()->isPointerTy()) { + Ret.insert(IndexWrapper(CS->getArgOperand(I))); + } + I++; + } + } + // kill all other facts + return Ret; + }); + } + // kill everything else + return killAllFlows(); +} + +IFDSUninitializedVariablesIndexed::FlowFunctionPtrType +IFDSUninitializedVariablesIndexed::getCallToRetFlowFunction( + n_t CallSite, n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { + //---------------------------------------------------------------------- + // Handle pointer/reference parameters + //---------------------------------------------------------------------- + if (const auto *CS = llvm::dyn_cast(CallSite)) { + return lambdaFlow([CS](const d_t &Source) -> std::set { + if (Source.getValue()->getType()->isPointerTy()) { + for (const auto &Arg : CS->args()) { + if (Arg.get() == Source.getValue()) { + // do not propagate pointer arguments, since the function may + // initialize them (would be much more precise with + // field-sensitivity) + return {}; + } + } + } + return {Source}; + }); + } + return identityFlow(); +} + +IFDSUninitializedVariablesIndexed::FlowFunctionPtrType +IFDSUninitializedVariablesIndexed::getSummaryFlowFunction(n_t /*CallSite*/, + f_t /*DestFun*/) { + return nullptr; +} + +InitialSeeds +IFDSUninitializedVariablesIndexed::initialSeeds() { + PHASAR_LOG_LEVEL(DEBUG, "IFDSUninitializedVariablesStructs::initialSeeds()"); + return createDefaultSeeds(); +} + +IFDSUninitializedVariablesIndexed::d_t +IFDSUninitializedVariablesIndexed::createZeroValue() const { + PHASAR_LOG_LEVEL(DEBUG, + "IFDSUninitializedVariablesStructs::createZeroValue()"); + // create a special value to represent the zero value! + return {LLVMZeroValue::getInstance()}; +} + +bool IFDSUninitializedVariablesIndexed::isZeroValue( + IFDSUninitializedVariablesIndexed::d_t Fact) const noexcept { + return LLVMZeroValue::isLLVMZeroValue(Fact.getValue()); +} + +void IFDSUninitializedVariablesIndexed::emitTextReport( + const SolverResults + & /*Result*/, + llvm::raw_ostream &OS) { + OS << "====================== IFDS-Uninitialized-Analysis Report " + "======================\n"; + if (UndefValueUses.empty()) { + OS << "No uses of uninitialized variables found by the analysis!\n"; + } else { + if (!IRDB->debugInfoAvailable()) { + // Emit only IR code, function name and module info + OS << "\nWARNING: No Debug Info available - emiting results without " + "source code mapping!\n"; + OS << "\nTotal uses of uninitialized IR Value's: " + << UndefValueUses.size() << '\n'; + size_t Count = 0; + for (const auto &User : UndefValueUses) { + OS << "\n--------------------------------- " << ++Count + << ". Use ---------------------------------\n\n"; + OS << "At IR statement: " << NToString(User.first); + OS << "\n in function: " << getFunctionNameFromIR(User.first); + OS << "\n in module : " << getModuleIDFromIR(User.first) << "\n\n"; + for (const auto &UndefV : User.second) { + OS << " Uninit Value: " << DToString(UndefV.getValue()); + OS << " Index: " + << std::string(UndefV.getIndices().begin(), + UndefV.getIndices().end()); + OS << '\n'; + } + } + OS << '\n'; + } else { + auto UninitResults = aggregateResults(); + OS << "\nTotal uses of uninitialized variables: " << UninitResults.size() + << '\n'; + size_t Count = 0; + for (auto Res : UninitResults) { + OS << "\n--------------------------------- " << ++Count + << ". Use ---------------------------------\n\n"; + Res.print(OS); + } + } + } +} + +std::vector +IFDSUninitializedVariablesIndexed::aggregateResults() { + std::vector Results; + unsigned int LineNr = 0; + + unsigned int CurrLineNr = 0; + UninitResult UR; + for (const auto &User : UndefValueUses) { + // new line nr idicates a new uninit use on source code level + LineNr = getLineFromIR(User.first); + if (CurrLineNr != LineNr) { + CurrLineNr = LineNr; + UninitResult NewUR; + NewUR.Line = LineNr; + NewUR.FuncName = getFunctionNameFromIR(User.first); + NewUR.FilePath = getFilePathFromIR(User.first); + NewUR.SrcCode = getSrcCodeFromIR(User.first); + if (!UR.empty()) { + Results.push_back(UR); + } + UR = NewUR; + } + // add current IR trace + UR.IRTrace[User.first] = User.second; + // add (possibly) new variable names + for (const auto &UndefV : User.second) { + auto VarName = getVarNameFromIR(UndefV.getValue()); + if (!VarName.empty()) { + UR.VarNames.push_back(VarName); + } + } + } + if (!UR.empty()) { + Results.push_back(UR); + } + return Results; +} + +bool IFDSUninitializedVariablesIndexed::UninitResult::empty() const { + return Line == 0; +} + +void IFDSUninitializedVariablesIndexed::UninitResult::print( + llvm::raw_ostream &OS) { + OS << "Variable(s): "; + if (!VarNames.empty()) { + for (size_t I = 0; I < VarNames.size(); ++I) { + OS << VarNames[I]; + if (I < VarNames.size() - 1) { + OS << ", "; + } + } + OS << '\n'; + } + OS << "Line : " << Line << '\n'; + OS << "Source code: " << SrcCode << '\n'; + OS << "Function : " << FuncName << '\n'; + OS << "File : " << FilePath << '\n'; + OS << "\nCorresponding IR Statements and uninit. Values\n"; + if (!IRTrace.empty()) { + for (const auto &Trace : IRTrace) { + OS << "At IR Statement: " << llvmIRToString(Trace.first) << '\n'; + for (const auto &IRVal : Trace.second) { + OS << " Uninit Value: " << llvmIRToString(IRVal.getValue()) << '\n'; + } + // os << '\n'; + } + } +} + +const std::map> & +IFDSUninitializedVariablesIndexed::getAllUndefUses() const { + return UndefValueUses; +} + +} // namespace psr \ No newline at end of file diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 64a97d80a..d8e83a033 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(example-tool) add_subdirectory(phasar-cli) +add_subdirectory(indexed-uninit-analysis) \ No newline at end of file diff --git a/tools/indexed-uninit-analysis/CMakeLists.txt b/tools/indexed-uninit-analysis/CMakeLists.txt new file mode 100644 index 000000000..3bcb9257c --- /dev/null +++ b/tools/indexed-uninit-analysis/CMakeLists.txt @@ -0,0 +1,31 @@ +set(LLVM_LINK_COMPONENTS + Analysis + BitWriter + Core + Demangle + IRReader + Linker + Passes + Support +) + +# Build a stand-alone executable +if(PHASAR_IN_TREE) + add_phasar_executable(indexed-uninit + IFDSUninitializedVaraiblesIndexedAnalysis.cpp + ) +else() + add_executable(indexed-uninit + IFDSUninitializedVaraiblesIndexedAnalysis.cpp + ) +endif() + +target_link_libraries(indexed-uninit + PRIVATE + phasar + ${PHASAR_STD_FILESYSTEM} +) + +if (NOT PHASAR_IN_TREE) + install(TARGETS indexed-uninit) +endif() diff --git a/tools/indexed-uninit-analysis/IFDSUninitializedVaraiblesIndexedAnalysis.cpp b/tools/indexed-uninit-analysis/IFDSUninitializedVaraiblesIndexedAnalysis.cpp new file mode 100644 index 000000000..979f28918 --- /dev/null +++ b/tools/indexed-uninit-analysis/IFDSUninitializedVaraiblesIndexedAnalysis.cpp @@ -0,0 +1,45 @@ + +#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesIndexed.h" +#include "phasar/PhasarLLVM/HelperAnalyses.h" +#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" +#include +#include + +using namespace psr; + + +int main(int Argc, const char **Argv) { + using namespace std::string_literals; + if (Argc < 2 || !std::filesystem::exists(Argv[1]) || + std::filesystem::is_directory(Argv[1])) { + llvm::errs() << "ifds uninitialized Variables Test\n" + "A changed Version of the one in phasar-cli to include aggregate types\n\n" + "Usage: myphasartool \n"; + return 1; + } + + llvm::errs() << "Starting uninitialized Variables Test\n"; + + std::vector EntryPoints = {"main"s}; + + HelperAnalyses HA(Argv[1], EntryPoints); + if (!HA.getProjectIRDB().isValid()) { + return 1; + } + llvm::errs() << "HelperAnalyses initialized and valid \n"; + + if (const auto *F = HA.getProjectIRDB().getFunctionDefinition("main")) { + auto L = createAnalysisProblem(HA, EntryPoints); + llvm::errs() << "Problem initialized \n"; + IFDSSolver S(L, &HA.getICFG()); + llvm::errs() << "Solver initialized \n"; + auto IFDSResults = S.solve(); + llvm::errs() << "Problem Sovled \n"; + L.emitTextReport(IFDSResults, llvm::errs()); + } else { + llvm::errs() << "error: file does not contain a 'main' function!\n"; + } + return 0; +} \ No newline at end of file