From 6f2c0a2e262e0dab0bbd29aadd5f1cc0fe574239 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 10 May 2024 14:25:50 +0200 Subject: [PATCH] Add test --- .../PhasarLLVM/Pointer/FilteredLLVMAliasSet.h | 13 +- .../IfdsIde/Problems/IFDSTaintAnalysis.cpp | 2 +- .../Pointer/FilteredLLVMAliasSet.cpp | 6 +- unittests/PhasarLLVM/Pointer/CMakeLists.txt | 1 + .../Pointer/FilteredLLVMAliasSetTest.cpp | 138 ++++++++++++++++++ 5 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp diff --git a/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h b/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h index e49267c74..83d63de8d 100644 --- a/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h +++ b/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h @@ -16,7 +16,6 @@ #include "phasar/Pointer/AliasSetOwner.h" #include "phasar/Utils/AnalysisProperties.h" #include "phasar/Utils/MaybeUniquePtr.h" -#include "phasar/Utils/StableVector.h" #include "llvm/Support/ErrorHandling.h" @@ -53,9 +52,10 @@ class FilteredLLVMAliasSet { FilteredLLVMAliasSet(const FilteredLLVMAliasSet &) = delete; FilteredLLVMAliasSet &operator=(const FilteredLLVMAliasSet &) = delete; - FilteredLLVMAliasSet(FilteredLLVMAliasSet &&) = delete; FilteredLLVMAliasSet &operator=(FilteredLLVMAliasSet &&) = delete; + FilteredLLVMAliasSet(FilteredLLVMAliasSet &&) noexcept = default; + ~FilteredLLVMAliasSet(); template AS) noexcept; MaybeUniquePtr AS; - AliasSetOwner::memory_resource_type MRes; - AliasSetOwner Owner{&MRes}; + AliasSetOwner Owner; llvm::DenseMap, AliasSetPtrTy> AliasSetMap; }; diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp index a39fbee4b..ccaa742fa 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp @@ -155,7 +155,7 @@ void IFDSTaintAnalysis::populateWithMayAliases( container_type &Facts, const llvm::Instruction *Context) const { container_type Tmp = Facts; for (const auto *Fact : Facts) { - auto Aliases = PT.getAliasSet(Fact); + auto Aliases = PT.getAliasSet(Fact, Context); for (const auto *Alias : *Aliases) { if (canSkipAtContext(Alias, Context)) { continue; diff --git a/lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp b/lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp index f4839a07e..19bb489ba 100644 --- a/lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp +++ b/lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp @@ -112,11 +112,13 @@ static void fillAliasSet(FilteredLLVMAliasSet::AliasSetTy &Set, } FilteredLLVMAliasSet::FilteredLLVMAliasSet(LLVMAliasSet *AS) noexcept - : AS(AS) {} + : AS(AS), Owner(&AS->MRes) {} FilteredLLVMAliasSet::FilteredLLVMAliasSet( MaybeUniquePtr AS) noexcept - : AS(std::move(AS)) {} + : AS(std::move(AS)), Owner(&this->AS->MRes) {} + +FilteredLLVMAliasSet::~FilteredLLVMAliasSet() = default; AliasAnalysisType FilteredLLVMAliasSet::getAliasAnalysisType() const noexcept { return AS->getAliasAnalysisType(); diff --git a/unittests/PhasarLLVM/Pointer/CMakeLists.txt b/unittests/PhasarLLVM/Pointer/CMakeLists.txt index a8745bbbc..8cf7152ad 100644 --- a/unittests/PhasarLLVM/Pointer/CMakeLists.txt +++ b/unittests/PhasarLLVM/Pointer/CMakeLists.txt @@ -1,6 +1,7 @@ set(ControlFlowSources LLVMAliasSetTest.cpp LLVMAliasSetSerializationTest.cpp + FilteredLLVMAliasSetTest.cpp ) foreach(TEST_SRC ${ControlFlowSources}) diff --git a/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp b/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp new file mode 100644 index 000000000..ccfb76b60 --- /dev/null +++ b/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp @@ -0,0 +1,138 @@ +#include "phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h" + +#include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/InstrTypes.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +using namespace psr; + +namespace { + +static LLVMTaintConfig getDefaultConfig() { + auto SourceCB = [](const llvm::Instruction *Inst) { + std::set Ret; + if (const auto *Call = llvm::dyn_cast(Inst); + Call && Call->getCalledFunction() && + Call->getCalledFunction()->getName() == "_Z6sourcev") { + Ret.insert(Call); + } + return Ret; + }; + auto SinkCB = [](const llvm::Instruction *Inst) { + std::set Ret; + if (const auto *Call = llvm::dyn_cast(Inst); + Call && Call->getCalledFunction() && + Call->getCalledFunction()->getName() == "_Z4sinki") { + assert(Call->arg_size() > 0); + Ret.insert(Call->getArgOperand(0)); + } + return Ret; + }; + return LLVMTaintConfig(std::move(SourceCB), std::move(SinkCB)); +} + +static LLVMTaintConfig getDoubleFreeConfig() { + auto SourceCB = [](const llvm::Instruction *Inst) { + std::set Ret; + if (const auto *Call = llvm::dyn_cast(Inst); + Call && Call->getCalledFunction() && + Call->getCalledFunction()->getName() == "free") { + Ret.insert(Call->getArgOperand(0)); + } + return Ret; + }; + + return LLVMTaintConfig(SourceCB, SourceCB); +} + +class TaintAnalysis : public ::testing::TestWithParam { +protected: + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("taint_analysis/"); + const std::vector EntryPoints = {"main"}; + +}; // Test Fixture + +TEST_P(TaintAnalysis, LeaksWithAndWithoutAliasFilteringEqual) { + + LLVMProjectIRDB IRDB(PathToLlFiles + GetParam()); + LLVMAliasSet AS(&IRDB, false); + FilteredLLVMAliasSet FAS(&AS); + LLVMBasedICFG ICF(&IRDB, CallGraphAnalysisType::OTF, EntryPoints, nullptr, + &AS); + + auto TSF = llvm::StringRef(GetParam()).startswith("double_free") + ? getDoubleFreeConfig() + : getDefaultConfig(); + + IFDSTaintAnalysis TaintProblem(&IRDB, &AS, &TSF, EntryPoints); + IFDSTaintAnalysis FilterTaintProblem(&IRDB, &FAS, &TSF, EntryPoints); + + solveIFDSProblem(TaintProblem, ICF).dumpResults(ICF); + solveIFDSProblem(FilterTaintProblem, ICF).dumpResults(ICF); + + EXPECT_EQ(TaintProblem.Leaks.size(), FilterTaintProblem.Leaks.size()); + + for (const auto &[LeakInst, LeakFacts] : TaintProblem.Leaks) { + const auto It = FilterTaintProblem.Leaks.find(LeakInst); + + EXPECT_NE(It, FilterTaintProblem.Leaks.end()) + << "Expected to find leak at " + llvmIRToString(LeakInst); + + if (It == FilterTaintProblem.Leaks.end()) { + continue; + } + + for (const auto *LeakFact : LeakFacts) { + EXPECT_TRUE(It->second.count(LeakFact)) + << "Expected to find leak-fact " + llvmIRToShortString(LeakFact) + + " at " + llvmIRToString(LeakInst); + } + } +} + +static constexpr std::string_view TaintTestFiles[] = { + // -- dummy-source-sink + "dummy_source_sink/taint_01_cpp_dbg.ll", + "dummy_source_sink/taint_01_cpp_m2r_dbg.ll", + "dummy_source_sink/taint_02_cpp_dbg.ll", + "dummy_source_sink/taint_03_cpp_dbg.ll", + "dummy_source_sink/taint_04_cpp_dbg.ll", + "dummy_source_sink/taint_05_cpp_dbg.ll", + "dummy_source_sink/taint_06_cpp_m2r_dbg.ll", + "dummy_source_sink/taint_exception_01_cpp_dbg.ll", + "dummy_source_sink/taint_exception_01_cpp_m2r_dbg.ll", + "dummy_source_sink/taint_exception_02_cpp_dbg.ll", + "dummy_source_sink/taint_exception_03_cpp_dbg.ll", + "dummy_source_sink/taint_exception_04_cpp_dbg.ll", + "dummy_source_sink/taint_exception_05_cpp_dbg.ll", + "dummy_source_sink/taint_exception_06_cpp_dbg.ll", + "dummy_source_sink/taint_exception_07_cpp_dbg.ll", + "dummy_source_sink/taint_exception_08_cpp_dbg.ll", + "dummy_source_sink/taint_exception_09_cpp_dbg.ll", + "dummy_source_sink/taint_exception_10_cpp_dbg.ll", + // -- double-free + "double_free_01_c.ll", + "double_free_02_c.ll", +}; + +INSTANTIATE_TEST_SUITE_P(InteractiveIDESolverTest, TaintAnalysis, + ::testing::ValuesIn(TaintTestFiles)); + +} // namespace + +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +}