Skip to content

Commit

Permalink
Added a uninit variables analysis with indexes
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
StamesJames committed Sep 24, 2024
1 parent 6e0f6f6 commit 1a96918
Show file tree
Hide file tree
Showing 6 changed files with 779 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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 <llvm/ADT/ArrayRef.h>

#include <llvm/IR/DerivedTypes.h>

#include <llvm/IR/Value.h>

#include <llvm-14/llvm/IR/Instructions.h>

#include <map>
#include <set>
#include <string>
#include <vector>

namespace psr {

struct LLVMAnalysisDomainIndexed : public AnalysisDomain {
public:
using d_t = IndexWrapper<llvm::Value>;
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<LLVMAnalysisDomainIndexed>;

class IFDSUninitializedVariablesIndexed
: public IFDSTabulationProblem<LLVMIFDSAnalysisDomainIndexed> {
struct UninitResult {
UninitResult() = default;
unsigned int Line = 0;
std::string FuncName;
std::string FilePath;
std::string SrcCode;
std::vector<std::string> VarNames;
std::map<IFDSUninitializedVariablesIndexed::n_t,
std::set<IFDSUninitializedVariablesIndexed::d_t>>
IRTrace;
[[nodiscard]] bool empty() const;
void print(llvm::raw_ostream &OS);
};

public:
IFDSUninitializedVariablesIndexed(const LLVMProjectIRDB *IRDB,
std::vector<std::string> 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<f_t> Callees) override;

FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite,
f_t DestFun) override;

InitialSeeds<n_t, d_t, l_t> initialSeeds() override;

[[nodiscard]] d_t createZeroValue() const;

[[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override;

void emitTextReport(const SolverResults<n_t, d_t, l_t> &Results,
llvm::raw_ostream &OS = llvm::outs()) override;

[[nodiscard]] const std::map<n_t, std::set<d_t>> &getAllUndefUses() const;

std::vector<UninitResult> aggregateResults();

private:
std::map<n_t, std::set<d_t>> UndefValueUses;
};

} // namespace psr

#endif
188 changes: 188 additions & 0 deletions include/phasar/Utils/IndexWrapper.h
Original file line number Diff line number Diff line change
@@ -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 <set>
#include <string>
#include <utility>
#include <vector>

#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h"


#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Value.h>
#include <llvm-14/llvm/IR/Instructions.h>

namespace psr {
/**
* @brief A wrapper around llvm::Value objects to include an indexing into the
* object
*
*/
template <typename T> struct IndexWrapper {

T const *Value;
std::vector<unsigned int> 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<unsigned int> *Indices)
: Value(Value), Indices(*Indices){};
IndexWrapper(T const *Value, std::vector<unsigned int> Indices)
: Value(Value), Indices(std::move(Indices)){};
IndexWrapper(T const *Value) : Value(Value), Indices({}){};
~IndexWrapper() {};
T const *getValue() const { return Value; };

[[nodiscard]] std::vector<unsigned int> getIndices() const {
return Indices;
};

std::set<IndexWrapper<T>>
excluded(const llvm::ArrayRef<unsigned int> &ExcludedIndex) const {
if (this->indexContains(ExcludedIndex)) {
std::set<IndexWrapper<T>> Result = {};
std::vector<unsigned int> PrefixVector = {};
llvm::Type *Ty = this->Value->getType();
for (unsigned int I : this->Indices) {
if (auto *StructType = llvm::dyn_cast<llvm::StructType>(Ty)) {
for (unsigned int J = 0; J < StructType->getNumElements(); ++I) {
if (I != J) {
PrefixVector.push_back(I);
auto Index = std::vector<unsigned int>(PrefixVector);
PrefixVector.pop_back();
Result.insert(IndexWrapper<T>(this->Value, Index));
}
}
Ty = StructType->getTypeAtIndex(I);
}
if (auto *ArrayType = llvm::dyn_cast<llvm::ArrayType>(Ty)) {
for (unsigned int J = 0; J < ArrayType->getNumElements(); ++I) {
if (I != J) {
PrefixVector.push_back(I);
auto Index = std::vector<unsigned int>(PrefixVector);
PrefixVector.pop_back();
Result.insert(IndexWrapper<T>(this->Value, Index));
}
}
Ty = ArrayType->getElementType();
}
}
return Result;
}
return {*this};
};

bool contains(const IndexWrapper<T> &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<llvm::ConstantInt>(OtherI)) {
if ((this->Indices)[I] != ConstantIndex->getZExtValue()) {
return false;
}
} else {
return false;
}
}
return true;
}
return false;
}

bool indexContains(const IndexWrapper<T> &Other) const {
return indexContains(Other.Indices);
};

[[nodiscard]] bool
indexContains(const llvm::ArrayRef<unsigned int> &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<T> &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<T> &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 <typename T>
struct hash<psr::IndexWrapper<T>> {
std::size_t operator()(const psr::IndexWrapper<T> &IW) const {
std::size_t HashValue = std::hash<T const *>()(IW.Value);

for (const auto &Index : IW.Indices) {
HashValue ^= std::hash<unsigned int>()(Index) + 0x9e3779b9 + (HashValue << 6) + (HashValue >> 2);
}

return HashValue;
}
};
} // namespace std

#endif
Loading

0 comments on commit 1a96918

Please sign in to comment.