diff --git a/.clang-tidy b/.clang-tidy index 3e95f2eaea..3308a915db 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -61,7 +61,7 @@ CheckOptions: - key: readability-identifier-naming.ParameterIgnoredRegexp value: (d|d1|d2|d3|d4|d5|eP|f|n) - key: readability-identifier-naming.FunctionIgnoredRegexp - value: (try_emplace|from_json|to_json|equal_to|to_string|DToString|NToString|FToString|LToString|hash_value) + value: (try_emplace|from_json|to_json|equal_to|to_string|DToString|NToString|FToString|LToString|hash_value|dyn_cast) - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor value: 1 - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 534357f5bb..fe1827b661 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -1616,7 +1616,7 @@ class IDESolver } else { // Get the fact-ID D1FactId = G.getFactID(D1Fact); - std::string D1Label = DToString(D1Fact); + std::string D1Label{DToString(D1Fact)}; // Get or create the fact subgraph D1FSG = FG->getOrCreateFactSG(D1FactId, D1Label); @@ -1634,7 +1634,7 @@ class IDESolver if (!IDEProblem.isZeroValue(D2Fact)) { // Get the fact-ID D2FactId = G.getFactID(D2Fact); - std::string D2Label = DToString(D2Fact); + std::string D2Label{DToString(D2Fact)}; DOTNode D2 = {FuncName, D2Label, N2StmtId, D2FactId, false, true}; std::string EFLabel; auto EFVec = IntermediateEdgeFunctions[std::make_tuple( @@ -1719,7 +1719,7 @@ class IDESolver } else { // Get the fact-ID D1FactId = G.getFactID(D1Fact); - std::string D1Label = DToString(D1Fact); + std::string D1Label{DToString(D1Fact)}; D1 = {FNameOfN1, D1Label, N1StmtId, D1FactId, false, true}; // FG should already exist even for single statement functions if (!G.containsFactSG(FNameOfN1, D1FactId)) { @@ -1738,7 +1738,7 @@ class IDESolver } else { // Get the fact-ID D2FactId = G.getFactID(D2Fact); - std::string D2Label = DToString(D2Fact); + std::string D2Label{DToString(D2Fact)}; D2 = {FNameOfN2, D2Label, N2StmtId, D2FactId, false, true}; // FG should already exist even for single statement functions if (!G.containsFactSG(FNameOfN2, D2FactId)) { diff --git a/include/phasar/Domain/LatticeDomain.h b/include/phasar/Domain/LatticeDomain.h index d45f7bc45a..560409f370 100644 --- a/include/phasar/Domain/LatticeDomain.h +++ b/include/phasar/Domain/LatticeDomain.h @@ -11,6 +11,7 @@ #define PHASAR_DOMAIN_LATTICEDOMAIN_H #include "phasar/Utils/ByRef.h" +#include "phasar/Utils/DebugOutput.h" #include "phasar/Utils/JoinLattice.h" #include "phasar/Utils/TypeTraits.h" @@ -100,9 +101,7 @@ struct LatticeDomain : public std::variant { } }; -template () - << std::declval())>> +template inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LatticeDomain &LD) { if (LD.isBottom()) { @@ -114,7 +113,11 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const auto *Val = LD.getValueOrNull(); assert(Val && "Only alternative remaining is L"); - return OS << *Val; + if constexpr (is_llvm_printable_v) { + return OS << *Val; + } else { + return OS << PrettyPrinter{*Val}; + } } template diff --git a/include/phasar/Utils/BitVectorSet.h b/include/phasar/Utils/BitVectorSet.h index c64f8f41bf..b11786e847 100644 --- a/include/phasar/Utils/BitVectorSet.h +++ b/include/phasar/Utils/BitVectorSet.h @@ -292,9 +292,9 @@ class BitVectorSet { [[nodiscard]] size_t size() const noexcept { return Bits.count(); } - [[nodiscard]] const BitVectorTy &getBits() const &noexcept { return Bits; } - [[nodiscard]] BitVectorTy &getBits() &noexcept { return Bits; } - [[nodiscard]] BitVectorTy &&getBits() &&noexcept { return std::move(Bits); } + [[nodiscard]] const BitVectorTy &getBits() const & noexcept { return Bits; } + [[nodiscard]] BitVectorTy &getBits() & noexcept { return Bits; } + [[nodiscard]] BitVectorTy &&getBits() && noexcept { return std::move(Bits); } friend bool operator==(const BitVectorSet &Lhs, const BitVectorSet &Rhs) { bool LeftEmpty = Lhs.empty(); @@ -392,6 +392,11 @@ class BitVectorSet { EndIter.setBits(Bits); return EndIter; } + + static void clearPosition() { + Position.left.clear(); + Position.right.clear(); + } }; // Overloads with the other intersectWith functions from Utilities.h diff --git a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp index 09abf5fecd..af8b41bf76 100644 --- a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp +++ b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp @@ -101,15 +101,19 @@ static llvm::DISubprogram *getDISubprogram(const llvm::Value *V) { llvm::DILocation *psr::getDILocation(const llvm::Value *V) { // Arguments and Instruction such as AllocaInst - if (auto *DbgIntr = getDbgVarIntrinsic(V)) { - if (auto *MN = DbgIntr->getMetadata(llvm::LLVMContext::MD_dbg)) { + + if (const auto *I = llvm::dyn_cast(V)) { + if (auto *MN = I->getMetadata(llvm::LLVMContext::MD_dbg)) { return llvm::dyn_cast(MN); } - } else if (const auto *I = llvm::dyn_cast(V)) { - if (auto *MN = I->getMetadata(llvm::LLVMContext::MD_dbg)) { + } + + if (auto *DbgIntr = getDbgVarIntrinsic(V)) { + if (auto *MN = DbgIntr->getMetadata(llvm::LLVMContext::MD_dbg)) { return llvm::dyn_cast(MN); } } + return nullptr; } diff --git a/test/llvm_test_code/general_linear_constant/CMakeLists.txt b/test/llvm_test_code/general_linear_constant/CMakeLists.txt index c1da0c9533..d0e555ccf6 100644 --- a/test/llvm_test_code/general_linear_constant/CMakeLists.txt +++ b/test/llvm_test_code/general_linear_constant/CMakeLists.txt @@ -14,5 +14,5 @@ set(Sources ) foreach(TEST_SRC ${Sources}) - generate_ll_file(FILE ${TEST_SRC}) + generate_ll_file(FILE ${TEST_SRC} DEBUG) endforeach(TEST_SRC) diff --git a/test/llvm_test_code/general_linear_constant/NullTest.c b/test/llvm_test_code/general_linear_constant/NullTest.c index 7858875af1..550254165f 100644 --- a/test/llvm_test_code/general_linear_constant/NullTest.c +++ b/test/llvm_test_code/general_linear_constant/NullTest.c @@ -2,4 +2,7 @@ char *foo(char *str) { return str; } extern void puts(const char *); -int main() { puts(foo(0)); } +int main() { + puts(foo(0)); + return 0; +} diff --git a/test/llvm_test_code/inst_interaction/CMakeLists.txt b/test/llvm_test_code/inst_interaction/CMakeLists.txt index 6fdfa88e8b..e5307f4949 100644 --- a/test/llvm_test_code/inst_interaction/CMakeLists.txt +++ b/test/llvm_test_code/inst_interaction/CMakeLists.txt @@ -41,9 +41,9 @@ set(SourcesOpt ) foreach(TEST_SRC ${Sources}) - generate_ll_file(FILE ${TEST_SRC}) + generate_ll_file(FILE ${TEST_SRC} DEBUG) endforeach(TEST_SRC) foreach(TEST_SRC ${SourcesOpt}) - generate_ll_file(FILE ${TEST_SRC} O1) + generate_ll_file(FILE ${TEST_SRC} DEBUG O1) endforeach(TEST_SRC) diff --git a/test/llvm_test_code/openssl/key_derivation/CMakeLists.txt b/test/llvm_test_code/openssl/key_derivation/CMakeLists.txt index 7565aeef5e..39770d7dbf 100644 --- a/test/llvm_test_code/openssl/key_derivation/CMakeLists.txt +++ b/test/llvm_test_code/openssl/key_derivation/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB openssl_files *.c *.cpp) foreach(TEST_SRC ${openssl_files}) get_filename_component(TEST_SRC_FILE ${TEST_SRC} NAME) - generate_ll_file(FILE ${TEST_SRC_FILE}) + generate_ll_file(FILE ${TEST_SRC_FILE} DEBUG) endforeach(TEST_SRC) diff --git a/test/llvm_test_code/openssl/secure_heap/CMakeLists.txt b/test/llvm_test_code/openssl/secure_heap/CMakeLists.txt index 7565aeef5e..39770d7dbf 100644 --- a/test/llvm_test_code/openssl/secure_heap/CMakeLists.txt +++ b/test/llvm_test_code/openssl/secure_heap/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB openssl_files *.c *.cpp) foreach(TEST_SRC ${openssl_files}) get_filename_component(TEST_SRC_FILE ${TEST_SRC} NAME) - generate_ll_file(FILE ${TEST_SRC_FILE}) + generate_ll_file(FILE ${TEST_SRC_FILE} DEBUG) endforeach(TEST_SRC) diff --git a/test/llvm_test_code/openssl/secure_memory/CMakeLists.txt b/test/llvm_test_code/openssl/secure_memory/CMakeLists.txt index 7565aeef5e..39770d7dbf 100644 --- a/test/llvm_test_code/openssl/secure_memory/CMakeLists.txt +++ b/test/llvm_test_code/openssl/secure_memory/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB openssl_files *.c *.cpp) foreach(TEST_SRC ${openssl_files}) get_filename_component(TEST_SRC_FILE ${TEST_SRC} NAME) - generate_ll_file(FILE ${TEST_SRC_FILE}) + generate_ll_file(FILE ${TEST_SRC_FILE} DEBUG) endforeach(TEST_SRC) diff --git a/test/llvm_test_code/taint_analysis/CMakeLists.txt b/test/llvm_test_code/taint_analysis/CMakeLists.txt index cbefe33821..1c3ff627f7 100644 --- a/test/llvm_test_code/taint_analysis/CMakeLists.txt +++ b/test/llvm_test_code/taint_analysis/CMakeLists.txt @@ -38,7 +38,7 @@ set(NoMem2regSources ) foreach(TEST_SRC ${NoMem2regSources}) - generate_ll_file(FILE ${TEST_SRC}) + generate_ll_file(FILE ${TEST_SRC} DEBUG) endforeach(TEST_SRC) add_subdirectory(dummy_source_sink) diff --git a/test/llvm_test_code/typestate_analysis_fileio/CMakeLists.txt b/test/llvm_test_code/typestate_analysis_fileio/CMakeLists.txt index 9da0ecdc68..ef2be35b66 100644 --- a/test/llvm_test_code/typestate_analysis_fileio/CMakeLists.txt +++ b/test/llvm_test_code/typestate_analysis_fileio/CMakeLists.txt @@ -1,10 +1,5 @@ file(GLOB typestate_files *.c *.cpp) -foreach(TEST_SRC ${typestate_files}) - get_filename_component(TEST_SRC_FILE ${TEST_SRC} NAME) - generate_ll_file(FILE ${TEST_SRC_FILE}) -endforeach(TEST_SRC) - foreach(TEST_SRC ${typestate_files}) get_filename_component(TEST_SRC_FILE ${TEST_SRC} NAME) generate_ll_file(FILE ${TEST_SRC_FILE} DEBUG) diff --git a/test/llvm_test_code/xtaint/CMakeLists.txt b/test/llvm_test_code/xtaint/CMakeLists.txt index ad1fa8702f..c3f8041798 100644 --- a/test/llvm_test_code/xtaint/CMakeLists.txt +++ b/test/llvm_test_code/xtaint/CMakeLists.txt @@ -1,5 +1,6 @@ -set(XTAINT_SOURCES +set(XTAINT_DBG_SOURCES xtaint01.cpp + xtaint01_json.cpp # xtaint01_json.cpp xtaint02.cpp xtaint03.cpp @@ -24,14 +25,6 @@ set(XTAINT_SOURCES xtaint21.cpp ) -set(XTAINT_DBG_SOURCES - xtaint01_json.cpp -) - -foreach(TEST_SRC ${XTAINT_SOURCES}) - generate_ll_file(FILE ${TEST_SRC}) -endforeach(TEST_SRC) - foreach(TEST_SRC ${XTAINT_DBG_SOURCES}) generate_ll_file(FILE ${TEST_SRC} DEBUG) endforeach(TEST_SRC) diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysisTest.cpp index 51af9f3058..988952783b 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysisTest.cpp @@ -11,35 +11,25 @@ #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/HelperAnalyses.h" -#include "phasar/PhasarLLVM/Passes/ValueAnnotationPass.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" #include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" -#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" -#include "phasar/Utils/DebugOutput.h" #include "phasar/Utils/Utilities.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Demangle/Demangle.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/Casting.h" +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" -#include "nlohmann/json.hpp" #include -#include #include #include -using namespace std; using namespace psr; -using json = nlohmann::json; using CallBackPairTy = std::pair::config_callback_t, IDEExtendedTaintAnalysis<>::config_callback_t>; @@ -51,14 +41,14 @@ class IDETaintAnalysisTest : public ::testing::Test { static constexpr auto PathToLLFiles = PHASAR_BUILD_SUBFOLDER("xtaint/"); const std::vector EntryPoints = {"main"}; - IDETaintAnalysisTest() = default; - ~IDETaintAnalysisTest() override = default; + using TaintSetT = std::set; void doAnalysis( - const llvm::Twine &IRFile, const map> &GroundTruth, + const llvm::Twine &IRFilePath, + const std::map &GroundTruth, std::variant Config, bool DumpResults = true) { - HelperAnalyses HA(IRFile, EntryPoints); + HelperAnalyses HA(PathToLLFiles + IRFilePath, EntryPoints); auto TC = std::visit(Overloaded{[&](std::monostate) { @@ -93,34 +83,26 @@ class IDETaintAnalysisTest : public ::testing::Test { compareResults(TaintProblem, Solver, GroundTruth); } - void SetUp() override { ValueAnnotationPass::resetValueID(); } + void + compareResults(IDEExtendedTaintAnalysis<> &TaintProblem, + IDESolver_P> &Solver, + const std::map &GroundTruth) { + auto GroundTruthEntries = convertTestingLocationSetMapInIR( + GroundTruth, *TaintProblem.getProjectIRDB()); - void TearDown() override {} + std::map> + FoundLeaks; - void compareResults(IDEExtendedTaintAnalysis<> &TaintProblem, - IDESolver_P> &Solver, - const map> &GroundTruth) { - - map> FoundLeaks; - for (const auto &Leak : + for (const auto &[LeakInst, LeakVals] : TaintProblem.getAllLeaks(Solver.getSolverResults())) { - llvm::errs() << "Leak: " << PrettyPrinter{Leak} << '\n'; - int SinkId = stoi(getMetaDataID(Leak.first)); - set LeakedValueIds; - for (const auto &LV : Leak.second) { - LeakedValueIds.insert(getMetaDataID(LV)); - } - FoundLeaks.emplace(SinkId, LeakedValueIds); + FoundLeaks[LeakInst].insert(LeakVals.begin(), LeakVals.end()); } - EXPECT_EQ(FoundLeaks, GroundTruth); + + EXPECT_EQ(FoundLeaks, GroundTruthEntries); } }; // Test Fixture TEST_F(IDETaintAnalysisTest, XTaint01_Json) { - map> Gt; - - Gt[7] = {"6"}; - TaintConfigData Config; FunctionData FuncDataMain; @@ -134,192 +116,184 @@ TEST_F(IDETaintAnalysisTest, XTaint01_Json) { Config.Functions.push_back(std::move(FuncDataMain)); Config.Functions.push_back(std::move(FuncDataPrint)); - doAnalysis({PathToLLFiles + "xtaint01_json_cpp_dbg.ll"}, Gt, &Config); + std::map GroundTruth = {{ + LineColFun{8, 3, "main"}, + {LineColFunOp{8, 9, "main", llvm::Instruction::Load}}, + }}; + + doAnalysis("xtaint01_json_cpp_dbg.ll", GroundTruth, &Config); } TEST_F(IDETaintAnalysisTest, XTaint01) { - map> Gt; - - Gt[13] = {"12"}; + std::map GroundTruth = { + {LineColFun{8, 3, "main"}, + {LineColFunOp{8, 9, "main", llvm::Instruction::Load}}}}; - doAnalysis({PathToLLFiles + "xtaint01_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint01_cpp_dbg.ll", GroundTruth, std::monostate{}); } TEST_F(IDETaintAnalysisTest, XTaint02) { - map> Gt; - - Gt[18] = {"17"}; + std::map GroundTruth = { + {LineColFun{9, 3, "main"}, + {LineColFunOp{9, 9, "main", llvm::Instruction::Load}}}}; - doAnalysis({PathToLLFiles + "xtaint02_cpp.ll"}, Gt, std::monostate{}, true); + doAnalysis("xtaint02_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } -TEST_F(IDETaintAnalysisTest, XTaint03) { - map> Gt; - Gt[21] = {"20"}; +TEST_F(IDETaintAnalysisTest, XTaint03) { + std::map GroundTruth = { + {LineColFun{10, 3, "main"}, + {LineColFunOp{10, 9, "main", llvm::Instruction::Load}}}}; - doAnalysis({PathToLLFiles + "xtaint03_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint03_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint04) { - map> Gt; + auto Call = LineColFun{6, 3, "_Z3barPi"}; - Gt[16] = {"15"}; + std::map GroundTruth = { + {Call, {OperandOf{0, Call}}}}; - doAnalysis({PathToLLFiles + "xtaint04_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint04_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } // XTaint05 is similar to 06, but even harder TEST_F(IDETaintAnalysisTest, XTaint06) { - map> Gt; - - // no leaks expected + std::map GroundTruth = { + // no leaks expected + }; - doAnalysis({PathToLLFiles + "xtaint06_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint06_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } -/// In the new TaintConfig specifying source/sink/sanitizer properties for extra -/// parameters of C-style variadic functions is not (yet?) supported. So, the -/// tests XTaint07 and XTaint08 are disabled. +/// In the new TaintConfig specifying source/sink/sanitizer properties for +/// extra parameters of C-style variadic functions is not (yet?) supported. +/// So, the tests XTaint07 and XTaint08 are disabled. TEST_F(IDETaintAnalysisTest, DISABLED_XTaint07) { - map> Gt; + std::map GroundTruth = { + {LineColFun{10, 0, "main"}, + {LineColFunOp{10, 18, "main", llvm::Instruction::Load}}}}; - Gt[21] = {"20"}; - - doAnalysis({PathToLLFiles + "xtaint07_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint07_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, DISABLED_XTaint08) { - map> Gt; - - Gt[24] = {"23"}; + std::map GroundTruth = { + {LineColFun{20, 3, "main"}, + {LineColFunOp{20, 18, "main", llvm::Instruction::Load}}}}; - doAnalysis({PathToLLFiles + "xtaint08_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint08_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint09_1) { - map> Gt; - - Gt[25] = {"24"}; + std::map GroundTruth = { + {LineColFun{14, 3, "main"}, {LineColFun{14, 8, "main"}}}}; - doAnalysis({PathToLLFiles + "xtaint09_1_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint09_1_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint09) { - map> Gt; + auto SinkCall = LineColFun{16, 3, "main"}; + std::map GroundTruth = { + {SinkCall, {OperandOf{0, SinkCall}}}}; - Gt[24] = {"23"}; - - doAnalysis({PathToLLFiles + "xtaint09_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint09_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, DISABLED_XTaint10) { - map> Gt; - - // undefined behaviour: sometimes this test fails, but most of the time - // it passes. It only fails when executed together with other tests. It - // never failed (so far) for ./IDEExtendedTaintAnalysisTest - // --Gtest_filter=*XTaint10 - // UPDATE: With the fixed k-limiting, this test - // almost always fails due to aliasing issues, so disable it. - // TODO: Also update the Gt - Gt[33] = {"32"}; - - doAnalysis({PathToLLFiles + "xtaint10_cpp.ll"}, Gt, std::monostate{}); + std::map GroundTruth = { + // no leaks expected + }; + + doAnalysis("xtaint10_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, DISABLED_XTaint11) { - map> Gt; - - // no leaks expected; actually finds "27" at 28 + std::map GroundTruth = { + // no leaks expected + }; - doAnalysis({PathToLLFiles + "xtaint11_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint11_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint12) { - map> Gt; + std::map GroundTruth = { + {LineColFun{19, 3, "main"}, {LineColFun{19, 8, "main"}}}}; - // We sanitize an alias - since we don't have must-alias relations, we cannot - // kill aliases at all - Gt[28] = {"27"}; - - doAnalysis({PathToLLFiles + "xtaint12_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint12_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint13) { - map> Gt; - - Gt[30] = {"29"}; + std::map GroundTruth = { + {LineColFun{17, 3, "main"}, {LineColFun{17, 8, "main"}}}}; - doAnalysis({PathToLLFiles + "xtaint13_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint13_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint14) { - map> Gt; - - Gt[33] = {"32"}; + std::map GroundTruth = { + {LineColFun{24, 3, "main"}, {LineColFun{24, 8, "main"}}}}; - doAnalysis({PathToLLFiles + "xtaint14_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint14_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } /// The TaintConfig fails to get all call-sites of Source::get, because it has /// no CallGraph information TEST_F(IDETaintAnalysisTest, DISABLED_XTaint15) { - map> Gt; + std::map GroundTruth = { + // no leaks expected + }; - Gt[47] = {"46"}; - - doAnalysis({PathToLLFiles + "xtaint15_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint15_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint16) { - map> Gt; - - Gt[24] = {"23"}; + std::map GroundTruth = { + {LineColFun{13, 3, "main"}, {LineColFun{13, 8, "main"}}}}; - doAnalysis({PathToLLFiles + "xtaint16_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint16_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint17) { - map> Gt; - - Gt[27] = {"26"}; + std::map GroundTruth = { + {LineColFun{17, 3, "main"}, {LineColFun{17, 8, "main"}}}}; - doAnalysis({PathToLLFiles + "xtaint17_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint17_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint18) { - map> Gt; + std::map GroundTruth = { + // no leaks expected + }; - // Gt[26] = {"25"}; - - doAnalysis({PathToLLFiles + "xtaint18_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint18_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } PHASAR_SKIP_TEST(TEST_F(IDETaintAnalysisTest, XTaint19) { // Is now the same as XTaint17 GTEST_SKIP(); - map> Gt; - Gt[22] = {"21"}; + std::map GroundTruth = { + {LineColFun{17, 3, "main"}, {LineColFun{17, 8, "main"}}}}; - doAnalysis({PathToLLFiles + "xtaint19_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint19_cpp_dbg.ll", GroundTruth, std::monostate{}, true); }) TEST_F(IDETaintAnalysisTest, XTaint20) { - map> Gt; - - Gt[22] = {"14"}; - Gt[24] = {"23"}; + std::map GroundTruth = { + {LineColFun{12, 3, "main"}, {LineColFun{6, 7, "main"}}}, + {LineColFun{13, 3, "main"}, {LineColFun{13, 8, "main"}}}, + }; - doAnalysis({PathToLLFiles + "xtaint20_cpp.ll"}, Gt, std::monostate{}); + doAnalysis("xtaint20_cpp_dbg.ll", GroundTruth, std::monostate{}, true); } TEST_F(IDETaintAnalysisTest, XTaint21) { - map> Gt; - - Gt[10] = {"2"}; - Gt[12] = {"11"}; + std::map GroundTruth = { + {LineColFun{17, 3, "main"}, {LineColFun{11, 7, "main"}}}, + {LineColFun{18, 3, "main"}, {LineColFun{18, 8, "main"}}}, + }; IDEExtendedTaintAnalysis<>::config_callback_t SourceCB = [](const llvm::Instruction *Inst) { @@ -343,7 +317,7 @@ TEST_F(IDETaintAnalysisTest, XTaint21) { return Ret; }; - doAnalysis({PathToLLFiles + "xtaint21_cpp.ll"}, Gt, + doAnalysis("xtaint21_cpp_dbg.ll", GroundTruth, CallBackPairTy{std::move(SourceCB), std::move(SinkCB)}); } diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysisTest.cpp index 243cb2d6a7..402cc59407 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysisTest.cpp @@ -17,20 +17,25 @@ #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" +#include + namespace { using namespace psr; -static std::string printSet(const std::set &EdgeFact) { - std::string Ret; - llvm::raw_string_ostream ROS(Ret); - llvm::interleaveComma(EdgeFact, ROS << '<'); - ROS << '>'; - return Ret; -} +using TaintSetT = std::set; + +// static std::string printSet(const std::set &EdgeFact) { +// std::string Ret; +// llvm::raw_string_ostream ROS(Ret); +// llvm::interleaveComma(EdgeFact, ROS << '<'); +// ROS << '>'; +// return Ret; +// } /* ============== TEST FIXTURE ============== */ class IDEFeatureTaintAnalysisTest : public ::testing::Test { @@ -38,9 +43,10 @@ class IDEFeatureTaintAnalysisTest : public ::testing::Test { static constexpr auto PathToLlFiles = PHASAR_BUILD_SUBFOLDER("inst_interaction/"); + using VarNameT = std::variant; // Function - Line Nr - Variable - Values using IIACompactResult_t = - std::tuple>; + std::tuple>; std::optional HA; LLVMProjectIRDB *IRDB{}; @@ -50,17 +56,35 @@ class IDEFeatureTaintAnalysisTest : public ::testing::Test { HA.emplace(PathToLlFiles + LlvmFilePath, EntryPoints, HelperAnalysisConfig{}.withCGType(CallGraphAnalysisType::CHA)); IRDB = &HA->getProjectIRDB(); + } - for (const auto &Glob : IRDB->getModule()->globals()) { - BitVectorSet BV; - BV.insert(getMetaDataID(&Glob)); - } - - // Initialze IDs - for (const auto *Inst : IRDB->getAllInstructions()) { - BitVectorSet BV; - BV.insert(getMetaDataID(Inst)); - } + [[nodiscard]] bool matchesVar(const llvm::Value *Fact, + const VarNameT &VarName) { + return std::visit( + psr::Overloaded{ + [&](const std::string &Name) { + if (!llvm::isa(Fact) && + !llvm::isa(Fact)) { + return false; + } + auto FactName = psr::getVarNameFromIR(Fact); + return FactName == Name; + }, + [&](RetVal R) { + return llvm::any_of(Fact->users(), [R](const auto *V) { + const auto *Ret = llvm::dyn_cast(V); + return Ret && Ret->getFunction()->getName() == R.InFunction; + }); + }, + }, + VarName); + } + [[nodiscard]] std::string printVar(const VarNameT &VarName) { + return std::visit(psr::Overloaded{ + [](const std::string &Name) { return Name; }, + [](RetVal R) { return R.str(); }, + }, + VarName); } void @@ -77,21 +101,32 @@ class IDEFeatureTaintAnalysisTest : public ::testing::Test { // use Phasar's instruction ids as testing labels auto Generator = [](std::variant - Current) -> std::set { + Current) -> std::set { return std::visit( - [](const auto *InstOrGlob) -> std::set { - std::set Labels; - if (InstOrGlob->hasMetadata()) { - std::string Label = - llvm::cast( - InstOrGlob->getMetadata(PhasarConfig::MetaDataKind()) - ->getOperand(0)) - ->getString() - .str(); - Labels.insert(Label); - } - return Labels; - }, + psr::Overloaded{ + [](const llvm::GlobalVariable *Glob) + -> std::set { + std::set Labels; + Labels.insert(GlobalVar{Glob->getName()}); + return Labels; + }, + [](const llvm::Instruction *Inst) + -> std::set { + std::set Labels; + auto [Line, Col] = getLineAndColFromIR(Inst); + if (Col == 0 && llvm::isa(Inst)) { + std::tie(Line, Col) = getLineAndColFromIR(Inst->getOperand( + llvm::StoreInst::getPointerOperandIndex())); + } + if (Line != 0) { + Labels.insert(LineColFun{ + Line, + Col, + Inst->getFunction()->getName(), + }); + } + return Labels; + }}, Current); }; assert(HA); @@ -112,438 +147,820 @@ class IDEFeatureTaintAnalysisTest : public ::testing::Test { // printDump(HA->getProjectIRDB(), IIASolver.getSolverResults()); // } // do the comparison - for (const auto &[FunName, SrcLine, VarName, LatticeVal] : GroundTruth) { - const auto *Fun = IRDB->getFunctionDefinition(FunName); - const auto *IRLine = getNthInstruction(Fun, SrcLine); - auto ResultMap = IIASolver.resultsAt(IRLine); - assert(IRLine && "Could not retrieve IR line!"); + for (const auto &[InstLoc, VarName, ExpectedVal] : GroundTruth) { + const auto *IRLoc = testingLocInIR(InstLoc, *IRDB); + ASSERT_TRUE(IRLoc) << "Could not retrieve IR Loc: " << InstLoc.str(); + ASSERT_TRUE(llvm::isa(IRLoc)); + auto ResultMap = + IIASolver.resultsAt(llvm::cast(IRLoc)); bool FactFound = false; - for (auto &[Fact, Value] : ResultMap) { - std::string FactStr; - llvm::raw_string_ostream RSO(FactStr); - RSO << *Fact; - llvm::StringRef FactRef(FactStr); - if (FactRef.ltrim().startswith("%" + VarName + " ") || - FactRef.ltrim().startswith("@" + VarName + " ")) { - PHASAR_LOG_LEVEL(DFADEBUG, "Checking variable: " << FactStr); - EXPECT_EQ(LatticeVal, Value.toSet()) - << "Value do not match for Variable '" << VarName - << "': Expected " << printSet(LatticeVal) - << "; got: " << LToString(Value.toBVSet()); + for (auto &[Fact, ComputedVal] : ResultMap) { + if (matchesVar(Fact, VarName)) { + EXPECT_EQ(ExpectedVal, ComputedVal.toSet()) + << "Unexpected taint-set at " << InstLoc << " for variable '" + << printVar(VarName) << "' (" << llvmIRToString(Fact) << ")"; FactFound = true; } } - EXPECT_TRUE(FactFound) << "Variable '" << VarName << "' missing at '" - << llvmIRToString(IRLine) << "'."; + EXPECT_TRUE(FactFound) + << "Variable '" << printVar(VarName) << "' missing at '" + << llvmIRToString(IRLoc) << "'."; } if (PrintDump || HasFailure()) { IIASolver.dumpResults(llvm::errs()); - llvm::errs() - << "\n======================================================\n"; - printDump(HA->getProjectIRDB(), IIASolver.getSolverResults()); + // llvm::errs() + // << "\n======================================================\n"; + // printDump(HA->getProjectIRDB(), IIASolver.getSolverResults()); } } - void TearDown() override {} - - // See vara::PhasarTaintAnalysis::taintsForInst - [[nodiscard]] inline std::set - taintsForInst(const llvm::Instruction *Inst, - SolverResults SR) { - - if (const auto *Ret = llvm::dyn_cast(Inst)) { - if (Ret->getNumOperands() == 0) { - return {}; - } - } else if (llvm::isa(Inst)) { - return {}; - } - - std::set AggregatedTaints; - - if (Inst->getType()->isVoidTy()) { // For void types, we need to look what - // taints flow into the inst - - // auto Results = SR.resultsAt(Inst); - assert(Inst->getNumOperands() >= 1 && - "Found case without first operand."); - AggregatedTaints = - SR.resultAt(Inst, Inst->getOperand(0)).toSet(); - - } else { - auto Results = SR.resultsAtInLLVMSSA(Inst); - auto SearchPosTaints = Results.find(Inst); - if (SearchPosTaints != Results.end()) { - AggregatedTaints = SearchPosTaints->second.toSet(); - } - } - - // additionalStaticTaints - AggregatedTaints.insert(getMetaDataID(Inst)); - - return AggregatedTaints; + void TearDown() override { + BitVectorSet::clearPosition(); } - void printDump(const LLVMProjectIRDB &IRDB, - SolverResults - SR) { - const llvm::Function *CurrFun = nullptr; - for (const auto *Inst : IRDB.getAllInstructions()) { - if (CurrFun != Inst->getFunction()) { - CurrFun = Inst->getFunction(); - llvm::errs() << "\n=================== '" << CurrFun->getName() - << "' ===================\n"; - } - llvm::errs() << " N: " << llvmIRToString(Inst) << '\n'; - llvm::errs() << " D: " << printSet(taintsForInst(Inst, SR)) << "\n\n"; - } - } + // // See vara::PhasarTaintAnalysis::taintsForInst + // [[nodiscard]] inline std::set + // taintsForInst(const llvm::Instruction *Inst, + // SolverResults SR) { + + // if (const auto *Ret = llvm::dyn_cast(Inst)) { + // if (Ret->getNumOperands() == 0) { + // return {}; + // } + // } else if (llvm::isa(Inst)) { + // return {}; + // } + + // std::set AggregatedTaints; + + // if (Inst->getType()->isVoidTy()) { // For void types, we need to look + // what + // // taints flow into the inst + + // // auto Results = SR.resultsAt(Inst); + // assert(Inst->getNumOperands() >= 1 && + // "Found case without first operand."); + // AggregatedTaints = + // SR.resultAt(Inst, Inst->getOperand(0)).toSet(); + + // } else { + // auto Results = SR.resultsAtInLLVMSSA(Inst); + // auto SearchPosTaints = Results.find(Inst); + // if (SearchPosTaints != Results.end()) { + // AggregatedTaints = SearchPosTaints->second.toSet(); + // } + // } + + // // additionalStaticTaints + // AggregatedTaints.insert(getMetaDataID(Inst)); + + // return AggregatedTaints; + // } + + // void printDump(const LLVMProjectIRDB &IRDB, + // SolverResults + // SR) { + // const llvm::Function *CurrFun = nullptr; + // for (const auto *Inst : IRDB.getAllInstructions()) { + // if (CurrFun != Inst->getFunction()) { + // CurrFun = Inst->getFunction(); + // llvm::errs() << "\n=================== '" << CurrFun->getName() + // << "' ===================\n"; + // } + // llvm::errs() << " N: " << llvmIRToString(Inst) << '\n'; + // llvm::errs() << " D: " << printSet(taintsForInst(Inst, SR)) << "\n\n"; + // } + // } }; // Test Fixture TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_01) { std::set GroundTruth; - GroundTruth.emplace("main", 9, "i", std::set{"4"}); - GroundTruth.emplace("main", 9, "j", - std::set{"4", "5", "6", "7"}); - GroundTruth.emplace("main", 9, "retval", std::set{"3"}); - doAnalysisAndCompareResults("basic_01_cpp.ll", {"main"}, GroundTruth, false); + auto Main9 = LineColFun{4, 3, "main"}; + GroundTruth.emplace(Main9, "i", TaintSetT{LineColFun{2, 7, "main"}}); + GroundTruth.emplace(Main9, "j", + TaintSetT{ + LineColFun{2, 7, "main"}, + LineColFun{3, 11, "main"}, + LineColFun{3, 13, "main"}, + LineColFun{3, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_02) { std::set GroundTruth; - GroundTruth.emplace("main", 24, "retval", std::set{"6"}); - GroundTruth.emplace("main", 24, "argc.addr", std::set{"7"}); - GroundTruth.emplace("main", 24, "argv.addr", std::set{"8"}); - GroundTruth.emplace("main", 24, "i", std::set{"16", "18"}); - GroundTruth.emplace("main", 24, "j", - std::set{"9", "10", "11", "12"}); - GroundTruth.emplace("main", 24, "k", - std::set{"21", "16", "18", "20"}); - doAnalysisAndCompareResults("basic_02_cpp.ll", {"main"}, GroundTruth, false); + auto Main24 = LineColFun{10, 3, "main"}; + + GroundTruth.emplace(Main24, "argc", TaintSetT{LineColFun{1, 14, "main"}}); + GroundTruth.emplace(Main24, "argv", TaintSetT{LineColFun{1, 27, "main"}}); + GroundTruth.emplace(Main24, "i", + TaintSetT{ + LineColFun{5, 7, "main"}, + LineColFun{7, 7, "main"}, + }); + GroundTruth.emplace(Main24, "j", + TaintSetT{ + LineColFun{2, 7, "main"}, + LineColFun{3, 11, "main"}, + LineColFun{3, 13, "main"}, + LineColFun{3, 7, "main"}, + }); + GroundTruth.emplace(Main24, "k", + TaintSetT{ + LineColFun{5, 7, "main"}, + LineColFun{7, 7, "main"}, + LineColFun{9, 11, "main"}, + LineColFun{9, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_02_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_03) { std::set GroundTruth; - GroundTruth.emplace("main", 20, "retval", std::set{"3"}); - GroundTruth.emplace("main", 20, "i", - std::set{"4", "10", "11", "12"}); - GroundTruth.emplace("main", 20, "x", - std::set{"5", "14", "15", "16"}); - doAnalysisAndCompareResults("basic_03_cpp.ll", {"main"}, GroundTruth, false); + + auto Main20 = LineColFun{6, 3, "main"}; + + GroundTruth.emplace(Main20, "i", + TaintSetT{ + LineColFun{2, 7, "main"}, + LineColFun{4, 5, "main"}, + }); + GroundTruth.emplace(Main20, "x", + TaintSetT{ + LineColFun{3, 12, "main"}, + LineColFun{3, 28, "main"}, + }); + + doAnalysisAndCompareResults("basic_03_cpp_dbg.ll", {"main"}, GroundTruth, + false); } -PHASAR_SKIP_TEST(TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_04) { - // If we use libcxx this won't work since internal implementation is different +TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_04) { + LIBCPP_GTEST_SKIP; std::set GroundTruth; - GroundTruth.emplace("main", 23, "retval", std::set{"7"}); - GroundTruth.emplace("main", 23, "argc.addr", std::set{"8"}); - GroundTruth.emplace("main", 23, "argv.addr", std::set{"9"}); - GroundTruth.emplace("main", 23, "i", std::set{"10"}); - GroundTruth.emplace("main", 23, "j", - std::set{"10", "11", "12", "13"}); - GroundTruth.emplace( - "main", 23, "k", - std::set{"10", "11", "12", "13", "14", "18", "19"}); - doAnalysisAndCompareResults("basic_04_cpp.ll", {"main"}, GroundTruth, false); -}) + auto Main23 = LineColFun{11, 3, "main"}; + + GroundTruth.emplace(Main23, "argc", + TaintSetT{ + LineColFun{3, 14, "main"}, + }); + GroundTruth.emplace(Main23, "argv", + TaintSetT{ + LineColFun{3, 27, "main"}, + }); + GroundTruth.emplace(Main23, "i", + TaintSetT{ + LineColFun{4, 7, "main"}, + }); + GroundTruth.emplace(Main23, "j", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 11, "main"}, + LineColFun{5, 13, "main"}, + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main23, "k", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 11, "main"}, + LineColFun{5, 13, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{6, 7, "main"}, + LineColFun{8, 9, "main"}, + LineColFun{8, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_04_cpp_dbg.ll", {"main"}, GroundTruth, + false); +} TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_05) { std::set GroundTruth; - GroundTruth.emplace("main", 11, "i", std::set{"5", "7"}); - GroundTruth.emplace("main", 11, "retval", std::set{"2"}); - doAnalysisAndCompareResults("basic_05_cpp.ll", {"main"}, GroundTruth, false); + auto Main11 = LineColFun{10, 3, "main"}; + GroundTruth.emplace(Main11, "i", + TaintSetT{ + LineColFun{6, 7, "main"}, + LineColFun{8, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_05_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_06) { std::set GroundTruth; - GroundTruth.emplace("main", 19, "retval", std::set{"5"}); - GroundTruth.emplace("main", 19, "i", std::set{"15", "6", "13"}); - GroundTruth.emplace("main", 19, "j", std::set{"15", "6", "13"}); - GroundTruth.emplace("main", 19, "k", std::set{"6"}); - GroundTruth.emplace("main", 19, "p", - std::set{"1", "2", "9", "11"}); - doAnalysisAndCompareResults("basic_06_cpp.ll", {"main"}, GroundTruth, true); + auto Main19 = LineColFun{14, 3, "main"}; + + GroundTruth.emplace(Main19, "i", + TaintSetT{ + LineColFun{6, 7, "main"}, + LineColFun{13, 8, "main"}, + LineColFun{13, 6, "main"}, + }); + GroundTruth.emplace(Main19, "j", + TaintSetT{ + LineColFun{6, 7, "main"}, + LineColFun{13, 8, "main"}, + LineColFun{13, 6, "main"}, + }); + GroundTruth.emplace(Main19, "k", + TaintSetT{ + LineColFun{6, 7, "main"}, + }); + GroundTruth.emplace(Main19, "p", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{9, 7, "main"}, + LineColFun{11, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_06_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_07) { std::set GroundTruth; - GroundTruth.emplace("main", 15, "retval", std::set{"5"}); - GroundTruth.emplace("main", 15, "argc.addr", std::set{"6"}); - GroundTruth.emplace("main", 15, "argv.addr", std::set{"7"}); - GroundTruth.emplace("main", 15, "i", std::set{"12"}); - GroundTruth.emplace("main", 15, "j", - std::set{"8", "9", "10", "11"}); - doAnalysisAndCompareResults("basic_07_cpp.ll", {"main"}, GroundTruth, false); + auto Main15 = LineColFun{5, 3, "main"}; + + GroundTruth.emplace(Main15, "argc", + TaintSetT{ + LineColFun{1, 14, "main"}, + }); + GroundTruth.emplace(Main15, "argv", + TaintSetT{ + LineColFun{1, 27, "main"}, + }); + // strong update on i + GroundTruth.emplace(Main15, "i", + TaintSetT{ + LineColFun{4, 5, "main"}, + }); + GroundTruth.emplace(Main15, "j", + TaintSetT{ + LineColFun{2, 7, "main"}, + LineColFun{3, 11, "main"}, + LineColFun{3, 13, "main"}, + LineColFun{3, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_07_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_08) { std::set GroundTruth; - GroundTruth.emplace("main", 12, "retval", std::set{"2"}); - GroundTruth.emplace("main", 12, "i", std::set{"9"}); - doAnalysisAndCompareResults("basic_08_cpp.ll", {"main"}, GroundTruth, false); + auto Main12 = LineColFun{11, 3, "main"}; + + // strong update on i + GroundTruth.emplace(Main12, "i", + TaintSetT{ + LineColFun{10, 5, "main"}, + }); + + doAnalysisAndCompareResults("basic_08_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_09) { std::set GroundTruth; - GroundTruth.emplace("main", 10, "i", std::set{"4"}); - GroundTruth.emplace("main", 10, "j", std::set{"4", "6", "7"}); - GroundTruth.emplace("main", 10, "retval", std::set{"3"}); - doAnalysisAndCompareResults("basic_09_cpp.ll", {"main"}, GroundTruth, false); + auto Main10 = LineColFun{6, 3, "main"}; + + GroundTruth.emplace(Main10, "i", + TaintSetT{ + LineColFun{3, 7, "main"}, + }); + GroundTruth.emplace(Main10, "j", + TaintSetT{ + LineColFun{3, 7, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{5, 5, "main"}, + }); + + doAnalysisAndCompareResults("basic_09_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_10) { std::set GroundTruth; - GroundTruth.emplace("main", 6, "i", std::set{"3"}); - GroundTruth.emplace("main", 6, "retval", std::set{"2"}); - doAnalysisAndCompareResults("basic_10_cpp.ll", {"main"}, GroundTruth, false); + auto Main6 = LineColFun{4, 3, "main"}; + GroundTruth.emplace(Main6, "i", + TaintSetT{ + LineColFun{3, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_10_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleBasicTest_11) { std::set GroundTruth; - GroundTruth.emplace("main", 20, "FeatureSelector", - std::set{"5", "7", "8"}); - GroundTruth.emplace("main", 20, "retval", std::set{"11", "16"}); - doAnalysisAndCompareResults("basic_11_cpp.ll", {"main"}, GroundTruth, false); + auto Main20 = RetStmt{"main"}; + + GroundTruth.emplace(Main20, "FeatureSelector", + TaintSetT{ + LineColFun{3, 14, "main"}, + LineColFun{4, 25, "main"}, + LineColFun{4, 7, "main"}, + }); + + GroundTruth.emplace(Main20, RetVal{"main"}, + TaintSetT{ + LineColFun{7, 5, "main"}, + LineColFun{15, 3, "main"}, + LineColFun{16, 1, "main"}, + }); + + doAnalysisAndCompareResults("basic_11_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleCallTest_01) { std::set GroundTruth; - GroundTruth.emplace("main", 14, "retval", std::set{"8"}); - GroundTruth.emplace("main", 14, "i", std::set{"9"}); - GroundTruth.emplace("main", 14, "j", - std::set{"12", "9", "10", "11"}); - GroundTruth.emplace( - "main", 14, "k", - std::set{"15", "1", "2", "13", "14", "12", "9", "10", "11"}); - doAnalysisAndCompareResults("call_01_cpp.ll", {"main"}, GroundTruth, false); + auto Main14 = RetStmt{"main"}; + + GroundTruth.emplace(Main14, "i", + TaintSetT{ + LineColFun{4, 7, "main"}, + }); + GroundTruth.emplace(Main14, "j", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 11, "main"}, + LineColFun{5, 13, "main"}, + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main14, "k", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 11, "main"}, + LineColFun{5, 13, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{6, 7, "main"}, + LineColFun{6, 11, "main"}, + LineColFun{6, 14, "main"}, + LineColFun{1, 12, "_Z2idi"}, + LineColFun{1, 24, "_Z2idi"}, + }); + + doAnalysisAndCompareResults("call_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleCallTest_02) { std::set GroundTruth; - GroundTruth.emplace("main", 13, "retval", std::set{"12"}); - GroundTruth.emplace("main", 13, "i", std::set{"13"}); - GroundTruth.emplace("main", 13, "j", std::set{"14"}); - GroundTruth.emplace("main", 13, "k", - std::set{"4", "5", "15", "6", "3", "14", "2", - "13", "16", "17", "18"}); - doAnalysisAndCompareResults("call_02_cpp.ll", {"main"}, GroundTruth, false); + auto Main13 = RetStmt{"main"}; + + GroundTruth.emplace(Main13, "i", + TaintSetT{ + LineColFun{4, 7, "main"}, + }); + GroundTruth.emplace(Main13, "j", + TaintSetT{ + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main13, "k", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{6, 15, "main"}, + LineColFun{6, 18, "main"}, + LineColFun{6, 11, "main"}, + LineColFun{6, 7, "main"}, + LineColFun{1, 13, "_Z3sumii"}, + LineColFun{1, 20, "_Z3sumii"}, + LineColFun{1, 32, "_Z3sumii"}, + LineColFun{1, 36, "_Z3sumii"}, + LineColFun{1, 34, "_Z3sumii"}, + }); + + doAnalysisAndCompareResults("call_02_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleCallTest_03) { std::set GroundTruth; - GroundTruth.emplace("main", 10, "retval", std::set{"20"}); - GroundTruth.emplace("main", 10, "i", std::set{"21"}); - GroundTruth.emplace("main", 10, "j", - std::set{"22", "23", "15", "6", "21", "2", - "13", "8", "9", "11", "12", "10", - "24"}); - doAnalysisAndCompareResults("call_03_cpp.ll", {"main"}, GroundTruth, false); + auto Main10 = RetStmt{"main"}; + + GroundTruth.emplace(Main10, "i", + TaintSetT{ + LineColFun{9, 7, "main"}, + }); + GroundTruth.emplace(Main10, "j", + TaintSetT{ + LineColFun{9, 7, "main"}, + LineColFun{10, 21, "main"}, + LineColFun{6, 1, "_Z9factorialj"}, + LineColFun{3, 5, "_Z9factorialj"}, + LineColFun{9, 7, "main"}, + LineColFun{1, 29, "_Z9factorialj"}, + LineColFun{5, 3, "_Z9factorialj"}, + LineColFun{5, 10, "_Z9factorialj"}, + LineColFun{5, 14, "_Z9factorialj"}, + LineColFun{5, 24, "_Z9factorialj"}, + LineColFun{5, 12, "_Z9factorialj"}, + LineColFun{5, 26, "_Z9factorialj"}, + LineColFun{10, 11, "main"}, + LineColFun{10, 7, "main"}, + }); + + doAnalysisAndCompareResults("call_03_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleCallTest_04) { std::set GroundTruth; - GroundTruth.emplace("main", 20, "retval", std::set{"33"}); - GroundTruth.emplace("main", 20, "i", std::set{"34"}); - GroundTruth.emplace("main", 20, "j", - std::set{"15", "6", "2", "13", "8", "9", - "11", "12", "10", "35", "36", "34", - "37"}); - GroundTruth.emplace("main", 20, "k", - std::set{"41", "19", "15", "6", "44", "2", - "13", "8", "45", "18", "9", "11", - "12", "10", "46", "24", "25", "35", - "36", "27", "23", "26", "38", "34", - "37", "42", "43", "39", "40"}); - doAnalysisAndCompareResults("call_04_cpp.ll", {"main"}, GroundTruth, false); + auto Main10 = RetStmt{"main"}; + + GroundTruth.emplace(Main10, "i", + TaintSetT{ + LineColFun{13, 7, "main"}, + }); + GroundTruth.emplace(Main10, "j", + TaintSetT{ + LineColFun{6, 1, "_Z9factorialj"}, + LineColFun{3, 5, "_Z9factorialj"}, + LineColFun{1, 29, "_Z9factorialj"}, + LineColFun{5, 3, "_Z9factorialj"}, + LineColFun{5, 10, "_Z9factorialj"}, + LineColFun{5, 14, "_Z9factorialj"}, + LineColFun{5, 24, "_Z9factorialj"}, + LineColFun{5, 12, "_Z9factorialj"}, + LineColFun{5, 26, "_Z9factorialj"}, + LineColFun{14, 21, "main"}, + LineColFun{13, 7, "main"}, + LineColFun{14, 7, "main"}, + LineColFun{14, 11, "main"}, + }); + GroundTruth.emplace(Main10, "k", + TaintSetT{ + LineColFun{16, 12, "main"}, + LineColFun{8, 24, "_Z2idi"}, + LineColFun{6, 1, "_Z9factorialj"}, + LineColFun{3, 5, "_Z9factorialj"}, + LineColFun{16, 5, "main"}, + LineColFun{1, 29, "_Z9factorialj"}, + LineColFun{5, 3, "_Z9factorialj"}, + LineColFun{5, 10, "_Z9factorialj"}, + LineColFun{5, 14, "_Z9factorialj"}, + LineColFun{16, 5, "main"}, + LineColFun{8, 12, "_Z2idi"}, + LineColFun{5, 24, "_Z9factorialj"}, + LineColFun{5, 12, "_Z9factorialj"}, + LineColFun{5, 26, "_Z9factorialj"}, + LineColFun{16, 12, "main"}, + LineColFun{10, 20, "_Z3sumii"}, + LineColFun{10, 32, "_Z3sumii"}, + LineColFun{14, 11, "main"}, + LineColFun{14, 21, "main"}, + LineColFun{10, 34, "_Z3sumii"}, + LineColFun{10, 36, "_Z3sumii"}, + LineColFun{10, 13, "_Z3sumii"}, + LineColFun{15, 11, "main"}, + LineColFun{15, 14, "main"}, + LineColFun{13, 7, "main"}, + LineColFun{14, 7, "main"}, + LineColFun{16, 8, "main"}, + LineColFun{16, 15, "main"}, + LineColFun{15, 7, "main"}, + }); + + doAnalysisAndCompareResults("call_04_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleCallTest_05) { std::set GroundTruth; - GroundTruth.emplace("main", 10, "retval", std::set{"8"}); - GroundTruth.emplace("main", 10, "i", std::set{"3", "11", "9"}); - GroundTruth.emplace("main", 10, "j", std::set{"3", "10", "12"}); - doAnalysisAndCompareResults("call_05_cpp.ll", {"main"}, GroundTruth, false); + auto Main10 = RetStmt{"main"}; + + GroundTruth.emplace(Main10, "i", + TaintSetT{ + LineColFun{2, 38, "_Z18setValueToFortyTwoPi"}, + LineColFun{7, 3, "main"}, + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main10, "j", + TaintSetT{ + LineColFun{2, 38, "_Z18setValueToFortyTwoPi"}, + LineColFun{6, 7, "main"}, + LineColFun{8, 3, "main"}, + }); + + doAnalysisAndCompareResults("call_05_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleCallTest_06) { // NOTE: Here we are suffering from IntraProceduralAliasesOnly std::set GroundTruth; - GroundTruth.emplace("main", 24, "retval", std::set{"11"}); - GroundTruth.emplace( - "main", 24, "i", - std::set{"3", "1", "2", "16", "17", "18", "12"}); - GroundTruth.emplace( - "main", 24, "j", - std::set{"19", "20", "21", "3", "1", "2", "13"}); - GroundTruth.emplace( - "main", 24, "k", - std::set{"22", "23", "3", "14", "1", "2", "24"}); - GroundTruth.emplace( - "main", 24, "l", - std::set{"15", "3", "1", "2", "25", "26", "27"}); - doAnalysisAndCompareResults("call_06_cpp.ll", {"main"}, GroundTruth, false); + auto Main24 = RetStmt{"main"}; + + GroundTruth.emplace(Main24, "i", + TaintSetT{ + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{2, 19, "_Z9incrementi"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{9, 17, "main"}, + LineColFun{9, 5, "main"}, + LineColFun{9, 7, "main"}, + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main24, "j", + TaintSetT{ + LineColFun{10, 7, "main"}, + LineColFun{10, 17, "main"}, + LineColFun{10, 5, "main"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{2, 19, "_Z9incrementi"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{6, 7, "main"}, + }); + GroundTruth.emplace(Main24, "k", + TaintSetT{ + LineColFun{11, 17, "main"}, + LineColFun{11, 7, "main"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{7, 7, "main"}, + LineColFun{2, 19, "_Z9incrementi"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{11, 5, "main"}, + }); + GroundTruth.emplace(Main24, "l", + TaintSetT{ + LineColFun{8, 7, "main"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{2, 19, "_Z9incrementi"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{12, 7, "main"}, + LineColFun{12, 17, "main"}, + LineColFun{12, 5, "main"}, + }); + + doAnalysisAndCompareResults("call_06_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleCallTest_07) { std::set GroundTruth; - GroundTruth.emplace("main", 6, "retval", std::set{"7"}); - GroundTruth.emplace("main", 6, "VarIR", std::set{"6", "3", "8"}); - doAnalysisAndCompareResults("call_07_cpp.ll", {"main"}, GroundTruth, false); + auto Main6 = RetStmt{"main"}; + + GroundTruth.emplace(Main6, "VarIR", + TaintSetT{ + LineColFun{7, 7, "main"}, + LineColFun{3, 6, "_Z13inputRefParamRi"}, + LineColFun{8, 3, "main"}, + }); + doAnalysisAndCompareResults("call_07_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleGlobalTest_01) { std::set GroundTruth; - GroundTruth.emplace("main", 9, "retval", std::set{"3"}); - GroundTruth.emplace("main", 9, "i", std::set{"7"}); - GroundTruth.emplace("main", 9, "j", std::set{"0", "5", "6"}); - doAnalysisAndCompareResults("global_01_cpp.ll", {"main"}, GroundTruth, false); + auto Main9 = RetStmt{"main"}; + + GroundTruth.emplace(Main9, "i", + TaintSetT{ + LineColFun{6, 5, "main"}, + }); + GroundTruth.emplace(Main9, "j", + TaintSetT{ + GlobalVar{"i"}, + LineColFun{5, 7, "main"}, + LineColFun{5, 5, "main"}, + }); + + doAnalysisAndCompareResults("global_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleGlobalTest_02) { std::set GroundTruth; - GroundTruth.emplace("_Z5initBv", 2, "a", std::set{"0"}); - GroundTruth.emplace("_Z5initBv", 2, "b", std::set{"2"}); - GroundTruth.emplace("main", 12, "a", std::set{"0"}); - GroundTruth.emplace("main", 12, "b", std::set{"2"}); - GroundTruth.emplace("main", 12, "retval", std::set{"6"}); - GroundTruth.emplace("main", 12, "c", std::set{"1", "8", "7"}); - doAnalysisAndCompareResults("global_02_cpp.ll", {"main"}, GroundTruth, false); + + auto Main12 = RetStmt{"main"}; + auto Init2 = RetStmt{"_Z5initBv"}; + + GroundTruth.emplace(Init2, "a", + TaintSetT{ + GlobalVar{"a"}, + }); + GroundTruth.emplace(Init2, "b", + TaintSetT{ + LineColFun{4, 18, "_Z5initBv"}, + }); + + GroundTruth.emplace(Main12, "a", + TaintSetT{ + GlobalVar{"a"}, + }); + GroundTruth.emplace(Main12, "b", + TaintSetT{ + LineColFun{4, 18, "_Z5initBv"}, + }); + GroundTruth.emplace(Main12, "c", + TaintSetT{ + GlobalVar{"b"}, + LineColFun{7, 7, "main"}, + LineColFun{7, 11, "main"}, + }); + + doAnalysisAndCompareResults("global_02_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleGlobalTest_03) { std::set GroundTruth; - GroundTruth.emplace("main", 1, "GlobalFeature", std::set{"0"}); - GroundTruth.emplace("main", 2, "GlobalFeature", std::set{"0"}); - GroundTruth.emplace("main", 17, "GlobalFeature", std::set{"0"}); - doAnalysisAndCompareResults("global_03_cpp.ll", {"main"}, GroundTruth, false); + GroundTruth.emplace(LineColFun{6, 11, "main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(LineColFun{6, 25, "main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(RetStmt{"main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + + doAnalysisAndCompareResults("global_03_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleGlobalTest_04) { std::set GroundTruth; - GroundTruth.emplace("main", 1, "GlobalFeature", std::set{"0"}); - GroundTruth.emplace("main", 2, "GlobalFeature", std::set{"0"}); - GroundTruth.emplace("main", 17, "GlobalFeature", std::set{"0"}); - GroundTruth.emplace("_Z7doStuffi", 1, "GlobalFeature", - std::set{"0"}); - GroundTruth.emplace("_Z7doStuffi", 2, "GlobalFeature", - std::set{"0"}); - doAnalysisAndCompareResults("global_04_cpp.ll", {"main", "_Z7doStuffi"}, + GroundTruth.emplace(LineColFun{8, 11, "main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(LineColFun{8, 25, "main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(RetStmt{"main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(LineColFun{3, 31, "_Z7doStuffi"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(LineColFun{3, 22, "_Z7doStuffi"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + + doAnalysisAndCompareResults("global_04_cpp_dbg.ll", {"main", "_Z7doStuffi"}, GroundTruth, false); } -TEST_F(IDEFeatureTaintAnalysisTest, HandleGlobalTest_05) { - std::set GroundTruth; - - // NOTE: Facts at init() should be empty, except for its own ID; - // g should be strongly updated - - GroundTruth.emplace("main", 1, "g", std::set{"0"}); - GroundTruth.emplace("main", 2, "g", std::set{"2"}); - GroundTruth.emplace("main", 4, "call", - std::set{"2", "4", "7", "8"}); - GroundTruth.emplace("main", 4, "g", std::set{"2"}); - - doAnalysisAndCompareResults("global_05_cpp.ll", {"main"}, GroundTruth, true); -} TEST_F(IDEFeatureTaintAnalysisTest, KillTest_01) { std::set GroundTruth; - GroundTruth.emplace("main", 12, "retval", std::set{"4"}); - GroundTruth.emplace("main", 12, "i", std::set{"5"}); - GroundTruth.emplace("main", 12, "j", std::set{"10"}); - GroundTruth.emplace("main", 12, "k", std::set{"9", "8", "5"}); - doAnalysisAndCompareResults("KillTest_01_cpp.ll", {"main"}, GroundTruth, + auto Main12 = RetStmt{"main"}; + + GroundTruth.emplace(Main12, "i", + TaintSetT{ + LineColFun{2, 7, "main"}, + }); + GroundTruth.emplace(Main12, "j", + TaintSetT{ + LineColFun{5, 5, "main"}, + }); + GroundTruth.emplace(Main12, "k", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{4, 11, "main"}, + LineColFun{2, 7, "main"}, + }); + + doAnalysisAndCompareResults("KillTest_01_cpp_dbg.ll", {"main"}, GroundTruth, false); } TEST_F(IDEFeatureTaintAnalysisTest, KillTest_02) { std::set GroundTruth; - GroundTruth.emplace("main", 12, "retval", std::set{"6"}); - GroundTruth.emplace("main", 12, "A", std::set{"0"}); - GroundTruth.emplace("main", 12, "B", std::set{"2"}); - GroundTruth.emplace("main", 12, "C", std::set{"1", "7", "8"}); - doAnalysisAndCompareResults("KillTest_02_cpp.ll", {"main"}, GroundTruth, + auto Main12 = RetStmt{"main"}; + + GroundTruth.emplace(Main12, "A", + TaintSetT{ + GlobalVar{"A"}, + }); + GroundTruth.emplace(Main12, "B", + TaintSetT{ + LineColFun{4, 18, "_Z5initBv"}, + }); + GroundTruth.emplace(Main12, "C", + TaintSetT{ + GlobalVar{"B"}, + LineColFun{7, 11, "main"}, + LineColFun{7, 7, "main"}, + }); + + doAnalysisAndCompareResults("KillTest_02_cpp_dbg.ll", {"main"}, GroundTruth, false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleReturnTest_01) { std::set GroundTruth; - GroundTruth.emplace("main", 6, "retval", std::set{"3"}); - GroundTruth.emplace("main", 6, "localVar", std::set{"4"}); - GroundTruth.emplace("main", 6, "call", std::set{"0", "5"}); - GroundTruth.emplace("main", 8, "localVar", - std::set{"0", "5", "6"}); - GroundTruth.emplace("main", 8, "call", std::set{"0", "5"}); - doAnalysisAndCompareResults("return_01_cpp.ll", {"main"}, GroundTruth, false); + auto Main6 = LineColFun{7, 12, "main"}; + auto Main8 = RetStmt{"main"}; + + GroundTruth.emplace(Main6, "localVar", + TaintSetT{ + LineColFun{6, 12, "main"}, + }); + GroundTruth.emplace(Main8, "localVar", + TaintSetT{ + LineColFun{2, 30, "_Z20returnIntegerLiteralv"}, + LineColFun{7, 14, "main"}, + LineColFun{7, 12, "main"}, + }); + + doAnalysisAndCompareResults("return_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEFeatureTaintAnalysisTest, HandleHeapTest_01) { std::set GroundTruth; - GroundTruth.emplace("main", 17, "retval", std::set{"3"}); - GroundTruth.emplace("main", 17, "i", std::set{"5", "6"}); - GroundTruth.emplace("main", 17, "j", - std::set{"5", "6", "7", "8", "9"}); - doAnalysisAndCompareResults("heap_01_cpp.ll", {"main"}, GroundTruth, false); -} -PHASAR_SKIP_TEST(TEST_F(IDEFeatureTaintAnalysisTest, HandleRVOTest_01) { - GTEST_SKIP() << "This test heavily depends on the used stdlib version. TODO: " - "add a better one"; + auto Main17 = RetStmt{"main"}; + GroundTruth.emplace(Main17, "i", + TaintSetT{ + LineColFun{3, 12, "main"}, + LineColFun{3, 8, "main"}, + }); + GroundTruth.emplace(Main17, "j", + TaintSetT{ + LineColFun{3, 12, "main"}, + LineColFun{3, 8, "main"}, + LineColFun{4, 12, "main"}, + LineColFun{4, 11, "main"}, + LineColFun{4, 7, "main"}, + }); + + doAnalysisAndCompareResults("heap_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); +} - std::set GroundTruth; - GroundTruth.emplace("main", 16, "retval", std::set{"75", "76"}); - GroundTruth.emplace("main", 16, "str", - std::set{"70", "65", "72", "74", "77"}); - GroundTruth.emplace("main", 16, "ref.tmp", - std::set{"66", "9", "72", "73", "71"}); - doAnalysisAndCompareResults("rvo_01_cpp.ll", {"main"}, GroundTruth, false); -}) - -PHASAR_SKIP_TEST(TEST_F(IDEFeatureTaintAnalysisTest, HandleRVOTest_02) { - GTEST_SKIP() << "This test heavily depends on the used stdlib version. TODO: " - "add a better one"; +// PHASAR_SKIP_TEST(TEST_F(IDEFeatureTaintAnalysisTest, HandleRVOTest_02) { +// GTEST_SKIP() << "This test heavily depends on the used stdlib version. +// TODO: " +// "add a better one"; - std::set GroundTruth; - GroundTruth.emplace("main", 18, "retval", std::set{"75", "76"}); - GroundTruth.emplace("main", 18, "str", - std::set{"70", "65", "72", "74", "77"}); - GroundTruth.emplace("main", 18, "ref.tmp", - std::set{"66", "9", "72", "73", "71"}); - doAnalysisAndCompareResults("rvo_02_cpp.ll", {"main"}, GroundTruth, true); -}) +// std::set GroundTruth; +// GroundTruth.emplace("main", 18, "retval", std::set{"75", +// "76"}); GroundTruth.emplace("main", 18, "str", +// std::set{"70", "65", "72", "74", "77"}); +// GroundTruth.emplace("main", 18, "ref.tmp", +// std::set{"66", "9", "72", "73", "71"}); +// doAnalysisAndCompareResults("rvo_02_cpp.ll", {"main"}, GroundTruth, true); +// }) TEST_F(IDEFeatureTaintAnalysisTest, HandleRVOTest_03) { std::set GroundTruth; - - GroundTruth.emplace( - "main", 19, "Str", - std::set{"39", "43", "46", "49", "51", "54", "63"}); - GroundTruth.emplace("main", 19, "ref.tmp", - std::set{"13", "19", "2", "20", "23", "24", - "25", "27", "29", "32", "40", "45", - "46", "47"}); - GroundTruth.emplace("main", 19, "ref.tmp1", - std::set{"1", "13", "19", "20", "23", "24", - "25", "27", "29", "32", "48", "49", - "50"}); - doAnalysisAndCompareResults("rvo_03_cpp.ll", {"main"}, GroundTruth, true); + auto Main19 = RetStmt{"main"}; + + GroundTruth.emplace(Main19, "Str", + TaintSetT{ + LineColFun{49, 10, "main"}, + LineColFun{49, 10, "main"}, + LineColFun{51, 7, "main"}, + LineColFun{52, 7, "main"}, + LineColFun{53, 14, "main"}, + LineColFun{54, 1, "main"}, + LineColFun{41, 10, "_ZN6StringC2Ev"}, + }); + + doAnalysisAndCompareResults("rvo_03_cpp_dbg.ll", {"main"}, GroundTruth, true); } TEST_F(IDEFeatureTaintAnalysisTest, HandleRVOTest_04) { std::set GroundTruth; - GroundTruth.emplace("main", 10, "retval", std::set{"14"}); - GroundTruth.emplace( - "main", 10, "F", - std::set{"12", "15", "16", "17", "2", "3", "9"}); - GroundTruth.emplace("main", 10, "ref.tmp", - std::set{"16", "17", "2", "3", "9"}); - doAnalysisAndCompareResults("rvo_04_cpp.ll", {"main"}, GroundTruth, true); + auto Main10 = RetStmt{"main"}; + + GroundTruth.emplace(Main10, "F", + TaintSetT{ + LineColFun{17, 7, "main"}, + LineColFun{17, 7, "main"}, + LineColFun{18, 7, "main"}, + LineColFun{18, 5, "main"}, + LineColFun{14, 26, "_Z9createFoov"}, + LineColFun{14, 26, "_Z9createFoov"}, + LineColFun{7, 7, "_ZN3FooC2Ev"}, + }); + + doAnalysisAndCompareResults("rvo_04_cpp_dbg.ll", {"main"}, GroundTruth, true); } } // namespace diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCATest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCATest.cpp index d81885c43f..d4e958248a 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCATest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCATest.cpp @@ -11,6 +11,7 @@ #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h" #include "phasar/PhasarLLVM/HelperAnalyses.h" #include "phasar/PhasarLLVM/Passes/ValueAnnotationPass.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" @@ -19,19 +20,25 @@ #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Operator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include "SourceMapping.h" +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" -#include #include using namespace psr; using namespace psr::glca; -using groundTruth_t = - std::tuple; +using l_t = IDEGeneralizedLCA::l_t; +using groundTruth_t = std::tuple; /* ============== TEST FIXTURE ============== */ @@ -68,127 +75,171 @@ class IDEGeneralizedLCATest : public ::testing::Test { /// \brief compares the computed results with every given tuple (value, /// alloca, inst) void compareResults(const std::vector &Expected) { - for (const auto &[EVal, VrId, InstId] : Expected) { - const auto *Vr = HA->getProjectIRDB().getInstruction(VrId); - const auto *Inst = HA->getProjectIRDB().getInstruction(InstId); - ASSERT_NE(nullptr, Vr); - ASSERT_NE(nullptr, Inst); - auto Result = LCASolver->resultAt(Inst, Vr); - - EXPECT_EQ(EVal, Result) << "vr:" << VrId << " inst:" << InstId - << " Expected: " << EVal << " Got:" << Result; + for (const auto &[EVal, VarLoc, InstLoc] : Expected) { + const auto *Var = testingLocInIR(VarLoc, HA->getProjectIRDB()); + const auto *Inst = llvm::dyn_cast_if_present( + testingLocInIR(InstLoc, HA->getProjectIRDB())); + + ASSERT_TRUE(Var) << "Cannot map location " << VarLoc.str() << " to LLVM"; + ASSERT_TRUE(Inst) << "Cannot map location " << InstLoc.str() + << " to LLVM"; + + auto Result = LCASolver->resultAt(Inst, Var); + EXPECT_EQ(EVal, Result) + << "At VarLoc: " << VarLoc.str() << ", InstLoc: " << InstLoc.str() + << ";\n aka. Var: " << llvmIRToString(Var) + << "; Inst: " << llvmIRToString(Inst) << ":\n Expected: " << EVal + << " Got:" << LToString(Result); } } }; // class Fixture TEST_F(IDEGeneralizedLCATest, SimpleTest) { - initialize("SimpleTest_c.ll"); + initialize("SimpleTest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue(10)}, 3, 20}); - GroundTruth.push_back({{EdgeValue(15)}, 4, 20}); + + GroundTruth.emplace_back(l_t{EdgeValue(10)}, LineColFun{4, 0, "main"}, + LineColFun{7, 3, "main"}); + GroundTruth.emplace_back(l_t{EdgeValue(15)}, LineColFun{5, 0, "main"}, + LineColFun{7, 3, "main"}); + compareResults(GroundTruth); } - TEST_F(IDEGeneralizedLCATest, BranchTest) { - initialize("BranchTest_c.ll"); + initialize("BranchTest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue(25), EdgeValue(43)}, 3, 22}); - GroundTruth.push_back({{EdgeValue(24)}, 4, 22}); + + GroundTruth.push_back( + {{EdgeValue(25)}, LineColFun{7, 11, "main"}, LineColFun{8, 3, "main"}}); + GroundTruth.push_back( + {{EdgeValue(24)}, LineColFun{7, 9, "main"}, LineColFun{8, 3, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, FPtest) { - initialize("FPtest_c.ll"); - + initialize("FPtest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue(4.5)}, 1, 16}); - GroundTruth.push_back({{EdgeValue(2.0)}, 2, 16}); + + GroundTruth.push_back( + {{EdgeValue(4.5)}, LineColFun{4, 9, "main"}, LineColFun{6, 3, "main"}}); + GroundTruth.push_back( + {{EdgeValue(2.0)}, LineColFun{5, 9, "main"}, LineColFun{6, 3, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, StringTest) { - initialize("StringTest_c.ll"); + initialize("StringTest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue("Hello, World")}, 2, 8}); - GroundTruth.push_back({{EdgeValue("Hello, World")}, 3, 8}); + + GroundTruth.push_back({{EdgeValue("Hello, World")}, + LineColFun{4, 0, "main"}, + LineColFun{7, 3, "main"}}); + GroundTruth.push_back({{EdgeValue("Hello, World")}, + LineColFun{5, 0, "main"}, + LineColFun{7, 3, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, StringBranchTest) { - initialize("StringBranchTest_c.ll"); + initialize("StringBranchTest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back( - {{EdgeValue("Hello, World"), EdgeValue("Hello Hello")}, 3, 15}); - GroundTruth.push_back({{EdgeValue("Hello Hello")}, 4, 15}); + + GroundTruth.push_back({{EdgeValue("Hello Hello"), EdgeValue("Hello, World")}, + LineColFun{5, 15, "main"}, + LineColFun{10, 3, "main"}}); + GroundTruth.push_back({{EdgeValue("Hello Hello")}, + LineColFun{6, 15, "main"}, + LineColFun{10, 3, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, StringTestCpp) { - initialize("StringTest_cpp.ll"); + initialize("StringTest_cpp_dbg.ll"); std::vector GroundTruth; - const auto *LastMainInstruction = - getLastInstructionOf(HA->getProjectIRDB().getFunction("main")); + GroundTruth.push_back({{EdgeValue("Hello, World")}, - 7, - static_cast( - std::stoi(getMetaDataID(LastMainInstruction)))}); + LineColFun{4, 15, "main"}, + LineColFun{6, 1, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, FloatDivisionTest) { - initialize("FloatDivision_c.ll"); + initialize("FloatDivision_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue(nullptr)}, 1, 24}); // i - GroundTruth.push_back({{EdgeValue(1.0)}, 2, 24}); // j - GroundTruth.push_back({{EdgeValue(-7.0)}, 3, 24}); // k + + GroundTruth.push_back( + {{EdgeValue(1.0)}, LineColFun{5, 9, "main"}, LineColFun{8, 3, "main"}}); + GroundTruth.push_back({{EdgeValue(nullptr)}, + LineColFun{6, 9, "main"}, + LineColFun{8, 3, "main"}}); + GroundTruth.push_back( + {{EdgeValue(-7.0)}, LineColFun{7, 9, "main"}, LineColFun{8, 3, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, SimpleFunctionTest) { - initialize("SimpleFunctionTest_c.ll"); + initialize("SimpleFunctionTest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue(48)}, 10, 31}); // i - GroundTruth.push_back({{EdgeValue(nullptr)}, 11, 31}); // j + + GroundTruth.push_back( + {{EdgeValue(48)}, LineColFun{8, 7, "main"}, LineColFun{10, 3, "main"}}); + GroundTruth.push_back({{EdgeValue(nullptr)}, + LineColFun{9, 7, "main"}, + LineColFun{10, 3, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, GlobalVariableTest) { - initialize("GlobalVariableTest_c.ll"); + initialize("GlobalVariableTest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue(50)}, 7, 13}); // i - GroundTruth.push_back({{EdgeValue(8)}, 10, 13}); // j + + GroundTruth.push_back( + {{EdgeValue(50)}, LineColFun{4, 13, "main"}, LineColFun{6, 3, "main"}}); + GroundTruth.push_back( + {{EdgeValue(8)}, LineColFun{5, 13, "main"}, LineColFun{6, 3, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, Imprecision) { - initialize("Imprecision_c.ll"); - // auto xInst = IRDB->getInstruction(0); // foo.x - // auto yInst = IRDB->getInstruction(1); // foo.y - // auto barInst = IRDB->getInstruction(7); + initialize("Imprecision_c_dbg.ll"); + std::vector GroundTruth; - // llvm::outs() << "foo.x = " << LCASolver->resultAt(barInst, xInst) << - // std::endl; llvm::outs() << "foo.y = " << LCASolver->resultAt(barInst, - // yInst) - // << std::endl; + GroundTruth.push_back({{EdgeValue(1), EdgeValue(2)}, + LineColFun{3, 14, "foo"}, + LineColFun{3, 26, "foo"}}); + GroundTruth.push_back({{EdgeValue(2), EdgeValue(3)}, + LineColFun{3, 21, "foo"}, + LineColFun{3, 26, "foo"}}); - std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue(1), EdgeValue(2)}, 0, 7}); // i - GroundTruth.push_back({{EdgeValue(2), EdgeValue(3)}, 1, 7}); // j compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, ReturnConstTest) { - initialize("ReturnConstTest_c.ll"); + initialize("ReturnConstTest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue(43)}, 7, 8}); // i + + GroundTruth.push_back( + {{EdgeValue(43)}, LineColFun{6, 12, "main"}, LineColFun{6, 3, "main"}}); + compareResults(GroundTruth); } TEST_F(IDEGeneralizedLCATest, NullTest) { - initialize("NullTest_c.ll"); + initialize("NullTest_c_dbg.ll"); std::vector GroundTruth; - GroundTruth.push_back({{EdgeValue("")}, 4, 5}); // foo(null) + + GroundTruth.push_back( + {{EdgeValue("")}, LineColFun{1, 31, "foo"}, LineColFun{1, 24, "foo"}}); + compareResults(GroundTruth); } diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp index 59a474013b..f3c05879a0 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp @@ -10,6 +10,7 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h" #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/Domain/LatticeDomain.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/HelperAnalyses.h" @@ -18,35 +19,46 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/BitVectorSet.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/Printer.h" +#include "phasar/Utils/Utilities.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" #include #include +#include #include #include #include using namespace psr; +using TaintSetT = BitVectorSet; + /* ============== TEST FIXTURE ============== */ class IDEInstInteractionAnalysisTest : public ::testing::Test { protected: static constexpr auto PathToLlFiles = PHASAR_BUILD_SUBFOLDER("inst_interaction/"); + using VarNameT = std::variant; // Function - Line Nr - Variable - Values using IIACompactResult_t = - std::tuple::l_t>; + std::tuple::l_t>; std::optional HA; LLVMProjectIRDB *IRDB{}; @@ -60,6 +72,55 @@ class IDEInstInteractionAnalysisTest : public ::testing::Test { IRDB = &HA->getProjectIRDB(); } + [[nodiscard]] const llvm::Instruction *getInst(TestingSrcLocation Loc) { + const auto *Ret = llvm::dyn_cast_if_present( + testingLocInIR(Loc, HA->getProjectIRDB())); + if (!Ret) { + throw std::runtime_error("Cannot convert loc " + Loc.str() + " to LLVM"); + } + return Ret; + } + + [[nodiscard]] bool matchesVar(const llvm::Value *Fact, + const VarNameT &VarName) { + return std::visit( + psr::Overloaded{ + [&](const std::string &Name) { + if (!llvm::isa(Fact) && + !llvm::isa(Fact)) { + return false; + } + auto FactName = psr::getVarNameFromIR(Fact); + return FactName == Name; + }, + [&](RetVal R) { + return llvm::any_of(Fact->users(), [R](const auto *V) { + const auto *Ret = llvm::dyn_cast(V); + return Ret && Ret->getFunction()->getName() == R.InFunction; + }); + }, + }, + VarName); + } + [[nodiscard]] std::string printVar(const VarNameT &VarName) { + return std::visit(psr::Overloaded{ + [](const std::string &Name) { return Name; }, + [](RetVal R) { return R.str(); }, + }, + VarName); + } + [[nodiscard]] LatticeDomain> + sorted(const IDEInstInteractionAnalysisT::l_t &Values) { + if (const auto *Set = Values.getValueOrNull()) { + std::set Ret(Set->begin(), Set->end()); + return Ret; + } + if (Values.isBottom()) { + return Bottom{}; + } + return Top{}; + } + void doAnalysisAndCompareResults(const std::string &LlvmFilePath, const std::vector &EntryPoints, @@ -75,26 +136,37 @@ class IDEInstInteractionAnalysisTest : public ::testing::Test { // EntryPoints); assert(HA); auto IIAProblem = - createAnalysisProblem>( + createAnalysisProblem>( *HA, EntryPoints); - // use Phasar's instruction ids as testing labels + auto Generator = [](std::variant - Current) -> std::set { + Current) -> std::set { return std::visit( - [](const auto *InstOrGlob) -> std::set { - std::set Labels; - if (InstOrGlob->hasMetadata()) { - std::string Label = - llvm::cast( - InstOrGlob->getMetadata(PhasarConfig::MetaDataKind()) - ->getOperand(0)) - ->getString() - .str(); - Labels.insert(Label); - } - return Labels; - }, + psr::Overloaded{ + [](const llvm::GlobalVariable *Glob) + -> std::set { + std::set Labels; + Labels.insert(GlobalVar{Glob->getName()}); + return Labels; + }, + [](const llvm::Instruction *Inst) + -> std::set { + std::set Labels; + auto [Line, Col] = getLineAndColFromIR(Inst); + if (Col == 0 && llvm::isa(Inst)) { + std::tie(Line, Col) = getLineAndColFromIR(Inst->getOperand( + llvm::StoreInst::getPointerOperandIndex())); + } + if (Line != 0) { + Labels.insert(LineColFun{ + Line, + Col, + Inst->getFunction()->getName(), + }); + } + return Labels; + }}, Current); }; // register the above generator function @@ -105,49 +177,48 @@ class IDEInstInteractionAnalysisTest : public ::testing::Test { IIASolver.dumpResults(); } // do the comparison - for (const auto &[FunName, SrcLine, VarName, LatticeVal] : GroundTruth) { - const auto *Fun = IRDB->getFunctionDefinition(FunName); - const auto *IRLine = getNthInstruction(Fun, SrcLine); - auto ResultMap = IIASolver.resultsAt(IRLine); - assert(IRLine && "Could not retrieve IR line!"); + for (const auto &[InstLoc, VarName, ExpectedVal] : GroundTruth) { + // const auto *Fun = IRDB->getFunctionDefinition(FunName); + // const auto *IRLine = getNthInstruction(Fun, SrcLine); + const auto *IRLoc = testingLocInIR(InstLoc, *IRDB); + ASSERT_TRUE(IRLoc) << "Could not retrieve IR Loc: " << InstLoc.str(); + ASSERT_TRUE(llvm::isa(IRLoc)); + auto ResultMap = + IIASolver.resultsAt(llvm::cast(IRLoc)); bool FactFound = false; - for (auto &[Fact, Value] : ResultMap) { - std::string FactStr; - llvm::raw_string_ostream RSO(FactStr); - RSO << *Fact.getBase(); - llvm::StringRef FactRef(FactStr); - if (FactRef.ltrim().startswith("%" + VarName + " ") || - FactRef.ltrim().startswith("@" + VarName + " ")) { - PHASAR_LOG_LEVEL(DFADEBUG, "Checking variable: " << FactStr); - EXPECT_EQ(LatticeVal, Value); + for (auto &[Fact, ComputedVal] : ResultMap) { + if (matchesVar(Fact.getBase(), VarName)) { + EXPECT_EQ(sorted(ExpectedVal), sorted(ComputedVal)) + << "Unexpected taint-set at " << InstLoc << " for variable '" + << printVar(VarName) << "' (" << llvmIRToString(Fact.getBase()) + << ")"; FactFound = true; } } - if (!FactFound) { - PHASAR_LOG_LEVEL(DFADEBUG, "Variable '" << VarName << "' missing at '" - << llvmIRToString(IRLine) - << "'."); - } - EXPECT_TRUE(FactFound); + + EXPECT_TRUE(FactFound) + << "Variable '" << printVar(VarName) << "' missing at '" + << llvmIRToString(IRLoc) << "'."; } } - void TearDown() override {} + void TearDown() override { + BitVectorSet::clearPosition(); + } }; // Test Fixture TEST_F(IDEInstInteractionAnalysisTest, FieldSensArrayConstruction_01) { - initializeIR("array_01_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("array_01_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{2, 7, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; auto FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 13); + Inst = getInst(LineColFun{5, 3, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 16); + Inst = getInst(LineColFun{6, 3, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; @@ -155,21 +226,21 @@ TEST_F(IDEInstInteractionAnalysisTest, FieldSensArrayConstruction_01) { } TEST_F(IDEInstInteractionAnalysisTest, FieldSensArrayConstruction_02) { - initializeIR("array_02_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("array_02_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{2, 7, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; auto FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 3); + Inst = getInst(LineColFun{4, 7, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 5); + Inst = getInst(LineColFun{3, 3, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 6); + Inst = getInst(OperandOf{llvm::StoreInst::getPointerOperandIndex(), + LineColFun{3, 16, "main"}}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; @@ -177,21 +248,28 @@ TEST_F(IDEInstInteractionAnalysisTest, FieldSensArrayConstruction_02) { } TEST_F(IDEInstInteractionAnalysisTest, FieldSensArrayConstruction_03) { - initializeIR("array_03_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("array_03_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{2, 7, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; auto FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 5); + + auto Store = LineColFun{3, 19, "main"}; + auto LastGep = OperandOf{llvm::StoreInst::getPointerOperandIndex(), Store}; + auto FirstGep = LineColFun{3, 3, "main"}; + + Inst = getInst(FirstGep); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 6); + + const auto *LastGepInst = getInst(LastGep); + + Inst = llvm::cast(LastGepInst->getOperand(0)); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 7); + Inst = LastGepInst; llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; @@ -199,17 +277,16 @@ TEST_F(IDEInstInteractionAnalysisTest, FieldSensArrayConstruction_03) { } TEST_F(IDEInstInteractionAnalysisTest, FieldSensStructConstruction_01) { - initializeIR("struct_01_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("struct_01_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{8, 7, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; auto FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 14); + Inst = getInst(LineColFun{12, 5, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 17); + Inst = getInst(LineColFun{13, 5, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; @@ -217,21 +294,20 @@ TEST_F(IDEInstInteractionAnalysisTest, FieldSensStructConstruction_01) { } TEST_F(IDEInstInteractionAnalysisTest, FieldSensStructConstruction_02) { - initializeIR("struct_02_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("struct_02_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{12, 5, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; auto FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 6); + Inst = getInst(LineColFun{13, 5, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 7); + Inst = getInst(LineColFun{13, 7, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; - Inst = getNthInstruction(Main, 9); + Inst = getInst(LineColFun{14, 5, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << FlowFact << '\n'; @@ -239,87 +315,98 @@ TEST_F(IDEInstInteractionAnalysisTest, FieldSensStructConstruction_02) { } TEST_F(IDEInstInteractionAnalysisTest, ArrayEquality_01) { - initializeIR("array_01_cpp.ll"); + initializeIR("array_01_cpp_dbg.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + const auto *Inst = getInst(LineColFun{2, 7, "main"}); auto FlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, FlowFact); - Inst = getNthInstruction(Main, 4); + Inst = getInst(LineColFun{4, 7, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 13); + Inst = getInst(LineColFun{5, 3, "main"}); auto OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_NE(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 13); - FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 18); + Inst = getInst(LineColFun{7, 11, "main"}); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 16); + Inst = getInst(LineColFun{6, 3, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 21); + Inst = getInst(LineColFun{8, 11, "main"}); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); } TEST_F(IDEInstInteractionAnalysisTest, ArrayEquality_02) { - initializeIR("array_02_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("array_02_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{2, 7, "main"}); auto FlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, FlowFact); - Inst = getNthInstruction(Main, 5); + const auto *FirstGep = getInst(LineColFun{3, 3, "main"}); + Inst = FirstGep; FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 8); + Inst = getInst(LineColFun{4, 11, "main"}); auto OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 6); + const auto *SecondGep = getInst(OperandOf{ + llvm::StoreInst::getPointerOperandIndex(), LineColFun{3, 16, "main"}}); + Inst = SecondGep; FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 9); + Inst = llvm::cast( + getInst(LineColFunOp{4, 11, "main", llvm::Instruction::Load}) + ->getOperand(0)); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 5); + Inst = FirstGep; FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 6); + Inst = SecondGep; OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_NE(FlowFact, OtherFlowFact); } TEST_F(IDEInstInteractionAnalysisTest, ArrayEquality_03) { - initializeIR("array_03_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("array_03_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{2, 7, "main"}); auto FlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, FlowFact); - Inst = getNthInstruction(Main, 5); + Inst = getInst(LineColFun{3, 3, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 9); + Inst = getInst(LineColFun{4, 11, "main"}); auto OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 6); + const auto *GepStore = + llvm::cast(getInst(LineColFun{3, 19, "main"})); + const auto *GepLoad = + getInst(LineColFunOp{4, 11, "main", llvm::Instruction::Load}); + + Inst = llvm::cast( + llvm::cast(GepStore->getPointerOperand()) + ->getPointerOperand()); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 10); + Inst = llvm::cast( + llvm::cast(GepLoad->getOperand(0)) + ->getPointerOperand()); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 7); + Inst = llvm::cast(GepStore->getPointerOperand()); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 11); + Inst = llvm::cast(GepLoad->getOperand(0)); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 6); + Inst = llvm::cast( + llvm::cast(GepStore->getPointerOperand()) + ->getPointerOperand()); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 11); + Inst = llvm::cast(GepLoad->getOperand(0)); OtherFlowFact = IDEIIAFlowFact::create(Inst); // For K-limit of 2, this should be considered equal if (IDEIIAFlowFact::KLimit <= 2) { @@ -330,33 +417,32 @@ TEST_F(IDEInstInteractionAnalysisTest, ArrayEquality_03) { } TEST_F(IDEInstInteractionAnalysisTest, StructEquality_01) { - initializeIR("struct_01_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("struct_01_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{8, 7, "main"}); auto FlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, FlowFact); - Inst = getNthInstruction(Main, 14); + Inst = getInst(LineColFun{12, 5, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 22); + Inst = getInst(LineColFun{15, 13, "main"}); auto OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 17); + Inst = getInst(LineColFun{13, 5, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 25); + Inst = getInst(LineColFun{16, 13, "main"}); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 20); + Inst = getInst(LineColFun{14, 5, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 28); + Inst = getInst(LineColFun{17, 13, "main"}); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 17); + Inst = getInst(LineColFun{13, 5, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 20); + Inst = getInst(LineColFun{14, 5, "main"}); OtherFlowFact = IDEIIAFlowFact::create(Inst); llvm::outs() << "Compare:\n"; llvm::outs() << FlowFact << '\n'; @@ -366,40 +452,39 @@ TEST_F(IDEInstInteractionAnalysisTest, StructEquality_01) { } TEST_F(IDEInstInteractionAnalysisTest, StructEquality_02) { - initializeIR("struct_02_cpp.ll"); - const auto *Main = IRDB->getFunction("main"); - const auto *Inst = getNthInstruction(Main, 2); + initializeIR("struct_02_cpp_dbg.ll"); + const auto *Inst = getInst(LineColFun{12, 5, "main"}); auto FlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, FlowFact); - Inst = getNthInstruction(Main, 6); + Inst = getInst(LineColFun{13, 5, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 11); + Inst = getInst(LineColFun{15, 13, "main"}); auto OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 6); + Inst = getInst(LineColFun{13, 5, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 7); + Inst = getInst(LineColFun{13, 7, "main"}); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_NE(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 7); + Inst = getInst(LineColFun{13, 7, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 12); + Inst = getInst(LineColFun{15, 15, "main"}); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 9); + Inst = getInst(LineColFun{14, 5, "main"}); FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 15); + Inst = getInst(LineColFun{16, 13, "main"}); OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_EQ(FlowFact, OtherFlowFact); - Inst = getNthInstruction(Main, 6); + Inst = getInst(LineColFun{13, 5, "main"}); llvm::outs() << "Instruction to create flow fact from: " << *Inst << '\n'; FlowFact = IDEIIAFlowFact::create(Inst); - Inst = getNthInstruction(Main, 9); + Inst = getInst(LineColFun{14, 5, "main"}); llvm::outs() << "Instruction to create flow fact from 2: " << *Inst << '\n'; OtherFlowFact = IDEIIAFlowFact::create(Inst); ASSERT_NE(FlowFact, OtherFlowFact); @@ -426,454 +511,683 @@ TEST_F(IDEInstInteractionAnalysisTest, StructEquality_02) { TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_01) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 9, "i", {"4"})); - GroundTruth.emplace( - std::tuple>( - "main", 9, "j", {"4", "5", "6", "7"})); - GroundTruth.emplace( - std::tuple>( - "main", 9, "retval", {"3"})); - doAnalysisAndCompareResults("basic_01_cpp.ll", {"main"}, GroundTruth, false); + auto Main9 = LineColFun{4, 3, "main"}; + GroundTruth.emplace(Main9, "i", TaintSetT{LineColFun{2, 7, "main"}}); + GroundTruth.emplace(Main9, "j", + TaintSetT{ + LineColFun{2, 7, "main"}, + LineColFun{3, 11, "main"}, + LineColFun{3, 13, "main"}, + LineColFun{3, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_02) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 24, "retval", {"6"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "argc.addr", {"7"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "argv.addr", {"8"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "i", {"16", "18"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "j", {"9", "10", "11", "12"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "k", {"21", "16", "18", "20"})); - doAnalysisAndCompareResults("basic_02_cpp.ll", {"main"}, GroundTruth, false); + auto Main24 = LineColFun{10, 3, "main"}; + + GroundTruth.emplace(Main24, "argc", TaintSetT{LineColFun{1, 14, "main"}}); + GroundTruth.emplace(Main24, "argv", TaintSetT{LineColFun{1, 27, "main"}}); + GroundTruth.emplace(Main24, "i", + TaintSetT{ + LineColFun{5, 7, "main"}, + LineColFun{7, 7, "main"}, + }); + GroundTruth.emplace(Main24, "j", + TaintSetT{ + LineColFun{2, 7, "main"}, + LineColFun{3, 11, "main"}, + LineColFun{3, 13, "main"}, + LineColFun{3, 7, "main"}, + }); + GroundTruth.emplace(Main24, "k", + TaintSetT{ + LineColFun{5, 7, "main"}, + LineColFun{7, 7, "main"}, + LineColFun{9, 11, "main"}, + LineColFun{9, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_02_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_03) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 20, "retval", {"3"})); - GroundTruth.emplace( - std::tuple>( - "main", 20, "i", {"4", "10", "11", "12"})); - GroundTruth.emplace( - std::tuple>( - "main", 20, "x", {"5", "14", "15", "16"})); - doAnalysisAndCompareResults("basic_03_cpp.ll", {"main"}, GroundTruth, false); -} - -PHASAR_SKIP_TEST(TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_04) { - // If we use libcxx this won't work since internal implementation is different + + auto Main20 = LineColFun{6, 3, "main"}; + + GroundTruth.emplace(Main20, "i", + TaintSetT{ + LineColFun{2, 7, "main"}, + LineColFun{4, 5, "main"}, + }); + GroundTruth.emplace(Main20, "x", + TaintSetT{ + LineColFun{3, 12, "main"}, + LineColFun{3, 28, "main"}, + }); + + doAnalysisAndCompareResults("basic_03_cpp_dbg.ll", {"main"}, GroundTruth, + false); +} + +TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_04) { + LIBCPP_GTEST_SKIP; std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 23, "retval", {"7"})); - GroundTruth.emplace( - std::tuple>( - "main", 23, "argc.addr", {"8"})); - GroundTruth.emplace( - std::tuple>( - "main", 23, "argv.addr", {"9"})); - GroundTruth.emplace( - std::tuple>( - "main", 23, "i", {"10"})); - GroundTruth.emplace( - std::tuple>( - "main", 23, "j", {"10", "11", "12", "13"})); - GroundTruth.emplace( - std::tuple>( - "main", 23, "k", {"10", "11", "12", "13", "14", "18", "19"})); - doAnalysisAndCompareResults("basic_04_cpp.ll", {"main"}, GroundTruth, false); -}) + auto Main23 = LineColFun{11, 3, "main"}; + + GroundTruth.emplace(Main23, "argc", + TaintSetT{ + LineColFun{3, 14, "main"}, + }); + GroundTruth.emplace(Main23, "argv", + TaintSetT{ + LineColFun{3, 27, "main"}, + }); + GroundTruth.emplace(Main23, "i", + TaintSetT{ + LineColFun{4, 7, "main"}, + }); + GroundTruth.emplace(Main23, "j", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 11, "main"}, + LineColFun{5, 13, "main"}, + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main23, "k", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 11, "main"}, + LineColFun{5, 13, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{6, 7, "main"}, + LineColFun{8, 9, "main"}, + LineColFun{8, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_04_cpp_dbg.ll", {"main"}, GroundTruth, + false); +} TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_05) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 11, "i", {"5", "7"})); - GroundTruth.emplace( - std::tuple>( - "main", 11, "retval", {"2"})); - doAnalysisAndCompareResults("basic_05_cpp.ll", {"main"}, GroundTruth, false); + auto Main11 = LineColFun{10, 3, "main"}; + GroundTruth.emplace(Main11, "i", + TaintSetT{ + LineColFun{6, 7, "main"}, + LineColFun{8, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_05_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_06) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 19, "retval", {"5"})); - GroundTruth.emplace( - std::tuple>( - "main", 19, "i", {"15", "6", "13"})); - GroundTruth.emplace( - std::tuple>( - "main", 19, "j", {"15", "6", "13"})); - GroundTruth.emplace( - std::tuple>( - "main", 19, "k", {"6"})); - GroundTruth.emplace( - std::tuple>( - "main", 19, "p", {"1", "2", "9", "11"})); - doAnalysisAndCompareResults("basic_06_cpp.ll", {"main"}, GroundTruth, false); + auto Main19 = LineColFun{14, 3, "main"}; + + GroundTruth.emplace(Main19, "i", + TaintSetT{ + LineColFun{6, 7, "main"}, + LineColFun{13, 8, "main"}, + LineColFun{13, 6, "main"}, + }); + GroundTruth.emplace(Main19, "j", + TaintSetT{ + LineColFun{6, 7, "main"}, + LineColFun{13, 8, "main"}, + LineColFun{13, 6, "main"}, + }); + GroundTruth.emplace(Main19, "k", + TaintSetT{ + LineColFun{6, 7, "main"}, + }); + GroundTruth.emplace(Main19, "p", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{9, 7, "main"}, + LineColFun{11, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_06_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_07) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 15, "retval", {"5"})); - GroundTruth.emplace( - std::tuple>( - "main", 15, "argc.addr", {"6"})); - GroundTruth.emplace( - std::tuple>( - "main", 15, "argv.addr", {"7"})); - GroundTruth.emplace( - std::tuple>( - "main", 15, "i", {"12"})); - GroundTruth.emplace( - std::tuple>( - "main", 15, "j", {"8", "9", "10", "11"})); - doAnalysisAndCompareResults("basic_07_cpp.ll", {"main"}, GroundTruth, false); + auto Main15 = LineColFun{5, 3, "main"}; + + GroundTruth.emplace(Main15, "argc", + TaintSetT{ + LineColFun{1, 14, "main"}, + }); + GroundTruth.emplace(Main15, "argv", + TaintSetT{ + LineColFun{1, 27, "main"}, + }); + // strong update on i + GroundTruth.emplace(Main15, "i", + TaintSetT{ + LineColFun{4, 5, "main"}, + }); + GroundTruth.emplace(Main15, "j", + TaintSetT{ + LineColFun{2, 7, "main"}, + LineColFun{3, 11, "main"}, + LineColFun{3, 13, "main"}, + LineColFun{3, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_07_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_08) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 12, "retval", {"2"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "i", {"9"})); - doAnalysisAndCompareResults("basic_08_cpp.ll", {"main"}, GroundTruth, false); + auto Main12 = LineColFun{11, 3, "main"}; + + // strong update on i + GroundTruth.emplace(Main12, "i", + TaintSetT{ + LineColFun{10, 5, "main"}, + }); + + doAnalysisAndCompareResults("basic_08_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_09) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 10, "i", {"4"})); - GroundTruth.emplace( - std::tuple>( - "main", 10, "j", {"4", "6", "7"})); - GroundTruth.emplace( - std::tuple>( - "main", 10, "retval", {"3"})); - doAnalysisAndCompareResults("basic_09_cpp.ll", {"main"}, GroundTruth, false); + auto Main10 = LineColFun{6, 3, "main"}; + + GroundTruth.emplace(Main10, "i", + TaintSetT{ + LineColFun{3, 7, "main"}, + }); + GroundTruth.emplace(Main10, "j", + TaintSetT{ + LineColFun{3, 7, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{5, 5, "main"}, + }); + + doAnalysisAndCompareResults("basic_09_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_10) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 6, "i", {"3"})); - GroundTruth.emplace( - std::tuple>( - "main", 6, "retval", {"2"})); - doAnalysisAndCompareResults("basic_10_cpp.ll", {"main"}, GroundTruth, false); + auto Main6 = LineColFun{4, 3, "main"}; + GroundTruth.emplace(Main6, "i", + TaintSetT{ + LineColFun{3, 7, "main"}, + }); + + doAnalysisAndCompareResults("basic_10_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleBasicTest_11) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 20, "FeatureSelector", {"5", "7", "8"})); - GroundTruth.emplace( - std::tuple>( - "main", 20, "retval", {"11", "16"})); - doAnalysisAndCompareResults("basic_11_cpp.ll", {"main"}, GroundTruth, false); + auto Main20 = RetStmt{"main"}; + + GroundTruth.emplace(Main20, "FeatureSelector", + TaintSetT{ + LineColFun{3, 14, "main"}, + LineColFun{4, 25, "main"}, + LineColFun{4, 7, "main"}, + }); + + GroundTruth.emplace(Main20, RetVal{"main"}, + TaintSetT{ + LineColFun{7, 5, "main"}, + LineColFun{15, 3, "main"}, + LineColFun{16, 1, "main"}, + }); + + doAnalysisAndCompareResults("basic_11_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleCallTest_01) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 14, "retval", {"8"})); - GroundTruth.emplace( - std::tuple>( - "main", 14, "i", {"9"})); - GroundTruth.emplace( - std::tuple>( - "main", 14, "j", {"12", "9", "10", "11"})); - GroundTruth.emplace( - std::tuple>( - "main", 14, "k", {"15", "1", "2", "13", "12", "9", "10", "11"})); - doAnalysisAndCompareResults("call_01_cpp.ll", {"main"}, GroundTruth, false); + auto Main14 = RetStmt{"main"}; + + GroundTruth.emplace(Main14, "i", + TaintSetT{ + LineColFun{4, 7, "main"}, + }); + GroundTruth.emplace(Main14, "j", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 11, "main"}, + LineColFun{5, 13, "main"}, + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main14, "k", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 11, "main"}, + LineColFun{5, 13, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{6, 7, "main"}, + LineColFun{6, 14, "main"}, + LineColFun{1, 12, "_Z2idi"}, + LineColFun{1, 24, "_Z2idi"}, + }); + + doAnalysisAndCompareResults("call_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleCallTest_02) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 13, "retval", {"12"})); - GroundTruth.emplace( - std::tuple>( - "main", 13, "i", {"13"})); - GroundTruth.emplace( - std::tuple>( - "main", 13, "j", {"14"})); - GroundTruth.emplace( - std::tuple>( - "main", 13, "k", - {"4", "5", "15", "6", "3", "14", "2", "13", "16", "18"})); - doAnalysisAndCompareResults("call_02_cpp.ll", {"main"}, GroundTruth, false); + auto Main13 = RetStmt{"main"}; + + GroundTruth.emplace(Main13, "i", + TaintSetT{ + LineColFun{4, 7, "main"}, + }); + GroundTruth.emplace(Main13, "j", + TaintSetT{ + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main13, "k", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{5, 7, "main"}, + LineColFun{6, 15, "main"}, + LineColFun{6, 18, "main"}, + LineColFun{6, 7, "main"}, + LineColFun{1, 13, "_Z3sumii"}, + LineColFun{1, 20, "_Z3sumii"}, + LineColFun{1, 32, "_Z3sumii"}, + LineColFun{1, 36, "_Z3sumii"}, + LineColFun{1, 34, "_Z3sumii"}, + }); + + doAnalysisAndCompareResults("call_02_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleCallTest_03) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 10, "retval", {"20"})); - GroundTruth.emplace( - std::tuple>( - "main", 10, "i", {"21"})); - GroundTruth.emplace( - std::tuple>( - "main", 10, "j", - {"22", "15", "6", "21", "2", "13", "8", "9", "12", "10", "24"})); - doAnalysisAndCompareResults("call_03_cpp.ll", {"main"}, GroundTruth, false); + auto Main10 = RetStmt{"main"}; + + GroundTruth.emplace(Main10, "i", + TaintSetT{ + LineColFun{9, 7, "main"}, + }); + GroundTruth.emplace(Main10, "j", + TaintSetT{ + LineColFun{9, 7, "main"}, + LineColFun{10, 21, "main"}, + LineColFun{6, 1, "_Z9factorialj"}, + LineColFun{3, 5, "_Z9factorialj"}, + LineColFun{9, 7, "main"}, + LineColFun{1, 29, "_Z9factorialj"}, + LineColFun{5, 3, "_Z9factorialj"}, + LineColFun{5, 10, "_Z9factorialj"}, + LineColFun{5, 24, "_Z9factorialj"}, + LineColFun{5, 12, "_Z9factorialj"}, + LineColFun{5, 26, "_Z9factorialj"}, + LineColFun{10, 7, "main"}, + }); + + doAnalysisAndCompareResults("call_03_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleCallTest_04) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 20, "retval", {"33"})); - GroundTruth.emplace( - std::tuple>( - "main", 20, "i", {"34"})); - GroundTruth.emplace( - std::tuple>( - "main", 20, "j", - {"15", "6", "2", "13", "8", "9", "12", "10", "35", "34", "37"})); - GroundTruth.emplace( - std::tuple>( - "main", 20, "k", - {"41", "19", "15", "6", "44", "2", "13", "8", "45", - "18", "9", "12", "10", "46", "24", "25", "35", "27", - "23", "26", "38", "34", "37", "42", "40"})); - doAnalysisAndCompareResults("call_04_cpp.ll", {"main"}, GroundTruth, false); + auto Main10 = RetStmt{"main"}; + + GroundTruth.emplace(Main10, "i", + TaintSetT{ + LineColFun{13, 7, "main"}, + }); + GroundTruth.emplace(Main10, "j", + TaintSetT{ + LineColFun{6, 1, "_Z9factorialj"}, + LineColFun{3, 5, "_Z9factorialj"}, + LineColFun{1, 29, "_Z9factorialj"}, + LineColFun{5, 3, "_Z9factorialj"}, + LineColFun{5, 10, "_Z9factorialj"}, + LineColFun{5, 24, "_Z9factorialj"}, + LineColFun{5, 12, "_Z9factorialj"}, + LineColFun{5, 26, "_Z9factorialj"}, + LineColFun{14, 21, "main"}, + LineColFun{13, 7, "main"}, + LineColFun{14, 7, "main"}, + }); + GroundTruth.emplace(Main10, "k", + TaintSetT{ + LineColFun{16, 12, "main"}, + LineColFun{8, 24, "_Z2idi"}, + LineColFun{6, 1, "_Z9factorialj"}, + LineColFun{3, 5, "_Z9factorialj"}, + LineColFun{16, 5, "main"}, + LineColFun{1, 29, "_Z9factorialj"}, + LineColFun{5, 3, "_Z9factorialj"}, + LineColFun{5, 10, "_Z9factorialj"}, + LineColFun{16, 5, "main"}, + LineColFun{8, 12, "_Z2idi"}, + LineColFun{5, 24, "_Z9factorialj"}, + LineColFun{5, 12, "_Z9factorialj"}, + LineColFun{5, 26, "_Z9factorialj"}, + LineColFun{16, 5, "main"}, + LineColFun{10, 20, "_Z3sumii"}, + LineColFun{10, 32, "_Z3sumii"}, + LineColFun{14, 21, "main"}, + LineColFun{10, 34, "_Z3sumii"}, + LineColFun{10, 36, "_Z3sumii"}, + LineColFun{10, 13, "_Z3sumii"}, + LineColFun{15, 14, "main"}, + LineColFun{13, 7, "main"}, + LineColFun{14, 7, "main"}, + LineColFun{16, 15, "main"}, + LineColFun{15, 7, "main"}, + }); + + doAnalysisAndCompareResults("call_04_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleCallTest_05) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 10, "retval", {"8"})); - GroundTruth.emplace( - std::tuple>( - "main", 10, "i", {"3", "11", "9"})); - GroundTruth.emplace( - std::tuple>( - "main", 10, "j", {"3", "10", "12"})); - doAnalysisAndCompareResults("call_05_cpp.ll", {"main"}, GroundTruth, false); + auto Main10 = RetStmt{"main"}; + + GroundTruth.emplace(Main10, "i", + TaintSetT{ + LineColFun{2, 38, "_Z18setValueToFortyTwoPi"}, + LineColFun{7, 3, "main"}, + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main10, "j", + TaintSetT{ + LineColFun{2, 38, "_Z18setValueToFortyTwoPi"}, + LineColFun{6, 7, "main"}, + LineColFun{8, 3, "main"}, + }); + + doAnalysisAndCompareResults("call_05_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleCallTest_06) { // NOTE: Here we are suffering from IntraProceduralAliasesOnly std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 24, "retval", {"11"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "i", {"3", "1", "2", "16", "18", "12"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "j", {"19", "21", "3", "1", "2", "13"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "k", {"22", "3", "14", "1", "2", "24"})); - GroundTruth.emplace( - std::tuple>( - "main", 24, "l", {"15", "3", "1", "2", "25", "27"})); - doAnalysisAndCompareResults("call_06_cpp.ll", {"main"}, GroundTruth, false); + auto Main24 = RetStmt{"main"}; + + GroundTruth.emplace(Main24, "i", + TaintSetT{ + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{2, 19, "_Z9incrementi"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{9, 17, "main"}, + LineColFun{9, 5, "main"}, + LineColFun{5, 7, "main"}, + }); + GroundTruth.emplace(Main24, "j", + TaintSetT{ + LineColFun{10, 17, "main"}, + LineColFun{10, 5, "main"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{2, 19, "_Z9incrementi"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{6, 7, "main"}, + }); + GroundTruth.emplace(Main24, "k", + TaintSetT{ + LineColFun{11, 17, "main"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{7, 7, "main"}, + LineColFun{2, 19, "_Z9incrementi"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{11, 5, "main"}, + }); + GroundTruth.emplace(Main24, "l", + TaintSetT{ + LineColFun{8, 7, "main"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{2, 19, "_Z9incrementi"}, + LineColFun{2, 31, "_Z9incrementi"}, + LineColFun{12, 17, "main"}, + LineColFun{12, 5, "main"}, + }); + + doAnalysisAndCompareResults("call_06_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleCallTest_07) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 6, "retval", {"7"})); - GroundTruth.emplace( - std::tuple>( - "main", 6, "VarIR", {"6", "3", "8"})); - doAnalysisAndCompareResults("call_07_cpp.ll", {"main"}, GroundTruth, false); + auto Main6 = RetStmt{"main"}; + + GroundTruth.emplace(Main6, "VarIR", + TaintSetT{ + LineColFun{7, 7, "main"}, + LineColFun{3, 6, "_Z13inputRefParamRi"}, + LineColFun{8, 3, "main"}, + }); + doAnalysisAndCompareResults("call_07_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleGlobalTest_01) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 9, "retval", {"3"})); - GroundTruth.emplace( - std::tuple>( - "main", 9, "i", {"7"})); - GroundTruth.emplace( - std::tuple>( - "main", 9, "j", {"0", "5", "6"})); - doAnalysisAndCompareResults("global_01_cpp.ll", {"main"}, GroundTruth, false); + auto Main9 = RetStmt{"main"}; + + GroundTruth.emplace(Main9, "i", + TaintSetT{ + LineColFun{6, 5, "main"}, + }); + GroundTruth.emplace(Main9, "j", + TaintSetT{ + GlobalVar{"i"}, + LineColFun{5, 7, "main"}, + LineColFun{5, 5, "main"}, + }); + + doAnalysisAndCompareResults("global_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleGlobalTest_02) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "_Z5initBv", 2, "a", {"0"})); - GroundTruth.emplace( - std::tuple>( - "_Z5initBv", 2, "b", {"2"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "a", {"0"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "b", {"2"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "retval", {"6"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "c", {"1", "8", "7"})); - doAnalysisAndCompareResults("global_02_cpp.ll", {"main"}, GroundTruth, false); + + auto Main12 = RetStmt{"main"}; + auto Init2 = RetStmt{"_Z5initBv"}; + + GroundTruth.emplace(Init2, "a", + TaintSetT{ + GlobalVar{"a"}, + }); + GroundTruth.emplace(Init2, "b", + TaintSetT{ + LineColFun{4, 18, "_Z5initBv"}, + }); + + GroundTruth.emplace(Main12, "a", + TaintSetT{ + GlobalVar{"a"}, + }); + GroundTruth.emplace(Main12, "b", + TaintSetT{ + LineColFun{4, 18, "_Z5initBv"}, + }); + GroundTruth.emplace(Main12, "c", + TaintSetT{ + GlobalVar{"b"}, + LineColFun{7, 7, "main"}, + LineColFun{7, 11, "main"}, + }); + + doAnalysisAndCompareResults("global_02_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleGlobalTest_03) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 1, "GlobalFeature", {"0"})); - GroundTruth.emplace( - std::tuple>( - "main", 2, "GlobalFeature", {"0"})); - GroundTruth.emplace( - std::tuple>( - "main", 17, "GlobalFeature", {"0"})); - doAnalysisAndCompareResults("global_03_cpp.ll", {"main"}, GroundTruth, false); + GroundTruth.emplace(LineColFun{6, 11, "main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(LineColFun{6, 25, "main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(RetStmt{"main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + + doAnalysisAndCompareResults("global_03_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleGlobalTest_04) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 1, "GlobalFeature", {"0"})); - GroundTruth.emplace( - std::tuple>( - "main", 2, "GlobalFeature", {"0"})); - GroundTruth.emplace( - std::tuple>( - "main", 17, "GlobalFeature", {"0"})); - GroundTruth.emplace( - std::tuple>( - "_Z7doStuffi", 1, "GlobalFeature", {"0"})); - GroundTruth.emplace( - std::tuple>( - "_Z7doStuffi", 2, "GlobalFeature", {"0"})); - doAnalysisAndCompareResults("global_04_cpp.ll", {"main", "_Z7doStuffi"}, + GroundTruth.emplace(LineColFun{8, 11, "main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(LineColFun{8, 25, "main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(RetStmt{"main"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(LineColFun{3, 31, "_Z7doStuffi"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + GroundTruth.emplace(LineColFun{3, 22, "_Z7doStuffi"}, "GlobalFeature", + TaintSetT{ + GlobalVar{"GlobalFeature"}, + }); + + doAnalysisAndCompareResults("global_04_cpp_dbg.ll", {"main", "_Z7doStuffi"}, GroundTruth, false); } TEST_F(IDEInstInteractionAnalysisTest, KillTest_01) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 12, "retval", {"4"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "i", {"5"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "j", {"10"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "k", {"9", "8", "5"})); - doAnalysisAndCompareResults("KillTest_01_cpp.ll", {"main"}, GroundTruth, + auto Main12 = RetStmt{"main"}; + + GroundTruth.emplace(Main12, "i", + TaintSetT{ + LineColFun{2, 7, "main"}, + }); + GroundTruth.emplace(Main12, "j", + TaintSetT{ + LineColFun{5, 5, "main"}, + }); + GroundTruth.emplace(Main12, "k", + TaintSetT{ + LineColFun{4, 7, "main"}, + LineColFun{4, 11, "main"}, + LineColFun{2, 7, "main"}, + }); + + doAnalysisAndCompareResults("KillTest_01_cpp_dbg.ll", {"main"}, GroundTruth, false); } TEST_F(IDEInstInteractionAnalysisTest, KillTest_02) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 12, "retval", {"6"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "A", {"0"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "B", {"2"})); - GroundTruth.emplace( - std::tuple>( - "main", 12, "C", {"1", "7", "8"})); - doAnalysisAndCompareResults("KillTest_02_cpp.ll", {"main"}, GroundTruth, + auto Main12 = RetStmt{"main"}; + + GroundTruth.emplace(Main12, "A", + TaintSetT{ + GlobalVar{"A"}, + }); + GroundTruth.emplace(Main12, "B", + TaintSetT{ + LineColFun{4, 18, "_Z5initBv"}, + }); + GroundTruth.emplace(Main12, "C", + TaintSetT{ + GlobalVar{"B"}, + LineColFun{7, 11, "main"}, + LineColFun{7, 7, "main"}, + }); + + doAnalysisAndCompareResults("KillTest_02_cpp_dbg.ll", {"main"}, GroundTruth, false); } TEST_F(IDEInstInteractionAnalysisTest, HandleReturnTest_01) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 6, "retval", {"3"})); - GroundTruth.emplace( - std::tuple>( - "main", 6, "localVar", {"4"})); - GroundTruth.emplace( - std::tuple>( - "main", 6, "call", {"0"})); - GroundTruth.emplace( - std::tuple>( - "main", 8, "localVar", {"0", "6"})); - GroundTruth.emplace( - std::tuple>( - "main", 8, "call", {"0"})); - doAnalysisAndCompareResults("return_01_cpp.ll", {"main"}, GroundTruth, false); + auto Main6 = LineColFun{7, 12, "main"}; + auto Main8 = RetStmt{"main"}; + + GroundTruth.emplace(Main6, "localVar", + TaintSetT{ + LineColFun{6, 12, "main"}, + }); + GroundTruth.emplace(Main8, "localVar", + TaintSetT{ + LineColFun{2, 30, "_Z20returnIntegerLiteralv"}, + LineColFun{7, 12, "main"}, + }); + + doAnalysisAndCompareResults("return_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); } TEST_F(IDEInstInteractionAnalysisTest, HandleHeapTest_01) { std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 17, "retval", {"3"})); - GroundTruth.emplace( - std::tuple>( - "main", 17, "i", {"5", "6"})); - GroundTruth.emplace( - std::tuple>( - "main", 17, "j", {"5", "6", "7", "8", "9"})); - doAnalysisAndCompareResults("heap_01_cpp.ll", {"main"}, GroundTruth, false); -} - -PHASAR_SKIP_TEST(TEST_F(IDEInstInteractionAnalysisTest, HandleRVOTest_01) { - GTEST_SKIP() << "This test heavily depends on the used stdlib version. TODO: " - "add a better one"; - std::set GroundTruth; - GroundTruth.emplace( - std::tuple>( - "main", 16, "retval", {"75", "76"})); - GroundTruth.emplace( - std::tuple>( - "main", 16, "str", {"70", "65", "72", "74", "77"})); - GroundTruth.emplace( - std::tuple>( - "main", 16, "ref.tmp", {"66", "9", "72", "73", "71"})); - doAnalysisAndCompareResults("rvo_01_cpp.ll", {"main"}, GroundTruth, false); -}) + auto Main17 = RetStmt{"main"}; + GroundTruth.emplace(Main17, "i", + TaintSetT{ + LineColFun{3, 12, "main"}, + LineColFun{3, 8, "main"}, + }); + GroundTruth.emplace(Main17, "j", + TaintSetT{ + LineColFun{3, 12, "main"}, + LineColFun{3, 8, "main"}, + LineColFun{4, 12, "main"}, + LineColFun{4, 11, "main"}, + LineColFun{4, 7, "main"}, + }); + + doAnalysisAndCompareResults("heap_01_cpp_dbg.ll", {"main"}, GroundTruth, + false); +} + +// PHASAR_SKIP_TEST(TEST_F(IDEInstInteractionAnalysisTest, HandleRVOTest_01) { +// GTEST_SKIP() << "This test heavily depends on the used stdlib version. +// TODO: " +// "add a better one"; + +// std::set GroundTruth; +// GroundTruth.emplace( +// std::tuple>( +// "main", 16, "retval", {"75", "76"})); +// GroundTruth.emplace( +// std::tuple>( +// "main", 16, "str", {"70", "65", "72", "74", "77"})); +// GroundTruth.emplace( +// std::tuple>( +// "main", 16, "ref.tmp", {"66", "9", "72", "73", "71"})); +// doAnalysisAndCompareResults("rvo_01_cpp.ll", {"main"}, GroundTruth, false); +// }) // TEST_F(IDEInstInteractionAnalysisTest, HandleStruct_01) { // std::set GroundTruth; diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp index 0b2d4fa52e..8845fc6aae 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp @@ -19,6 +19,11 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "llvm/IR/Instruction.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" + +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" @@ -62,6 +67,58 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { void TearDown() override {} + std::map> + srcCodeLocsToInsts( + const std::map> + &GroundTruth) { + std::map> + Converted; + + for (const auto &OuterEntry : GroundTruth) { + const auto *FirstInst = getInstFromEntryOrNull(std::get<0>(OuterEntry)); + if (FirstInst) { + for (const auto &InnerEntry : std::get<1>(OuterEntry)) { + const auto *SecondInst = + getInstFromEntryOrNull(std::get<0>(InnerEntry)); + + if (SecondInst) { + std::map InnerMap = { + {SecondInst, std::get<1>(InnerEntry)}}; + + Converted.insert( + std::pair>(FirstInst, + InnerMap)); + continue; + } + + llvm::outs() << "Line: " << std::get<0>(InnerEntry).Line + << "\nColumn: " << std::get<0>(InnerEntry).Column + << "\n"; + llvm::report_fatal_error( + "Second SrcCodeLocationEntry couldn't be converted to an " + "Instruction.\n"); + // llvm::errs() + // << "Second SrcCodeLocationEntry couldn't be converted to an " + // "Instruction.\n"; + } + continue; + } + + llvm::outs() << "Line: " << std::get<0>(OuterEntry).Line + << "\nColumn: " << std::get<0>(OuterEntry).Column << "\n"; + llvm::report_fatal_error( + "First SrcCodeLocationEntry couldn't be converted to an " + "Instruction.\n"); + // llvm::errs() << "First SrcCodeLocationEntry couldn't be converted to an + // " + // "Instruction.\n"; + } + + return Converted; + } + /** * We map instruction id to value for the ground truth. ID has to be * a string since Argument ID's are not integer type (e.g. main.0 for argc). @@ -69,53 +126,119 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { * @param solver provides the results */ void compareResults( - const std::map> &GroundTruth, + const std::map> + &GroundTruth, IDESolver_P> &Solver) { - for (const auto &InstToGroundTruth : GroundTruth) { - const auto *Inst = - HA->getProjectIRDB().getInstruction(InstToGroundTruth.first); - // std::cout << "Handle results at " << InstToGroundTruth.first << - // std::endl; - auto GT = InstToGroundTruth.second; - std::map Results; - for (auto Result : Solver.resultsAt(Inst, true)) { - if (GT.find(getMetaDataID(Result.first)) != GT.end()) { - Results.insert(std::pair( - getMetaDataID(Result.first), int(Result.second))); + auto GroundTruthEntries = srcCodeLocsToInsts(GroundTruth); + + int Counter = 0; + for (const auto &Entry : GroundTruthEntries) { + std::map Results; + auto GT = std::get<1>(Entry); + llvm::outs() << "Counter: " << Counter++ << "\n"; + const auto *CurrInst = std::get<0>(Entry); + for (auto Result : Solver.resultsAt(CurrInst, true)) { + const auto &FirstResult = std::get<0>(Result); + const auto &SecondResult = std::get<1>(Result); + + llvm::outs() << "FirstResult: " << llvmIRToString(FirstResult) << "\n"; + llvm::outs() << "SecondResult: " << SecondResult << "\n"; + if (const auto *CastInst = + llvm::dyn_cast_or_null(FirstResult)) { + if (GT.find(CastInst) != GT.end()) { + Results.insert(std::pair( + CastInst, int(SecondResult))); + } + } else { + llvm::errs() + << "[Error]: Couldn't cast FirstResult to Instruction.\n"; } } - EXPECT_EQ(Results, GT) << "At " << llvmIRToShortString(Inst); + + EXPECT_EQ(Results, GT) << "At " << llvmIRToShortString(CurrInst); } } }; // Test Fixture TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_01) { - initialize({PathToLlFiles + "typestate_01_c.ll"}); + initialize({PathToLlFiles + "typestate_01_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); Llvmtssolver.solve(); - const std::map> Gt = { - {5, {{"3", IOSTATE::UNINIT}}}, - {9, {{"3", IOSTATE::CLOSED}}}, - {7, {{"3", IOSTATE::OPENED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto File = + SrcCodeLocationEntry(4, 9, HA->getICFG().getFunction("main")); + const auto Entry = + SrcCodeLocationEntry(5, 7, HA->getICFG().getFunction("main")); + const auto EntryTwo = + SrcCodeLocationEntry(6, 3, HA->getICFG().getFunction("main")); + const auto EntryThree = + SrcCodeLocationEntry(7, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({Entry, {{File, IOSTATE::UNINIT}}}); + GroundTruth.insert({EntryTwo, {{File, IOSTATE::OPENED}}}); + GroundTruth.insert({EntryThree, {{File, IOSTATE::CLOSED}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_02) { - initialize({PathToLlFiles + "typestate_02_c.ll"}); + initialize({PathToLlFiles + "typestate_02_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - {7, {{"3", IOSTATE::OPENED}, {"5", IOSTATE::OPENED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto File = + SrcCodeLocationEntry(4, 9, HA->getICFG().getFunction("main")); + const auto Entry = + SrcCodeLocationEntry(6, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({Entry, {{File, IOSTATE::OPENED}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_03) { - initialize({PathToLlFiles + "typestate_03_c.ll"}); + initialize({PathToLlFiles + "typestate_03_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); + + std::map> + GroundTruth; + // %f = alloca ptr, align 8 + const auto MainFile = + SrcCodeLocationEntry(6, 9, HA->getICFG().getFunction("main")); + // %f.addr = alloca ptr, align 8 + const auto FooFile = + SrcCodeLocationEntry(3, 16, HA->getICFG().getFunction("foo")); + // const auto FooFClose = + // SrcCodeLocationEntry(3, 21, HA->getICFG().getFunction("foo")); + // %0 = load ptr, ptr %f + const auto PassFToFClose = + SrcCodeLocationEntry(3, 28, HA->getICFG().getFunction("foo")); + // ret void + const auto FooRet = + SrcCodeLocationEntry(3, 32, HA->getICFG().getFunction("foo")); + // %0 = load ptr, ptr %f, align 8 + const auto PassFToFoo = + SrcCodeLocationEntry(9, 7, HA->getICFG().getFunction("main")); + // ret i32 0 + const auto Return = + SrcCodeLocationEntry(11, 3, HA->getICFG().getFunction("main")); + // Entry in foo() + // GroundTruth.insert({FooFClose, {{FooFile, IOSTATE::OPENED}}}); + // Exit in foo() + GroundTruth.insert({FooRet, + {// {FooFile, IOSTATE::CLOSED}, + {PassFToFClose, IOSTATE::CLOSED}}}); + // Exit in main() + GroundTruth.insert({Return, + {// {FooFClose, IOSTATE::CLOSED}, + {MainFile, IOSTATE::CLOSED}, + {PassFToFoo, IOSTATE::CLOSED}}}); + compareResults(GroundTruth, Llvmtssolver); + + // Old ground truth +#if false // llvmtssolver.printReport(); const std::map> Gt = { // Entry in foo() @@ -135,54 +258,126 @@ TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_03) { {"8", IOSTATE::CLOSED}, {"12", IOSTATE::CLOSED}}}}; compareResults(Gt, Llvmtssolver); +#endif } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_04) { - initialize({PathToLlFiles + "typestate_04_c.ll"}); + initialize({PathToLlFiles + "typestate_04_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // At exit in foo() - {6, - { - {"2", IOSTATE::OPENED}, - //{"8", IOSTATE::OPENED} // 6 is before 8, so no info available - // before retFF - }}, - // Before closing in main() - {12, {{"2", IOSTATE::UNINIT}, {"8", IOSTATE::UNINIT}}}, - // At exit in main() - {14, {{"2", IOSTATE::ERROR}, {"8", IOSTATE::ERROR}}}}; - - compareResults(Gt, Llvmtssolver); + std::map> + GroundTruth; + const auto FooArg = + SrcCodeLocationEntry(4, 16, HA->getICFG().getFunction("foo")); + const auto FooRet = + SrcCodeLocationEntry(4, 49, HA->getICFG().getFunction("foo")); + const auto File = + SrcCodeLocationEntry(7, 9, HA->getICFG().getFunction("main")); + const auto FClose = + SrcCodeLocationEntry(9, 3, HA->getICFG().getFunction("main")); + const auto Return = + SrcCodeLocationEntry(10, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({FooRet, {{FooArg, IOSTATE::OPENED}}}); + GroundTruth.insert({FClose, {{File, IOSTATE::UNINIT}}}); + GroundTruth.insert({Return, {{File, IOSTATE::ERROR}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_05) { - initialize({PathToLlFiles + "typestate_05_c.ll"}); + initialize({PathToLlFiles + "typestate_05_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // Before if statement - {10, {{"4", IOSTATE::OPENED}, {"6", IOSTATE::OPENED}}}, - // Inside if statement at last instruction - {13, - {{"4", IOSTATE::CLOSED}, - {"6", IOSTATE::CLOSED}, - {"11", IOSTATE::CLOSED}}}, - // After if statement - {14, {{"4", IOSTATE::BOT}, {"6", IOSTATE::BOT}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto File = + SrcCodeLocationEntry(6, 9, HA->getICFG().getFunction("main")); + const auto CallFOpen = + SrcCodeLocationEntry(7, 7, HA->getICFG().getFunction("main")); + const auto AfterFOpen = + SrcCodeLocationEntry(8, 7, HA->getICFG().getFunction("main")); + const auto LoadFile = + SrcCodeLocationEntry(9, 12, HA->getICFG().getFunction("main")); + const auto AfterFClose = + SrcCodeLocationEntry(10, 3, HA->getICFG().getFunction("main")); + const auto Return = + SrcCodeLocationEntry(11, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert( + {AfterFOpen, {{File, IOSTATE::OPENED}, {CallFOpen, IOSTATE::OPENED}}}); + GroundTruth.insert({AfterFClose, + {{File, IOSTATE::CLOSED}, + {CallFOpen, IOSTATE::CLOSED}, + {LoadFile, IOSTATE::CLOSED}}}); + GroundTruth.insert( + {Return, {{File, IOSTATE::BOT}, {CallFOpen, IOSTATE::BOT}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, DISABLED_HandleTypeState_06) { // This test fails due to imprecise points-to information - initialize({PathToLlFiles + "typestate_06_c.ll"}); + initialize({PathToLlFiles + "typestate_06_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); + + std::map> + GroundTruth; + + // %f = alloca ptr, align 8 + const auto FileF = + SrcCodeLocationEntry(5, 9, HA->getICFG().getFunction("main")); + // %d = alloca ptr, align 8 + const auto FileD = + SrcCodeLocationEntry(6, 9, HA->getICFG().getFunction("main")); + // %call = call noalias ptr @fopen(ptr noundef @.str, ptr noundef @.str.1) + const auto FirstFOpenCall = + SrcCodeLocationEntry(7, 7, HA->getICFG().getFunction("main")); + // store ptr %call, ptr %f, align 8 + const auto StoreFirstFOpenRetVal = + SrcCodeLocationEntry(7, 5, HA->getICFG().getFunction("main")); + // %call1 = call noalias ptr @fopen(ptr noundef @.str.2, ptr noundef @.str.3) + const auto SecondFOpenCall = + SrcCodeLocationEntry(8, 7, HA->getICFG().getFunction("main")); + // store ptr %call1, ptr %d, align 8 + const auto StoreSecondFOpenRetVal = + SrcCodeLocationEntry(8, 5, HA->getICFG().getFunction("main")); + // %0 = load ptr, ptr %f, align 8 + const auto LoadFileF = + SrcCodeLocationEntry(10, 10, HA->getICFG().getFunction("main")); + // %call2 = call i32 @fclose(ptr noundef %0) + const auto CallFClose = + SrcCodeLocationEntry(10, 3, HA->getICFG().getFunction("main")); + // ret i32 0 + const auto Return = + SrcCodeLocationEntry(12, 3, HA->getICFG().getFunction("main")); + + GroundTruth.insert({FirstFOpenCall, {{FileF, IOSTATE::UNINIT}}}); + GroundTruth.insert({FirstFOpenCall, {{FileD, IOSTATE::UNINIT}}}); + + GroundTruth.insert({StoreFirstFOpenRetVal, {{FileF, IOSTATE::UNINIT}}}); + GroundTruth.insert({StoreFirstFOpenRetVal, {{FileD, IOSTATE::UNINIT}}}); + GroundTruth.insert( + {StoreFirstFOpenRetVal, {{FirstFOpenCall, IOSTATE::OPENED}}}); + + GroundTruth.insert({SecondFOpenCall, {{FileF, IOSTATE::OPENED}}}); + GroundTruth.insert({SecondFOpenCall, {{FileD, IOSTATE::UNINIT}}}); + GroundTruth.insert({SecondFOpenCall, {{FirstFOpenCall, IOSTATE::OPENED}}}); + + GroundTruth.insert({StoreSecondFOpenRetVal, {{FileF, IOSTATE::OPENED}}}); + GroundTruth.insert({StoreSecondFOpenRetVal, {{FileD, IOSTATE::UNINIT}}}); + GroundTruth.insert( + {StoreSecondFOpenRetVal, {{SecondFOpenCall, IOSTATE::OPENED}}}); + + GroundTruth.insert({CallFClose, {{FileF, IOSTATE::OPENED}}}); + GroundTruth.insert({CallFClose, {{FileD, IOSTATE::UNINIT}}}); + GroundTruth.insert({CallFClose, {{LoadFileF, IOSTATE::OPENED}}}); + + GroundTruth.insert({Return, {{FileF, IOSTATE::OPENED}}}); + GroundTruth.insert({Return, {{FileD, IOSTATE::UNINIT}}}); + compareResults(GroundTruth, Llvmtssolver); + + // Old ground truth +#if false const std::map> Gt = { // Before first fopen() {8, {{"5", IOSTATE::UNINIT}, {"6", IOSTATE::UNINIT}}}, @@ -211,341 +406,397 @@ TEST_F(IDETSAnalysisFileIOTest, DISABLED_HandleTypeState_06) { // After if statement {14, {{"5", IOSTATE::CLOSED}, {"6", IOSTATE::OPENED}}}}; compareResults(Gt, Llvmtssolver); +#endif } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_07) { - initialize({PathToLlFiles + "typestate_07_c.ll"}); + initialize({PathToLlFiles + "typestate_07_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // In foo() - {6, - { - {"foo.0", IOSTATE::CLOSED}, {"2", IOSTATE::CLOSED}, - //{"8", IOSTATE::CLOSED}// 6 is before 8, so no info available - // before retFF - }}, - // At fclose() - {11, {{"8", IOSTATE::UNINIT}, {"10", IOSTATE::UNINIT}}}, - // After fclose() - {12, {{"8", IOSTATE::ERROR}, {"10", IOSTATE::ERROR}}}, - // After fopen() - {13, - {{"8", IOSTATE::ERROR}, - {"10", IOSTATE::ERROR}, - {"12", IOSTATE::OPENED}}}, - // After store - {14, - {{"8", IOSTATE::OPENED}, - {"10", IOSTATE::ERROR}, - {"12", IOSTATE::OPENED}}}, - // At exit in main() - {16, {{"2", IOSTATE::CLOSED}, {"8", IOSTATE::CLOSED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + // %f.addr = alloca ptr, align 8 + const auto FooFile = + SrcCodeLocationEntry(3, 16, HA->getICFG().getFunction("foo")); + // ret void + const auto FooRet = + SrcCodeLocationEntry(3, 32, HA->getICFG().getFunction("foo")); + // %f = alloca ptr, align 8 + const auto MainFile = + SrcCodeLocationEntry(6, 9, HA->getICFG().getFunction("main")); + // %0 = load ptr, ptr %f, align 8 + const auto MainFileLoad = + SrcCodeLocationEntry(7, 10, HA->getICFG().getFunction("main")); + // %call = call i32 @fclose(ptr noundef %0) + const auto CallFClose = + SrcCodeLocationEntry(7, 3, HA->getICFG().getFunction("main")); + // %call1 = call noalias ptr @fopen(ptr noundef @.str, ptr noundef @.str.1) + const auto Call1FOpen = + SrcCodeLocationEntry(8, 7, HA->getICFG().getFunction("main")); + // store ptr %call1, ptr %f, align 8 + const auto StoreOfCall1 = + SrcCodeLocationEntry(8, 5, HA->getICFG().getFunction("main")); + // %1 = load ptr, ptr %f, align 8 + const auto LoadMainFile = + SrcCodeLocationEntry(10, 7, HA->getICFG().getFunction("main")); + // ret i32 0 + const auto MainReturn = + SrcCodeLocationEntry(12, 3, HA->getICFG().getFunction("main")); + + GroundTruth.insert({FooRet, {{FooFile, IOSTATE::CLOSED}}}); + GroundTruth.insert( + {CallFClose, + {{MainFile, IOSTATE::UNINIT}, {MainFileLoad, IOSTATE::UNINIT}}}); + GroundTruth.insert( + {Call1FOpen, + {{MainFile, IOSTATE::ERROR}, {MainFileLoad, IOSTATE::ERROR}}}); + GroundTruth.insert({StoreOfCall1, + {{MainFile, IOSTATE::ERROR}, + {MainFileLoad, IOSTATE::ERROR}, + {Call1FOpen, IOSTATE::OPENED}}}); + GroundTruth.insert({LoadMainFile, + {{MainFile, IOSTATE::OPENED}, + {MainFileLoad, IOSTATE::ERROR}, + {Call1FOpen, IOSTATE::OPENED}}}); + GroundTruth.insert( + {MainReturn, {{MainFile, IOSTATE::CLOSED}, {FooFile, IOSTATE::CLOSED}}}); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_08) { - initialize({PathToLlFiles + "typestate_08_c.ll"}); + initialize({PathToLlFiles + "typestate_08_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // At exit in foo() - {6, {{"2", IOSTATE::OPENED}}}, - // At exit in main() - {11, {{"2", IOSTATE::OPENED}, {"8", IOSTATE::UNINIT}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto FooFile = + SrcCodeLocationEntry(5, 9, HA->getICFG().getFunction("foo")); + const auto FooRet = + SrcCodeLocationEntry(7, 3, HA->getICFG().getFunction("foo")); + const auto MainFile = + SrcCodeLocationEntry(11, 9, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(13, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({FooRet, {{FooFile, IOSTATE::OPENED}}}); + GroundTruth.insert( + {MainReturn, {{FooFile, IOSTATE::OPENED}, {MainFile, IOSTATE::UNINIT}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_09) { - initialize({PathToLlFiles + "typestate_09_c.ll"}); + initialize({PathToLlFiles + "typestate_09_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // At exit in foo() - {8, - { - {"4", IOSTATE::OPENED}, - //{"10", IOSTATE::OPENED}// 8 is before 10, so no info available - // before retFF - }}, - // At exit in main() - {18, {{"4", IOSTATE::CLOSED}, {"10", IOSTATE::CLOSED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto FooFile = + SrcCodeLocationEntry(5, 9, HA->getICFG().getFunction("foo")); + const auto FooRet = + SrcCodeLocationEntry(7, 3, HA->getICFG().getFunction("foo")); + const auto MainFile = + SrcCodeLocationEntry(11, 9, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(15, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({FooRet, {{FooFile, IOSTATE::OPENED}}}); + GroundTruth.insert( + {MainReturn, {{FooFile, IOSTATE::CLOSED}, {MainFile, IOSTATE::CLOSED}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_10) { - initialize({PathToLlFiles + "typestate_10_c.ll"}); + initialize({PathToLlFiles + "typestate_10_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // At exit in bar() - {4, {{"2", IOSTATE::UNINIT}}}, - // At exit in foo() - {11, - {//{"2", IOSTATE::OPENED}, - //{"13", IOSTATE::OPENED}, // 2 and 13 are in different functions, so - // results are not available before retFF - {"5", IOSTATE::OPENED}}}, - // At exit in main() - {19, - {{"2", IOSTATE::CLOSED}, - {"5", IOSTATE::CLOSED}, - {"13", IOSTATE::CLOSED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto BarFile = + SrcCodeLocationEntry(5, 9, HA->getICFG().getFunction("bar")); + const auto BarRet = + SrcCodeLocationEntry(6, 3, HA->getICFG().getFunction("bar")); + const auto FooFile = + SrcCodeLocationEntry(10, 9, HA->getICFG().getFunction("foo")); + const auto FooRet = + SrcCodeLocationEntry(12, 3, HA->getICFG().getFunction("foo")); + const auto MainFile = + SrcCodeLocationEntry(16, 9, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(20, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({BarRet, {{BarFile, IOSTATE::UNINIT}}}); + GroundTruth.insert({FooRet, {{FooFile, IOSTATE::OPENED}}}); + GroundTruth.insert({MainReturn, + {{BarFile, IOSTATE::CLOSED}, + {FooFile, IOSTATE::CLOSED}, + {MainFile, IOSTATE::CLOSED}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_11) { - initialize({PathToLlFiles + "typestate_11_c.ll"}); + initialize({PathToLlFiles + "typestate_11_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // At exit in bar(): closing uninitialized file-handle gives error-state - {6, - { - {"2", IOSTATE::ERROR}, - //{"7", IOSTATE::ERROR}, - //{"13", IOSTATE::ERROR} // 7 and 13 not yet reached - }}, - // At exit in foo() - {11, - { - //{"2", IOSTATE::OPENED}, // 2 is in different function - {"7", IOSTATE::OPENED}, - //{"13", IOSTATE::OPENED} // 13 is after 11 - }}, - // At exit in main(): due to aliasing the error-state from bar is - // propagated back to main - {19, - {{"2", IOSTATE::ERROR}, {"7", IOSTATE::ERROR}, {"13", IOSTATE::ERROR}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto BarFile = + SrcCodeLocationEntry(4, 16, HA->getICFG().getFunction("bar")); + const auto BarRet = + SrcCodeLocationEntry(4, 32, HA->getICFG().getFunction("bar")); + const auto FooFile = + SrcCodeLocationEntry(6, 16, HA->getICFG().getFunction("foo")); + const auto FooRet = + SrcCodeLocationEntry(6, 49, HA->getICFG().getFunction("foo")); + const auto MainFile = + SrcCodeLocationEntry(9, 9, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(13, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({BarRet, {{BarFile, IOSTATE::ERROR}}}); + GroundTruth.insert({FooRet, {{FooFile, IOSTATE::OPENED}}}); + GroundTruth.insert({MainReturn, + {{BarFile, IOSTATE::ERROR}, + {FooFile, IOSTATE::ERROR}, + {MainFile, IOSTATE::ERROR}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_12) { - initialize({PathToLlFiles + "typestate_12_c.ll"}); + initialize({PathToLlFiles + "typestate_12_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // At exit in bar() - {6, - { - {"2", IOSTATE::OPENED}, - //{"10", IOSTATE::OPENED} // 6 has no information about 10, as it - // always completes before - }}, - // At exit in foo() - {8, {{"2", IOSTATE::OPENED}, {"10", IOSTATE::OPENED}}}, - // At exit in main() - {16, {{"2", IOSTATE::CLOSED}, {"10", IOSTATE::CLOSED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto BarFile = + SrcCodeLocationEntry(5, 9, HA->getICFG().getFunction("bar")); + const auto BarRet = + SrcCodeLocationEntry(7, 3, HA->getICFG().getFunction("bar")); + const auto AfterFoo = + SrcCodeLocationEntry(15, 3, HA->getICFG().getFunction("main")); + const auto MainFile = + SrcCodeLocationEntry(13, 9, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(17, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({BarRet, {{BarFile, IOSTATE::OPENED}}}); + GroundTruth.insert( + {AfterFoo, {{MainFile, IOSTATE::OPENED}, {BarFile, IOSTATE::OPENED}}}); + GroundTruth.insert( + {MainReturn, {{MainFile, IOSTATE::CLOSED}, {BarFile, IOSTATE::CLOSED}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_13) { - initialize({PathToLlFiles + "typestate_13_c.ll"}); + initialize({PathToLlFiles + "typestate_13_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // Before first fclose() - {8, {{"3", IOSTATE::OPENED}}}, - // Before second fclose() - {10, {{"3", IOSTATE::CLOSED}}}, - // At exit in main() - {11, {{"3", IOSTATE::ERROR}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto File = + SrcCodeLocationEntry(4, 9, HA->getICFG().getFunction("main")); + const auto BeforeFirstFClose = + SrcCodeLocationEntry(7, 3, HA->getICFG().getFunction("main")); + const auto BeforeSecondFClose = + SrcCodeLocationEntry(8, 3, HA->getICFG().getFunction("main")); + const auto Return = + SrcCodeLocationEntry(10, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({BeforeFirstFClose, {{File, IOSTATE::OPENED}}}); + GroundTruth.insert({BeforeSecondFClose, {{File, IOSTATE::CLOSED}}}); + GroundTruth.insert({Return, {{File, IOSTATE::ERROR}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_14) { - initialize({PathToLlFiles + "typestate_14_c.ll"}); + initialize({PathToLlFiles + "typestate_14_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // Before first fopen() - {7, {{"5", IOSTATE::UNINIT}}}, - // Before second fopen() - {9, {{"5", IOSTATE::OPENED}}}, - // After second store - {11, - {{"5", IOSTATE::OPENED}, - {"7", IOSTATE::OPENED}, - {"9", IOSTATE::OPENED}}}, - // At exit in main() - {11, - {{"5", IOSTATE::CLOSED}, - {"7", IOSTATE::CLOSED}, - {"9", IOSTATE::CLOSED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto File = + SrcCodeLocationEntry(4, 9, HA->getICFG().getFunction("main")); + const auto BeforeFirstFOpen = + SrcCodeLocationEntry(5, 5, HA->getICFG().getFunction("main")); + const auto BeforeSecondFOpen = + SrcCodeLocationEntry(6, 5, HA->getICFG().getFunction("main")); + const auto BeforeFClose = + SrcCodeLocationEntry(7, 3, HA->getICFG().getFunction("main")); + const auto Return = + SrcCodeLocationEntry(9, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({BeforeFirstFOpen, {{File, IOSTATE::UNINIT}}}); + GroundTruth.insert({BeforeSecondFOpen, {{File, IOSTATE::OPENED}}}); + GroundTruth.insert({BeforeFClose, + {{File, IOSTATE::OPENED}, + {BeforeFirstFOpen, IOSTATE::OPENED}, + {BeforeSecondFOpen, IOSTATE::OPENED}}}); + GroundTruth.insert({Return, + {{File, IOSTATE::CLOSED}, + {BeforeFirstFOpen, IOSTATE::CLOSED}, + {BeforeSecondFOpen, IOSTATE::CLOSED}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_15) { - initialize({PathToLlFiles + "typestate_15_c.ll"}); + initialize({PathToLlFiles + "typestate_15_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // After store of ret val of first fopen() - {9, - { - {"5", IOSTATE::OPENED}, {"7", IOSTATE::OPENED}, - // for 9, 11, 13 state is top - // {"9", IOSTATE::OPENED}, - // {"11", IOSTATE::OPENED}, - // {"13", IOSTATE::OPENED} - }}, - // After first fclose() - {11, - { - {"5", IOSTATE::CLOSED}, - {"7", IOSTATE::CLOSED}, - {"9", IOSTATE::CLOSED}, - // for 11 and 13 state is top - // {"11", IOSTATE::CLOSED}, - // {"13", IOSTATE::CLOSED} - }}, - // After second fopen() but before storing ret val - {12, - { - {"5", IOSTATE::CLOSED}, - {"7", IOSTATE::CLOSED}, - {"9", IOSTATE::CLOSED}, - {"11", IOSTATE::OPENED}, - // for 13 state is top - //{"13", IOSTATE::CLOSED} - }}, - // After storing ret val of second fopen() - {13, - { - {"5", IOSTATE::OPENED}, - {"7", IOSTATE::CLOSED}, // 7 and 9 do not alias 11 - {"9", IOSTATE::CLOSED}, - {"11", IOSTATE::OPENED}, - // for 13 state is top - //{"13", IOSTATE::OPENED} - }}, - // At exit in main() - {15, - {{"5", IOSTATE::CLOSED}, - // Due to flow-insensitive alias information, the - // closed file-handle (which has ID 13) may alias - // the closed file handles 7 and 9. Hence closed - // + closed gives error for 7 and 9 => false positive - {"7", IOSTATE::ERROR}, - {"9", IOSTATE::ERROR}, - {"11", IOSTATE::CLOSED}, - {"13", IOSTATE::CLOSED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + // 5: %f = alloca ptr, align 8 + const auto File = + SrcCodeLocationEntry(4, 9, HA->getICFG().getFunction("main")); + // %call = call noalias ptr @fopen + const auto FOpen = + SrcCodeLocationEntry(5, 7, HA->getICFG().getFunction("main")); + // %0 = load ptr, ptr %f, align 8 + const auto LoadFile = + SrcCodeLocationEntry(6, 10, HA->getICFG().getFunction("main")); + // %call2 = call noalias ptr @fopen + const auto SecondFOpen = + SrcCodeLocationEntry(7, 7, HA->getICFG().getFunction("main")); + // store ptr %call2, ptr %f, align 8 + const auto StoreSecondFOpen = + SrcCodeLocationEntry(7, 5, HA->getICFG().getFunction("main")); + // %1 = load ptr, ptr %f, align 8 + const auto SecondLoadFile = + SrcCodeLocationEntry(8, 10, HA->getICFG().getFunction("main")); + // ret i32 0 + const auto Return = + SrcCodeLocationEntry(10, 3, HA->getICFG().getFunction("main")); + + GroundTruth.insert( + {LoadFile, {{File, IOSTATE::OPENED}, {FOpen, IOSTATE::OPENED}}}); + GroundTruth.insert({SecondFOpen, + {{File, IOSTATE::CLOSED}, + {FOpen, IOSTATE::CLOSED}, + {LoadFile, IOSTATE::CLOSED}}}); + GroundTruth.insert({StoreSecondFOpen, + {{File, IOSTATE::CLOSED}, + {FOpen, IOSTATE::CLOSED}, + {LoadFile, IOSTATE::CLOSED}, + {SecondFOpen, IOSTATE::OPENED}}}); + GroundTruth.insert({SecondLoadFile, + {{File, IOSTATE::OPENED}, + {FOpen, IOSTATE::CLOSED}, + {LoadFile, IOSTATE::CLOSED}, + {SecondFOpen, IOSTATE::OPENED}}}); + GroundTruth.insert({Return, + {{File, IOSTATE::CLOSED}, + {FOpen, IOSTATE::ERROR}, + {LoadFile, IOSTATE::ERROR}, + {SecondFOpen, IOSTATE::CLOSED}, + {SecondLoadFile, IOSTATE::CLOSED}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_16) { /// TODO: After the EF fix everything is BOT; --> Make the TSA more precise! - initialize({PathToLlFiles + "typestate_16_c.ll"}); + initialize({PathToLlFiles + "typestate_16_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - // Llvmtssolver.dumpResults(); - - // auto Pts = PT->getAliasSet(IRDB->getInstruction(2)); - // std::cout << "Alias(2) = {"; - // bool Frst = true; - // for (const auto *P : *Pts) { - // if (Frst) { - // Frst = false; - // } else { - // std::cout << ", "; - // } - // std::cout << llvmIRToShortString(P); - // } - // std::cout << "}" << std::endl; - const std::map> Gt = { - // At exit in foo() - {16, - { - //{"2", IOSTATE::CLOSED}, - {"2", IOSTATE::BOT} // Overapproximation due to too flat lattice! - // {"18", IOSTATE::CLOSED} // pointsTo information is not sufficient - }}, - // At exit in main() - {24, - {{"2", IOSTATE::BOT}, - {"18", IOSTATE::BOT}}}}; // Overapproximation due to too flat lattice - // (would expect CLOSED for both)! - compareResults(Gt, Llvmtssolver); + std::map> + GroundTruth; + const auto FooFile = + SrcCodeLocationEntry(4, 16, HA->getICFG().getFunction("foo")); + const auto FooExit = + SrcCodeLocationEntry(11, 1, HA->getICFG().getFunction("foo")); + const auto MainFile = + SrcCodeLocationEntry(14, 9, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(19, 3, HA->getICFG().getFunction("main")); + // At exit in foo() + GroundTruth.insert({FooExit, {{FooFile, IOSTATE::BOT}}}); + // At exit in main() + GroundTruth.insert( + {MainReturn, {{FooFile, IOSTATE::BOT}, {MainFile, IOSTATE::BOT}}}); + compareResults(GroundTruth, Llvmtssolver); } -// TODO: Check this case again! TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_17) { - initialize({PathToLlFiles + "typestate_17_c.ll"}); + initialize({PathToLlFiles + "typestate_17_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // Before loop - {15, - {{"2", IOSTATE::CLOSED}, - {"9", IOSTATE::CLOSED}, - {"13", IOSTATE::CLOSED}}}, - // Before fgetc() // fgetc(CLOSED)=ERROR join CLOSED = BOT - {17, - { - {"2", IOSTATE::BOT}, {"9", IOSTATE::BOT}, {"13", IOSTATE::BOT}, - // {"16", IOSTATE::BOT} // at 16 we now have ERROR (actually, this is - // correct as well as BOT) - }}, - // At exit in main() - {22, - { - {"2", IOSTATE::BOT}, {"9", IOSTATE::BOT}, {"13", IOSTATE::BOT}, - //{"16", IOSTATE::BOT} // at 16 we now have ERROR (actually, this is - // correct as well as BOT) - }}}; - compareResults(Gt, Llvmtssolver); + std::map> + GroundTruth; + const auto FooFile = + SrcCodeLocationEntry(4, 16, HA->getICFG().getFunction("foo")); + const auto File = + SrcCodeLocationEntry(8, 9, HA->getICFG().getFunction("main")); + const auto FOpenFile = + SrcCodeLocationEntry(8, 9, HA->getICFG().getFunction("main")); + const auto BeforeLoop = + SrcCodeLocationEntry(14, 3, HA->getICFG().getFunction("main")); + const auto BeforeFGetC = + SrcCodeLocationEntry(14, 13, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(17, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({BeforeLoop, + {{FooFile, IOSTATE::CLOSED}, + {File, IOSTATE::CLOSED}, + {FOpenFile, IOSTATE::CLOSED}}}); + GroundTruth.insert({BeforeFGetC, + {{FooFile, IOSTATE::BOT}, + {File, IOSTATE::BOT}, + {FOpenFile, IOSTATE::BOT}}}); + GroundTruth.insert({MainReturn, + {{FooFile, IOSTATE::BOT}, + {File, IOSTATE::BOT}, + {FOpenFile, IOSTATE::BOT}}}); + compareResults(GroundTruth, Llvmtssolver); } TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_18) { /// TODO: After the EF fix everything is BOT; --> Make the TSA more precise! - initialize({PathToLlFiles + "typestate_18_c.ll"}); + initialize({PathToLlFiles + "typestate_18_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - // At exit in foo() - {17, - { - //{"2", IOSTATE::CLOSED}, - {"2", IOSTATE::BOT}, // Overapproximation due to too flat lattice! - // {"19", IOSTATE::CLOSED} // pointsTo information not sufficient - }}, - // At exit in main() - {25, - {{"2", IOSTATE::BOT}, - {"19", IOSTATE::BOT}}}}; // Overapproximation due to too flat lattice - // (would expect CLOSED for both)! - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto FooReturn = + SrcCodeLocationEntry(11, 1, HA->getICFG().getFunction("foo")); + const auto FooFile = + SrcCodeLocationEntry(4, 16, HA->getICFG().getFunction("foo")); + const auto MainFile = + SrcCodeLocationEntry(14, 9, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(19, 3, HA->getICFG().getFunction("main")); + GroundTruth.insert({FooReturn, {{FooFile, IOSTATE::BOT}}}); + GroundTruth.insert( + {MainReturn, {{MainFile, IOSTATE::BOT}, {FooFile, IOSTATE::BOT}}}); + compareResults(GroundTruth, Llvmtssolver); } -// TODO: Check this case again! TEST_F(IDETSAnalysisFileIOTest, HandleTypeState_19) { - initialize({PathToLlFiles + "typestate_19_c.ll"}); + initialize({PathToLlFiles + "typestate_19_c_dbg.ll"}); IDESolver Llvmtssolver(*TSProblem, &HA->getICFG()); - Llvmtssolver.solve(); - const std::map> Gt = { - {11, {{"8", IOSTATE::UNINIT}}}, - {14, {{"8", IOSTATE::BOT}}}, - // At exit in main() - {25, {{"2", IOSTATE::CLOSED}, {"8", IOSTATE::CLOSED}}}}; - compareResults(Gt, Llvmtssolver); + + std::map> + GroundTruth; + const auto FooFile = + SrcCodeLocationEntry(4, 16, HA->getICFG().getFunction("foo")); + const auto MainFile = + SrcCodeLocationEntry(7, 9, HA->getICFG().getFunction("main")); + const auto WhileCond = + SrcCodeLocationEntry(11, 3, HA->getICFG().getFunction("main")); + const auto StoreCall = + SrcCodeLocationEntry(11, 13, HA->getICFG().getFunction("main")); + const auto MainReturn = + SrcCodeLocationEntry(18, 3, HA->getICFG().getFunction("main")); + + GroundTruth.insert({WhileCond, {{MainFile, IOSTATE::UNINIT}}}); + GroundTruth.insert({StoreCall, {{MainFile, IOSTATE::BOT}}}); + GroundTruth.insert( + {MainReturn, {{FooFile, IOSTATE::CLOSED}, {MainFile, IOSTATE::CLOSED}}}); + compareResults(GroundTruth, Llvmtssolver); } // main function for the test case diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysisTest.cpp index b36430c3c6..0760511c32 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysisTest.cpp @@ -11,11 +11,17 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" +#include "llvm/Support/Casting.h" +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" +#include +#include #include using namespace std; @@ -59,26 +65,58 @@ class IFDSConstAnalysisTest : public ::testing::Test { return RetOrResInstructions; } - void compareResults(const std::set &GroundTruth, - IFDSSolver_P &Solver) { + void compareResultsImpl(const std::set &GroundTruth, + IFDSSolver_P &Solver) { std::set AllMutableAllocas; + for (const auto *RR : getRetOrResInstructions()) { std::set Facts = Solver.ifdsResultsAt(RR); for (const auto *Fact : Facts) { if (isAllocaInstOrHeapAllocaFunction(Fact) || (llvm::isa(Fact) && !Constproblem->isZeroValue(Fact))) { - + llvm::outs() << "Found *Fact: " << *Fact << "\n"; AllMutableAllocas.insert(Fact); } } } - std::set MutableIDs; - for (const auto *Memloc : AllMutableAllocas) { - std::cerr << "> Is Mutable: " << llvmIRToShortString(Memloc) << "\n"; - MutableIDs.insert(std::stoul(getMetaDataID(Memloc))); + + EXPECT_EQ(GroundTruth, AllMutableAllocas); + } + + void compareResults(const std::set &GroundTruth, + IFDSSolver_P &Solver) { + auto GroundTruthEntriesAsInsts = getGroundTruthValues(GroundTruth); + std::set GroundTruthEntries; + for (const auto *Entry : GroundTruthEntriesAsInsts) { + if (const auto *EntryVal = llvm::dyn_cast_or_null(Entry)) { + llvm::outs() << "*EntryVal: " << *EntryVal << "\n"; + GroundTruthEntries.insert(EntryVal); + continue; + } + + llvm::errs() + << "Ground Truth Instruction was not a Value and can't be a " + "correct entry here. Please double check the Ground Truth.\n"; + ASSERT_TRUE(false); } - EXPECT_EQ(GroundTruth, MutableIDs); + + compareResultsImpl(GroundTruthEntries, Solver); + } + + void compareResults(const std::set &GroundTruth, + IFDSSolver_P &Solver) { + auto GroundTruthEntries = + convertTestingLocationSetInIR(GroundTruth, HA->getProjectIRDB()); + + compareResultsImpl(GroundTruthEntries, Solver); + } + void compareResults(std::initializer_list GroundTruth, + IFDSSolver_P &Solver) { + auto GroundTruthEntries = + convertTestingLocationSetInIR(GroundTruth, HA->getProjectIRDB()); + + compareResultsImpl(GroundTruthEntries, Solver); } }; @@ -87,28 +125,36 @@ TEST_F(IFDSConstAnalysisTest, HandleBasicTest_01) { initialize({PathToLlFiles + "basic/basic_01_cpp_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({}, Llvmconstsolver); + std::set GroundTruth; + HA->getProjectIRDB().getModule()->getGlobalList(); + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleBasicTest_02) { initialize({PathToLlFiles + "basic/basic_02_cpp_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleBasicTest_03) { initialize({PathToLlFiles + "basic/basic_03_cpp_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleBasicTest_04) { initialize({PathToLlFiles + "basic/basic_04_cpp_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } /* ============== CONTROL FLOW TESTS ============== */ @@ -116,35 +162,44 @@ TEST_F(IFDSConstAnalysisTest, HandleCFForTest_01) { initialize({PathToLlFiles + "control_flow/cf_for_01_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 12, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCFForTest_02) { initialize({PathToLlFiles + "control_flow/cf_for_02_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(4, 12, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCFIfTest_01) { initialize({PathToLlFiles + "control_flow/cf_if_01_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(4, 12, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCFIfTest_02) { initialize({PathToLlFiles + "control_flow/cf_if_02_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({}, Llvmconstsolver); + std::set GroundTruth{}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCFWhileTest_01) { initialize({PathToLlFiles + "control_flow/cf_while_01_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(5, 12, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } /* ============== POINTER TESTS ============== */ @@ -152,14 +207,18 @@ TEST_F(IFDSConstAnalysisTest, HandlePointerTest_01) { initialize({PathToLlFiles + "pointer/pointer_01_cpp_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandlePointerTest_02) { initialize({PathToLlFiles + "pointer/pointer_02_cpp_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, DISABLED_HandlePointerTest_03) { @@ -168,14 +227,18 @@ TEST_F(IFDSConstAnalysisTest, DISABLED_HandlePointerTest_03) { initialize({PathToLlFiles + "pointer/pointer_03_cpp_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({2, 3}, Llvmconstsolver); + SrcCodeLocationEntry Entry(4, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandlePointerTest_04) { initialize({PathToLlFiles + "pointer/pointer_04_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({3}, Llvmconstsolver); + SrcCodeLocationEntry Entry(5, 7, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } /* ============== GLOBAL TESTS ============== */ @@ -183,14 +246,21 @@ TEST_F(IFDSConstAnalysisTest, HandleGlobalTest_01) { initialize({PathToLlFiles + "global/global_01_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0}, Llvmconstsolver); + SrcCodeLocationEntry Entry( + 1, 0, HA->getProjectIRDB().getGlobalVariableDefinition("g1")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleGlobalTest_02) { initialize({PathToLlFiles + "global/global_02_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0, 1}, Llvmconstsolver); + SrcCodeLocationEntry Entry( + 1, 0, HA->getProjectIRDB().getGlobalVariableDefinition("g")); + SrcCodeLocationEntry EntryTwo(4, 7, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry, EntryTwo}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleGlobalTest_03) { @@ -198,8 +268,13 @@ TEST_F(IFDSConstAnalysisTest, HandleGlobalTest_03) { IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - /// The @llvm.global_ctors global variable is never immutable - compareResults({0, /*1,*/ 2}, Llvmconstsolver); + SrcCodeLocationEntry Entry( + 6, 10, HA->getProjectIRDB().getFunction("__cxx_global_var_init")); + SrcCodeLocationEntry EntryTwo( + 0, 0, HA->getProjectIRDB().getGlobalVariableDefinition("g")); + + std::set GroundTruth{Entry, EntryTwo}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, DISABLED_HandleGlobalTest_04) { @@ -208,7 +283,10 @@ TEST_F(IFDSConstAnalysisTest, DISABLED_HandleGlobalTest_04) { initialize({PathToLlFiles + "global/global_04_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0, 4}, Llvmconstsolver); + SrcCodeLocationEntry Entry( + 1, 0, HA->getProjectIRDB().getGlobalVariableDefinition("g1")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } /* ============== CALL TESTS ============== */ @@ -216,21 +294,28 @@ TEST_F(IFDSConstAnalysisTest, HandleCallParamTest_01) { initialize({PathToLlFiles + "call/param/call_param_01_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({5}, Llvmconstsolver); + SrcCodeLocationEntry Entry(5, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCallParamTest_02) { initialize({PathToLlFiles + "call/param/call_param_02_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({5}, Llvmconstsolver); + SrcCodeLocationEntry Entry(5, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCallParamTest_03) { initialize({PathToLlFiles + "call/param/call_param_03_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({}, Llvmconstsolver); + // SrcCodeLocationEntry Entry(, , HA->getProjectIRDB().getFunction("main")); + // std::set GroundTruth{Entry}; + std::set GroundTruth{}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, DISABLED_HandleCallParamTest_04) { @@ -248,7 +333,7 @@ TEST_F(IFDSConstAnalysisTest, DISABLED_HandleCallParamTest_05) { initialize({PathToLlFiles + "call/param/call_param_05_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({2}, Llvmconstsolver); + compareResults({}, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCallParamTest_06) { @@ -262,14 +347,18 @@ TEST_F(IFDSConstAnalysisTest, HandleCallParamTest_07) { initialize({PathToLlFiles + "call/param/call_param_07_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({6}, Llvmconstsolver); + SrcCodeLocationEntry Entry(6, 12, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCallParamTest_08) { initialize({PathToLlFiles + "call/param/call_param_08_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({4}, Llvmconstsolver); + SrcCodeLocationEntry Entry(9, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCallReturnTest_01) { @@ -283,14 +372,20 @@ TEST_F(IFDSConstAnalysisTest, HandleCallReturnTest_02) { initialize({PathToLlFiles + "call/return/call_ret_02_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 12, + HA->getProjectIRDB().getFunction("_Z3foov")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleCallReturnTest_03) { initialize({PathToLlFiles + "call/return/call_ret_03_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 12, + HA->getProjectIRDB().getFunction("_Z3foov")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } /* ============== ARRAY TESTS ============== */ @@ -328,7 +423,9 @@ TEST_F(IFDSConstAnalysisTest, HandleArrayTest_05) { initialize({PathToLlFiles + "array/array_05_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, HandleArrayTest_06) { @@ -336,7 +433,9 @@ TEST_F(IFDSConstAnalysisTest, HandleArrayTest_06) { IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); HA->getAliasInfo().print(llvm::errs()); - compareResults({1}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } TEST_F(IFDSConstAnalysisTest, DISABLED_HandleArrayTest_07) { @@ -359,7 +458,9 @@ TEST_F(IFDSConstAnalysisTest, HandleArrayTest_09) { initialize({PathToLlFiles + "array/array_09_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0}, Llvmconstsolver); + SrcCodeLocationEntry Entry(3, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } /* ============== STL ARRAY TESTS ============== */ @@ -374,7 +475,12 @@ TEST_F(IFDSConstAnalysisTest, HandleSTLArrayTest_02) { initialize({PathToLlFiles + "array/stl_array/stl_array_02_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0, 1}, Llvmconstsolver); + std::set GroundTruth = { + LineColFun{4, 0, "main"}, + GlobalVar{"__const.main.a"}, + }; + + compareResults(GroundTruth, Llvmconstsolver); } PHASAR_SKIP_TEST(TEST_F(IFDSConstAnalysisTest, HandleSTLArrayTest_03) { @@ -384,7 +490,13 @@ PHASAR_SKIP_TEST(TEST_F(IFDSConstAnalysisTest, HandleSTLArrayTest_03) { initialize({PathToLlFiles + "array/stl_array/stl_array_03_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({0, 1, 2}, Llvmconstsolver); + compareResults( + { + GlobalVar{"__const.main.a"}, + GlobalVar{".str"}, + LineColFun{4, 0, "main"}, + }, + Llvmconstsolver); }) TEST_F(IFDSConstAnalysisTest, DISABLED_HandleSTLArrayTest_04) { @@ -407,7 +519,9 @@ TEST_F(IFDSConstAnalysisTest, HandleSTLArrayTest_06) { initialize({PathToLlFiles + "array/stl_array/stl_array_06_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({2}, Llvmconstsolver); + SrcCodeLocationEntry Entry(4, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } /* ============== CSTRING TESTS ============== */ @@ -424,7 +538,9 @@ TEST_F(IFDSConstAnalysisTest, DISABLED_HandleCStringTest_02) { initialize({PathToLlFiles + "array/cstring/cstring_02_cpp_m2r_dbg.ll"}); IFDSSolver Llvmconstsolver(*Constproblem, &HA->getICFG()); Llvmconstsolver.solve(); - compareResults({2}, Llvmconstsolver); + SrcCodeLocationEntry Entry(4, 0, HA->getProjectIRDB().getFunction("main")); + std::set GroundTruth{Entry}; + compareResults(GroundTruth, Llvmconstsolver); } /* ============== STRUCTURE TESTS ============== */ diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp index e050acc5dc..390c347197 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp @@ -1,5 +1,6 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" @@ -11,9 +12,17 @@ #include "phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Value.h" + +#include "SourceMapping.h" +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" +#include #include using namespace std; @@ -78,48 +87,72 @@ class IFDSTaintAnalysisTest : public ::testing::Test { if (!TSF) { TSF = getDefaultConfig(); } + TaintProblem = createAnalysisProblem(*HA, &*TSF, EntryPoints); } - static void doAnalysis(const llvm::Twine &IRFile, - const LLVMTaintConfig &Config, - const map> &GroundTruth) { - HelperAnalyses HA(PathToLlFiles + IRFile, EntryPoints); - - auto TaintProblem = - createAnalysisProblem(HA, &Config, EntryPoints); - - IFDSSolver TaintSolver(TaintProblem, &HA.getICFG()); - TaintSolver.solve(); + void initialize(const llvm::Twine &IRFile, const LLVMTaintConfig *Config) { + HA.emplace(IRFile, EntryPoints); + TaintProblem = + createAnalysisProblem(*HA, Config, EntryPoints); + } - TaintSolver.dumpResults(); + template + static void + compare(const LeaksTy &Leaks, + const std::set> + &GroundTruth) { + auto GroundTruthEntries = getGroundTruthInsts(GroundTruth); + std::set> + FoundLeaks; - compare(TaintProblem.Leaks, GroundTruth); - } + for (const auto &Leak : Leaks) { + if (const auto *SinkInst = + llvm::dyn_cast_or_null(Leak.first)) { + for (const auto *LV : Leak.second) { + if (LV) { + if (const auto *LVValue = llvm::dyn_cast_or_null(LV)) { + FoundLeaks.insert({SinkInst, {LVValue}}); + } + } + } + } + } - static void doAnalysis(const llvm::Twine &IRFile, - const map> &GroundTruth) { - doAnalysis(IRFile, getDefaultConfig(), GroundTruth); + EXPECT_EQ(FoundLeaks, GroundTruthEntries); } template - static void compare(const LeaksTy &Leaks, - const map> &GroundTruth) { - map> FoundLeaks; + static void + compare(const LeaksTy &Leaks, + const std::set> + &GroundTruth) { + std::set> + GroundTruthEntries; + + for (const auto &Entry : GroundTruth) { + GroundTruthEntries.insert( + {getGroundTruthInst(std::get<0>(Entry)), std::get<1>(Entry)}); + } + + std::set> + FoundLeaks; + for (const auto &Leak : Leaks) { - int SinkId = stoi(getMetaDataID(Leak.first)); - set LeakedValueIds; - for (const auto *LV : Leak.second) { - LeakedValueIds.insert(getMetaDataID(LV)); + if (const auto *SinkInst = + llvm::dyn_cast_or_null(Leak.first)) { + for (const auto *LV : Leak.second) { + if (LV) { + if (const auto *LVValue = llvm::dyn_cast_or_null(LV)) { + FoundLeaks.insert({SinkInst, {LVValue}}); + } + } + } } - FoundLeaks.insert(make_pair(SinkId, LeakedValueIds)); } - EXPECT_EQ(FoundLeaks, GroundTruth); - } - void compareResults(const map> &GroundTruth) noexcept { - compare(TaintProblem->Leaks, GroundTruth); + EXPECT_EQ(FoundLeaks, GroundTruthEntries); } }; // Test Fixture @@ -127,64 +160,100 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_01) { initialize({PathToLlFiles + "dummy_source_sink/taint_01_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[13] = set{"12"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry = + SrcCodeLocationEntry(6, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo = + SrcCodeLocationEntry(6, 8, HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_01_m2r) { initialize({PathToLlFiles + "dummy_source_sink/taint_01_cpp_m2r_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[4] = set{"2"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(6, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(5, 11, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_02) { initialize({PathToLlFiles + "dummy_source_sink/taint_02_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[9] = set{"8"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(5, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(5, 8, HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_03) { initialize({PathToLlFiles + "dummy_source_sink/taint_03_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[18] = set{"17"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(6, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(6, 8, HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_04) { initialize({PathToLlFiles + "dummy_source_sink/taint_04_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[19] = set{"18"}; - GroundTruth[24] = set{"23"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(6, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(6, 8, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryThree(8, 3, + HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryFour(8, 8, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}, {EntryThree, EntryFour}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_05) { initialize({PathToLlFiles + "dummy_source_sink/taint_05_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[22] = set{"21"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(6, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(6, 8, HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_06) { initialize({PathToLlFiles + "dummy_source_sink/taint_06_cpp_m2r_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[5] = set{"main.0"}; - compareResults(GroundTruth); + + const auto &IRDB = HA->getProjectIRDB(); + SrcCodeLocationEntry Entry(5, 3, IRDB.getFunction("main")); + const auto *ArgValue = + testingLocInIR({ArgNo{0}}, IRDB, IRDB.getFunction("main")); + std::set> GroundTruth{ + {Entry, ArgValue}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_01) { @@ -192,9 +261,14 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_01) { {PathToLlFiles + "dummy_source_sink/taint_exception_01_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[14] = set{"13"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(12, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(12, 8, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_01_m2r) { @@ -202,9 +276,14 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_01_m2r) { {PathToLlFiles + "dummy_source_sink/taint_exception_01_cpp_m2r_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[5] = set{"0"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(12, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(10, 14, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_02) { @@ -212,9 +291,14 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_02) { {PathToLlFiles + "dummy_source_sink/taint_exception_02_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[16] = set{"15"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(11, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(11, 8, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_03) { @@ -222,10 +306,18 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_03) { {PathToLlFiles + "dummy_source_sink/taint_exception_03_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[11] = set{"10"}; - GroundTruth[20] = set{"19"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(11, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(11, 8, + HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryThree(14, 3, + HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryFour(14, 8, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}, {EntryThree, EntryFour}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_04) { @@ -233,9 +325,14 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_04) { {PathToLlFiles + "dummy_source_sink/taint_exception_04_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[32] = set{"31"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(16, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(16, 8, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_05) { @@ -244,9 +341,13 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_05) { IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[32] = set{"31"}; - compareResults(GroundTruth); + SrcCodeLocationEntry Entry(16, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(16, 8, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_06) { @@ -254,9 +355,14 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_06) { {PathToLlFiles + "dummy_source_sink/taint_exception_06_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[14] = set{"13"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(13, 5, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(13, 10, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_07) { @@ -264,9 +370,14 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_07) { {PathToLlFiles + "dummy_source_sink/taint_exception_07_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[30] = set{"29"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(14, 5, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(14, 10, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_08) { @@ -274,9 +385,14 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_08) { {PathToLlFiles + "dummy_source_sink/taint_exception_08_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[32] = set{"31"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(19, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(19, 8, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_09) { @@ -284,9 +400,14 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_09) { {PathToLlFiles + "dummy_source_sink/taint_exception_09_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[62] = set{"61"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(20, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(20, 8, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_10) { @@ -294,32 +415,59 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_10) { {PathToLlFiles + "dummy_source_sink/taint_exception_10_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[60] = set{"59"}; - compareResults(GroundTruth); -} -TEST_F(IFDSTaintAnalysisTest, TaintTest_DoubleFree_01) { - doAnalysis("double_free_01_c.ll", getDoubleFreeConfig(), - { - {6, {"5"}}, - }); -} + SrcCodeLocationEntry Entry(19, 5, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(19, 10, + HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; -TEST_F(IFDSTaintAnalysisTest, TaintTest_DoubleFree_02) { - doAnalysis("double_free_02_c.ll", getDoubleFreeConfig(), - { - {11, {"10"}}, - }); + compare(TaintProblem->Leaks, GroundTruth); } TEST_F(IFDSTaintAnalysisTest, TaintTest_LibSummary_01) { initialize({PathToLlFiles + "dummy_source_sink/taint_lib_sum_01_cpp_dbg.ll"}); IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); TaintSolver.solve(); - map> GroundTruth; - GroundTruth[20] = {"19"}; - compareResults(GroundTruth); + + SrcCodeLocationEntry Entry(8, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(8, 8, HA->getProjectIRDB().getFunction("main"), + [](const llvm::Instruction *Inst) { + return Inst->getOpcode() == + llvm::Instruction::FPToSI; + }); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); +} + +TEST_F(IFDSTaintAnalysisTest, TaintTest_DoubleFree_01) { + auto DoubleFreeConf = getDoubleFreeConfig(); + initialize({PathToLlFiles + "double_free_01_c_dbg.ll"}, &DoubleFreeConf); + IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); + TaintSolver.solve(); + + SrcCodeLocationEntry Entry(6, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(6, 8, HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); +} + +TEST_F(IFDSTaintAnalysisTest, TaintTest_DoubleFree_02) { + auto DoubleFreeConf = getDoubleFreeConfig(); + initialize({PathToLlFiles + "double_free_02_c_dbg.ll"}, &DoubleFreeConf); + IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG()); + TaintSolver.solve(); + + SrcCodeLocationEntry Entry(8, 3, HA->getProjectIRDB().getFunction("main")); + SrcCodeLocationEntry EntryTwo(8, 8, HA->getProjectIRDB().getFunction("main")); + std::set> GroundTruth{ + {Entry, EntryTwo}}; + + compare(TaintProblem->Leaks, GroundTruth); } int main(int Argc, char **Argv) { diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesTest.cpp index 51d7b04649..d68bdeec00 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariablesTest.cpp @@ -1,6 +1,7 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" @@ -9,16 +10,24 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/Utils/DebugOutput.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" +#include "SourceMapping.h" +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" #include #include +#include -using namespace std; using namespace psr; /* ============== TEST FIXTURE ============== */ @@ -46,19 +55,60 @@ class IFDSUninitializedVariablesTest : public ::testing::Test { void TearDown() override {} - void compareResults(map> &GroundTruth) { + void compareResults( + std::set> + &GroundTruthEntries) { + for (const auto &Entry : GroundTruthEntries) { + const auto *GTInst = std::get<0>(Entry); + llvm::outs() << "GTInst: " << GTInst << "\n"; + llvm::outs() << "*GTInst: " << *GTInst << "\n"; + + const auto *GTValue = std::get<1>(Entry); + llvm::outs() << "GTValue: " << GTValue << "\n"; + llvm::outs() << "*GTValue: " << *GTValue << "\n\n"; + } - map> FoundUninitUses; + std::set> + FoundUninitUses; for (const auto &Kvp : UninitProblem->getAllUndefUses()) { - auto InstID = stoi(getMetaDataID(Kvp.first)); - set UndefValueIds; + const auto *SourceInst = Kvp.first; + llvm::outs() << "SourceInst: " << SourceInst << "\n"; + llvm::outs() << "*SourceInst: " << *SourceInst << "\n"; + for (const auto *UV : Kvp.second) { - UndefValueIds.insert(getMetaDataID(UV)); + llvm::outs() << "UV: " << UV << "\n"; + llvm::outs() << "*UV: " << *UV << "\n\n"; + FoundUninitUses.insert({SourceInst, UV}); } - FoundUninitUses[InstID] = UndefValueIds; } - EXPECT_EQ(FoundUninitUses, GroundTruth); + EXPECT_EQ(FoundUninitUses, GroundTruthEntries) + << "Expected: " << PrettyPrinter{GroundTruthEntries} + << "; got: " << PrettyPrinter{FoundUninitUses}; + } + + void compareResults( + const std::set> + &GroundTruth) { + auto GroundTruthEntries = getGroundTruthInsts(GroundTruth, true); + compareResults(GroundTruthEntries); + } + + void compareResults( + const std::set> + &GroundTruth, + const LLVMProjectIRDB &IRDB) { + std::set> + GroundTruthEntries; + + for (const auto &Entry : GroundTruth) { + const auto *First = testingLocInIR(std::get<0>(Entry), IRDB); + const auto *FirstAsInst = llvm::dyn_cast(First); + const auto *Second = testingLocInIR(std::get<1>(Entry), IRDB); + GroundTruthEntries.insert({FirstAsInst, Second}); + } + + compareResults(GroundTruthEntries); } }; // Test Fixture @@ -66,8 +116,9 @@ TEST_F(IFDSUninitializedVariablesTest, UninitTest_01_SHOULD_NOT_LEAK) { initialize({PathToLlFiles + "all_uninit_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); + // all_uninit.cpp does not contain undef-uses - map> GroundTruth; + std::set> GroundTruth; compareResults(GroundTruth); } @@ -77,32 +128,44 @@ TEST_F(IFDSUninitializedVariablesTest, UninitTest_02_SHOULD_LEAK) { Solver.solve(); // binop_uninit uses uninitialized variable i in 'int j = i + 10;' - map> GroundTruth; + std::set> GroundTruth; + // %4 = load i32, i32* %2, ID: 6 ; %2 is the uninitialized variable i - GroundTruth[6] = {"1"}; // %5 = add nsw i32 %4, 10 ; %4 is undef, since it is loaded from // undefined alloca; not sure if it is necessary to report again - GroundTruth[7] = {"6"}; + const auto Entry = + SrcCodeLocationEntry(2, 0, HA->getICFG().getFunction("main")); + const auto EntryTwo = + SrcCodeLocationEntry(3, 11, HA->getICFG().getFunction("main")); + const auto EntryThree = + SrcCodeLocationEntry(3, 13, HA->getICFG().getFunction("main")); + GroundTruth.insert({EntryTwo, Entry}); + GroundTruth.insert({EntryThree, EntryTwo}); + compareResults(GroundTruth); } + TEST_F(IFDSUninitializedVariablesTest, UninitTest_03_SHOULD_LEAK) { initialize({PathToLlFiles + "callnoret_c_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); // callnoret uses uninitialized variable a in 'return a + 10;' of addTen(int) - map> GroundTruth; - - // %4 = load i32, i32* %2 ; %2 is the parameter a of addTen(int) containing - // undef - GroundTruth[5] = {"0"}; - // The same as in test2: is it necessary to report again? - GroundTruth[6] = {"5"}; - // %5 = load i32, i32* %2 ; %2 is the uninitialized variable a - GroundTruth[16] = {"9"}; - // The same as in test2: is it necessary to report again? (the analysis does - // not) - // GroundTruth[17] = {"16"}; + std::set> GroundTruth; + + const auto IntA = + SrcCodeLocationEntry(7, 7, HA->getICFG().getFunction("main")); + const auto CopyA = + SrcCodeLocationEntry(9, 10, HA->getICFG().getFunction("main")); + const auto ArgA = + SrcCodeLocationEntry(1, 16, HA->getICFG().getFunction("addTen")); + const auto LoadA = + SrcCodeLocationEntry(3, 10, HA->getICFG().getFunction("addTen")); + const auto Add = + SrcCodeLocationEntry(3, 12, HA->getICFG().getFunction("addTen")); + GroundTruth.insert({CopyA, IntA}); + GroundTruth.insert({Add, LoadA}); + GroundTruth.insert({LoadA, ArgA}); compareResults(GroundTruth); } @@ -111,25 +174,31 @@ TEST_F(IFDSUninitializedVariablesTest, UninitTest_04_SHOULD_NOT_LEAK) { initialize({PathToLlFiles + "ctor_default_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); + // ctor.cpp does not contain undef-uses - map> GroundTruth; + std::set> GroundTruth; + compareResults(GroundTruth); } - TEST_F(IFDSUninitializedVariablesTest, UninitTest_05_SHOULD_NOT_LEAK) { initialize({PathToLlFiles + "struct_member_init_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); + // struct_member_init.cpp does not contain undef-uses - map> GroundTruth; + std::set> GroundTruth; + compareResults(GroundTruth); } + TEST_F(IFDSUninitializedVariablesTest, UninitTest_06_SHOULD_NOT_LEAK) { initialize({PathToLlFiles + "struct_member_uninit_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); + // struct_member_uninit.cpp does not contain undef-uses - map> GroundTruth; + std::set> GroundTruth; + compareResults(GroundTruth); } /**************************************************************************************** @@ -151,12 +220,15 @@ Solver(*UninitProblem, false); Solver.solve(); compareResults(GroundTruth); } *****************************************************************************************/ + TEST_F(IFDSUninitializedVariablesTest, UninitTest_08_SHOULD_NOT_LEAK) { initialize({PathToLlFiles + "global_variable_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); + // global_variable.cpp does not contain undef-uses - map> GroundTruth; + std::set> GroundTruth; + compareResults(GroundTruth); } /**************************************************************************************** @@ -176,17 +248,21 @@ Solver(*UninitProblem, false); Solver.solve(); compareResults(GroundTruth); } *****************************************************************************************/ + TEST_F(IFDSUninitializedVariablesTest, UninitTest_10_SHOULD_LEAK) { initialize({PathToLlFiles + "return_uninit_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); - UninitProblem->emitTextReport(Solver.getSolverResults(), llvm::outs()); - map> GroundTruth; - //%2 = load i32, i32 %1 - GroundTruth[2] = {"0"}; - // What about this call? - // %3 = call i32 @_Z3foov() - // GroundTruth[8] = {""}; + + std::set> GroundTruth; + + const auto IntI = + SrcCodeLocationEntry(2, 7, HA->getICFG().getFunction("_Z3foov")); + const auto UseOfI = + SrcCodeLocationEntry(3, 10, HA->getICFG().getFunction("_Z3foov")); + + GroundTruth.insert({UseOfI, IntI}); + compareResults(GroundTruth); } @@ -195,15 +271,23 @@ TEST_F(IFDSUninitializedVariablesTest, UninitTest_11_SHOULD_NOT_LEAK) { initialize({PathToLlFiles + "sanitizer_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); - map> GroundTruth; + + std::set> GroundTruth; // all undef-uses are sanitized; // However, the uninitialized variable j is read, which causes the analysis to // report an undef-use // 6 => {2} - GroundTruth[6] = {"2"}; + const auto IntI = + SrcCodeLocationEntry(3, 7, HA->getICFG().getFunction("main")); + const auto UseOfI = + SrcCodeLocationEntry(4, 7, HA->getICFG().getFunction("main")); + + GroundTruth.insert({UseOfI, IntI}); + compareResults(GroundTruth); } + //--------------------------------------------------------------------- // Not relevant any more; Test case covered by UninitTest_11 //--------------------------------------------------------------------- @@ -225,23 +309,48 @@ TEST_F(IFDSUninitializedVariablesTest, UninitTest_13_SHOULD_NOT_LEAK) { initialize({PathToLlFiles + "sanitizer2_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); + // The undef-uses do not affect the program behaviour, but are of course still // found and reported - map> GroundTruth; - GroundTruth[9] = {"2"}; + std::set> GroundTruth; + + const auto IntJ = + SrcCodeLocationEntry(3, 7, HA->getICFG().getFunction("main")); + const auto LoadJ = + SrcCodeLocationEntry(5, 7, HA->getICFG().getFunction("main")); + + GroundTruth.insert({LoadJ, IntJ}); + compareResults(GroundTruth); } + TEST_F(IFDSUninitializedVariablesTest, UninitTest_14_SHOULD_LEAK) { initialize({PathToLlFiles + "uninit_c_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); - map> GroundTruth; - GroundTruth[14] = {"1"}; - GroundTruth[15] = {"2"}; - GroundTruth[16] = {"14", "15"}; + + std::set> GroundTruth; + + const auto IntA = + SrcCodeLocationEntry(2, 7, HA->getICFG().getFunction("main")); + const auto IntB = + SrcCodeLocationEntry(3, 7, HA->getICFG().getFunction("main")); + const auto LoadA = + SrcCodeLocationEntry(6, 11, HA->getICFG().getFunction("main")); + const auto Multiply = + SrcCodeLocationEntry(6, 13, HA->getICFG().getFunction("main")); + const auto LoadB = + SrcCodeLocationEntry(6, 15, HA->getICFG().getFunction("main")); + + GroundTruth.insert({LoadA, IntA}); + GroundTruth.insert({LoadB, IntB}); + GroundTruth.insert({Multiply, LoadA}); + GroundTruth.insert({Multiply, LoadB}); + compareResults(GroundTruth); } + /**************************************************************************************** * Fails probably due to field-insensitivity * @@ -275,20 +384,35 @@ GroundTruth; compareResults(GroundTruth); } *****************************************************************************************/ + TEST_F(IFDSUninitializedVariablesTest, UninitTest_16_SHOULD_LEAK) { initialize({PathToLlFiles + "growing_example_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); - map> GroundTruth; - // TODO remove GT[11] - GroundTruth[11] = {"0"}; - - GroundTruth[16] = {"2"}; - GroundTruth[18] = {"16"}; - GroundTruth[34] = {"24"}; - + std::set> GroundTruth; + + const auto ArgX = + SrcCodeLocationEntry(1, 18, HA->getICFG().getFunction("_Z8functionii")); + const auto IntI = + SrcCodeLocationEntry(2, 7, HA->getICFG().getFunction("_Z8functionii")); + const auto LoadX = + SrcCodeLocationEntry(3, 11, HA->getICFG().getFunction("_Z8functionii")); + const auto LoadI = + SrcCodeLocationEntry(5, 10, HA->getICFG().getFunction("_Z8functionii")); + const auto Add = + SrcCodeLocationEntry(5, 12, HA->getICFG().getFunction("_Z8functionii")); + const auto IntJ = + SrcCodeLocationEntry(10, 7, HA->getICFG().getFunction("main")); + const auto LoadJ = + SrcCodeLocationEntry(12, 16, HA->getICFG().getFunction("main")); + + // TODO remove GroundTruth.insert({LoadX, ArgX}) below + GroundTruth.insert({LoadX, ArgX}); + GroundTruth.insert({LoadI, IntI}); + GroundTruth.insert({Add, LoadI}); + GroundTruth.insert({LoadJ, IntJ}); compareResults(GroundTruth); } @@ -345,42 +469,139 @@ Solver(*UninitProblem, false); Solver.solve(); compareResults(GroundTruth); } *****************************************************************************************/ + TEST_F(IFDSUninitializedVariablesTest, UninitTest_20_SHOULD_LEAK) { initialize({PathToLlFiles + "recursion_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); - map> GroundTruth; - // Leaks at 11 and 14 due to field-insensitivity - GroundTruth[11] = {"2"}; - GroundTruth[14] = {"2"}; + std::set> GroundTruth; + + const auto IntI = + SrcCodeLocationEntry(9, 7, HA->getICFG().getFunction("main")); + + // Leaks due to field-insensitivity + + // %1 = load ptr, ptr %x.addr, align 8, !dbg !240, !psr.id !241 | ID: 11 + LineColFun LoadX{4, 12, "_Z3fooRii"}; + // %x.addr = alloca ptr, align 8 + LineColFun ArgAddrX{2, 15, "_Z3fooRii"}; + GroundTruth.insert({LoadX, ArgAddrX}); + // %2 = load ptr, ptr %x.addr + LineColFun LoadXTwo{5, 14, "_Z3fooRii"}; + GroundTruth.insert({LoadXTwo, ArgAddrX}); + + // Load uninitialized variable + + // %1 = load i32, ptr %j, align 4, !dbg !274, !psr.id !275 | ID: 31 + LineColFun LoadJ{11, 18, "main"}; + // %j = alloca i32, align 4 + LineColFun IntJ{10, 7, "main"}; + GroundTruth.insert({LoadJ, IntJ}); - // Load uninitialized variable i - GroundTruth[31] = {"24"}; // Load recursive return-value for returning it - GroundTruth[20] = {"1"}; + + // %4 = load ptr, ptr %retval + LineColFun FooExit{6, 1, "_Z3fooRii"}; + GroundTruth.insert({FooExit, OperandOf{0, FooExit}}); // Load return-value of foo in main - GroundTruth[29] = {"28"}; - // Analysis does not check uninit on actualparameters - // GroundTruth[32] = {"31"}; - compareResults(GroundTruth); + // %0 = load i32, ptr %call, align 4 + LineColFunLambda Load0{10, 11, "main", [](const llvm::Instruction *Inst) { + return llvm::isa(Inst); + }}; + // %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z3fooRii(ptr + // noundef nonnull align 4 dereferenceable(4) %i, i32 noundef 10) + LineColFunLambda CallFooRec{10, 11, "main", + [](const llvm::Instruction *Inst) { + return llvm::isa(Inst); + }}; + GroundTruth.insert({Load0, CallFooRec}); + // // Load return-value of foo in main + // GroundTruth.insert({FooExit, IntJ}); + + // *********** + // Load recursive return-value for returning it + // GroundTruth.insert({RetOfFoo, IntJ}); + // *********** + + // Load return-value of foo in main + // GroundTruth.insert({IntJ, RetOfFoo}); + + compareResults(GroundTruth, *HA->getICFG().getIRDB()); } + TEST_F(IFDSUninitializedVariablesTest, UninitTest_21_SHOULD_LEAK) { initialize({PathToLlFiles + "virtual_call_cpp_dbg.ll"}); IFDSSolver Solver(*UninitProblem, &HA->getICFG()); Solver.solve(); - map> GroundTruth = { - {3, {"0"}}, {8, {"5"}}, {10, {"5"}}, {35, {"34"}}, {37, {"17"}}}; + std::set> GroundTruth; + // %x.addr = alloca ptr, align 8 + const auto FooXAddr = + SrcCodeLocationEntry(3, 15, HA->getICFG().getFunction("_Z3fooRi")); + // %0 = load ptr, ptr %x.addr, align 8 + const auto FooXLoad = + SrcCodeLocationEntry(3, 27, HA->getICFG().getFunction("_Z3fooRi")); + // %x.addr = alloca ptr, align 8 + const auto BarXAddr = + SrcCodeLocationEntry(4, 15, HA->getICFG().getFunction("_Z3barRi")); + // %0 = load ptr, ptr %x.addr, align 8 + const auto Load = + SrcCodeLocationEntry(5, 3, HA->getICFG().getFunction("_Z3barRi")); + // %1 = load ptr, ptr %x.addr, align 8 + const auto LoadX = + SrcCodeLocationEntry(6, 10, HA->getICFG().getFunction("_Z3barRi")); + // + const auto IntI = + SrcCodeLocationEntry(9, 7, HA->getICFG().getFunction("main")); + // %j = alloca i32, align 4 + const auto IntJ = + SrcCodeLocationEntry(16, 7, HA->getICFG().getFunction("main")); + // %call = call noundef nonnull align 4 dereferenceable(4) ptr %1 + const auto BazCall = + SrcCodeLocationEntry(16, 11, HA->getICFG().getFunction("main"), + [](const llvm::Instruction *Inst) { + return llvm::isa(Inst); + }); + // This implementation to get %2 is bad, but it works + bool SkippedFirst = false; + // %2 = load i32, ptr %call, align 4 + const auto SecondLoadInIfEnd = SrcCodeLocationEntry( + 16, 11, HA->getICFG().getFunction("main"), + [&SkippedFirst](const llvm::Instruction *Inst) mutable { + if (llvm::isa(Inst)) { + if (!SkippedFirst) { + SkippedFirst = true; + return false; + } + return true; + } + + return false; + }); + // %3 = load i32, ptr %j, align 4 + const auto LoadJ = + SrcCodeLocationEntry(17, 10, HA->getICFG().getFunction("main")); + // is passed as a reference, so I isn't being loaded here + // const auto LoadI = + // SrcCodeLocationEntry(16, 15, HA->getICFG().getFunction("main")); + // 3 => {0}; due to field-insensitivity + GroundTruth.insert({FooXLoad, FooXAddr}); // 8 => {5}; due to field-insensitivity + GroundTruth.insert({Load, BarXAddr}); // 10 => {5}; due to alias-unawareness + GroundTruth.insert({LoadX, BarXAddr}); // 35 => {34}; actual leak + GroundTruth.insert({SecondLoadInIfEnd, BazCall}); // 37 => {17}; actual leak + GroundTruth.insert({LoadJ, IntJ}); + compareResults(GroundTruth); } + int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); return RUN_ALL_TESTS(); diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp index 060f438271..ee0353254a 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp @@ -194,8 +194,8 @@ static constexpr std::string_view LCATestFiles[] = { }; static constexpr std::string_view TaintTestFiles[] = { - "double_free_01_c.ll", - "double_free_02_c.ll", + "double_free_01_c_dbg.ll", + "double_free_02_c_dbg.ll", }; INSTANTIATE_TEST_SUITE_P(SparseIDETest, LinearConstant, diff --git a/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp b/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp index ccfb76b605..d7a2eff826 100644 --- a/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp +++ b/unittests/PhasarLLVM/Pointer/FilteredLLVMAliasSetTest.cpp @@ -123,8 +123,8 @@ static constexpr std::string_view TaintTestFiles[] = { "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", + "double_free_01_c_dbg.ll", + "double_free_02_c_dbg.ll", }; INSTANTIATE_TEST_SUITE_P(InteractiveIDESolverTest, TaintAnalysis, diff --git a/unittests/PhasarLLVM/TypeHierarchy/CMakeLists.txt b/unittests/PhasarLLVM/TypeHierarchy/CMakeLists.txt index fc190151ac..75f52a91d5 100644 --- a/unittests/PhasarLLVM/TypeHierarchy/CMakeLists.txt +++ b/unittests/PhasarLLVM/TypeHierarchy/CMakeLists.txt @@ -1,5 +1,5 @@ set(PointerSources - DIBasedTypeHierarchySerializationTest.cpp + DIBasedTypeHierarchySerializationTest.cpp DIBasedTypeHierarchyTest.cpp LLVMTypeHierarchySerializationTest.cpp LLVMTypeHierarchyTest.cpp diff --git a/unittests/TestUtils/SourceMapping.h b/unittests/TestUtils/SourceMapping.h new file mode 100644 index 0000000000..efb492e301 --- /dev/null +++ b/unittests/TestUtils/SourceMapping.h @@ -0,0 +1,32 @@ +#ifndef UNITTEST_TESTUTILS_SOURCEMAPPING_H +#define UNITTEST_TESTUTILS_SOURCEMAPPING_H + +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instruction.h" + +#include + +namespace psr::unittest { + +template +inline const llvm::Instruction * +getInstAtOrNull(const llvm::Function *F, uint32_t ReqLine, + uint32_t ReqColumn = 0, PredFn Pred = {}) { + assert(F != nullptr); + for (const auto &I : llvm::instructions(F)) { + auto [Line, Column] = psr::getLineAndColFromIR(&I); + if (Line == ReqLine && (ReqColumn == 0 || ReqColumn == Column) && + std::invoke(Pred, &I)) { + return &I; + } + } + return nullptr; +} + +} // namespace psr::unittest + +#endif // UNITTEST_TESTUTILS_SOURCEMAPPING_H diff --git a/unittests/TestUtils/SrcCodeLocationEntry.h b/unittests/TestUtils/SrcCodeLocationEntry.h new file mode 100644 index 0000000000..558ebcaab5 --- /dev/null +++ b/unittests/TestUtils/SrcCodeLocationEntry.h @@ -0,0 +1,661 @@ +#ifndef PHASAR_UTILS_SRCCODELOCATIONENTRY_H +#define PHASAR_UTILS_SRCCODELOCATIONENTRY_H + +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/Utilities.h" + +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +#include "SourceMapping.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace psr { + +struct GlobalVar { + llvm::StringRef Name; + + friend bool operator<(GlobalVar G1, GlobalVar G2) noexcept { + return G1.Name < G2.Name; + } + friend bool operator==(GlobalVar G1, GlobalVar G2) noexcept { + return G1.Name == G2.Name; + } + + [[nodiscard]] std::string str() const { + return std::string("GlobalVar { Name: ") + Name.str() + " }"; + } +}; +struct LineCol { + uint32_t Line{}; + uint32_t Col{}; + + friend bool operator<(LineCol LC1, LineCol LC2) noexcept { + return std::tie(LC1.Line, LC1.Col) < std::tie(LC2.Line, LC2.Col); + } + friend bool operator==(LineCol LC1, LineCol LC2) noexcept { + return std::tie(LC1.Line, LC1.Col) == std::tie(LC2.Line, LC2.Col); + } + [[nodiscard]] std::string str() const { + return std::string("LineCol { Line: ") + std::to_string(Line) + + "; Col: " + std::to_string(Col) + " }"; + } +}; +struct LineColFun { + uint32_t Line{}; + uint32_t Col{}; + llvm::StringRef InFunction{}; + + friend bool operator<(LineColFun LC1, LineColFun LC2) noexcept { + return std::tie(LC1.InFunction, LC1.Line, LC1.Col) < + std::tie(LC2.InFunction, LC2.Line, LC2.Col); + } + friend bool operator==(LineColFun LC1, LineColFun LC2) noexcept { + return std::tie(LC1.Line, LC1.Col, LC1.InFunction) == + std::tie(LC2.Line, LC2.Col, LC2.InFunction); + } + [[nodiscard]] std::string str() const { + return std::string("LineColFun { Line: ") + std::to_string(Line) + + "; Col: " + std::to_string(Col) + + "; InFunction: " + InFunction.str() + " }"; + } +}; +struct LineColFunLambda { + uint32_t Line{}; + uint32_t Col{}; + llvm::StringRef InFunction{}; + std::function Lambda{}; + + // TODO: impl lambda into std::tie and std::string + + friend bool operator<(LineColFunLambda LC1, LineColFunLambda LC2) noexcept { + return std::tie(LC1.InFunction, LC1.Line, LC1.Col) < + std::tie(LC2.InFunction, LC2.Line, LC2.Col); + } + friend bool operator==(LineColFunLambda LC1, LineColFunLambda LC2) noexcept { + return std::tie(LC1.Line, LC1.Col, LC1.InFunction) == + std::tie(LC2.Line, LC2.Col, LC2.InFunction); + } + [[nodiscard]] std::string str() const { + return std::string("LineColFun { Line: ") + std::to_string(Line) + + "; Col: " + std::to_string(Col) + "; Col: " + std::to_string(Col) + + "; InFunction: " + InFunction.str() + + "; Lambda: Cannot be converted to string yet. }"; + } +}; + +struct LineColFunOp { + uint32_t Line{}; + uint32_t Col{}; + llvm::StringRef InFunction{}; + uint32_t OpCode{}; + + friend bool operator<(LineColFunOp LC1, LineColFunOp LC2) noexcept { + return std::tie(LC1.InFunction, LC1.Line, LC1.Col, LC1.OpCode) < + std::tie(LC2.InFunction, LC2.Line, LC2.Col, LC2.OpCode); + } + friend bool operator==(LineColFunOp LC1, LineColFunOp LC2) noexcept { + return std::tie(LC1.Line, LC1.Col, LC1.InFunction, LC1.OpCode) == + std::tie(LC2.Line, LC2.Col, LC2.InFunction, LC2.OpCode); + } + [[nodiscard]] std::string str() const { + return std::string("LineColFunOp { Line: ") + std::to_string(Line) + + "; Col: " + std::to_string(Col) + + "; InFunction: " + InFunction.str() + + "; OpCode: " + llvm::Instruction::getOpcodeName(OpCode) + " }"; + } +}; +struct ArgNo { + uint32_t Idx{}; + + friend bool operator<(ArgNo A1, ArgNo A2) noexcept { return A1.Idx < A2.Idx; } + friend bool operator==(ArgNo A1, ArgNo A2) noexcept { + return A1.Idx == A2.Idx; + } + [[nodiscard]] std::string str() const { + return std::string("ArgNo { Idx: ") + std::to_string(Idx) + " }"; + } +}; +struct ArgInFun { + uint32_t Idx; + llvm::StringRef InFunction{}; + + friend bool operator<(ArgInFun A1, ArgInFun A2) noexcept { + return std::tie(A1.InFunction, A1.Idx) < std::tie(A2.InFunction, A2.Idx); + } + friend bool operator==(ArgInFun A1, ArgInFun A2) noexcept { + return std::tie(A1.Idx, A1.InFunction) == std::tie(A2.Idx, A2.InFunction); + } + [[nodiscard]] std::string str() const { + return std::string("ArgInFun { Idx: ") + std::to_string(Idx) + + "; InFunction: " + InFunction.str() + " }"; + } +}; + +struct RetVal { + llvm::StringRef InFunction; + + friend bool operator<(RetVal R1, RetVal R2) noexcept { + return R1.InFunction < R2.InFunction; + } + friend bool operator==(RetVal R1, RetVal R2) noexcept { + return R1.InFunction == R2.InFunction; + } + [[nodiscard]] std::string str() const { + return std::string("RetVal { InFunction: ") + InFunction.str() + " }"; + } +}; +struct RetStmt { + llvm::StringRef InFunction; + + friend bool operator<(RetStmt R1, RetStmt R2) noexcept { + return R1.InFunction < R2.InFunction; + } + friend bool operator==(RetStmt R1, RetStmt R2) noexcept { + return R1.InFunction == R2.InFunction; + } + [[nodiscard]] std::string str() const { + return std::string("RetStmt { InFunction: ") + InFunction.str() + " }"; + } +}; + +struct OperandOf { + uint32_t OperandIndex{}; + LineColFun Inst{}; + + friend bool operator<(OperandOf R1, OperandOf R2) noexcept { + return std::tie(R1.OperandIndex, R2.Inst) < + std::tie(R2.OperandIndex, R2.Inst); + } + friend bool operator==(OperandOf R1, OperandOf R2) noexcept { + return R1.OperandIndex == R2.OperandIndex && R1.Inst == R2.Inst; + } + [[nodiscard]] std::string str() const { + return std::string("OperandOf { OperandIndex: ") + + std::to_string(OperandIndex) + "; Inst: " + Inst.str() + " }"; + } +}; + +struct TestingSrcLocation + : public std::variant { + using VarT = + std::variant; + using VarT::variant; + + template [[nodiscard]] constexpr bool isa() const noexcept { + return std::holds_alternative(*this); + } + template + [[nodiscard]] constexpr const T *dyn_cast() const noexcept { + return std::get_if(this); + } + template [[nodiscard]] constexpr T *dyn_cast() noexcept { + return std::get_if(this); + } + [[nodiscard]] std::string str() const { + return std::visit([](const auto &Val) { return Val.str(); }, *this); + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const TestingSrcLocation &Loc) { + return OS << Loc.str(); + } + friend std::ostream &operator<<(std::ostream &OS, + const TestingSrcLocation &Loc) { + return OS << Loc.str(); + } +}; + +} // namespace psr + +namespace std { +template <> struct hash { + size_t operator()(psr::LineCol LC) const noexcept { + return llvm::hash_value(std::make_pair(LC.Line, LC.Col)); + } +}; +template <> struct hash { + size_t operator()(psr::LineColFun LCF) const noexcept { + return llvm::hash_combine( + llvm::hash_value(std::make_pair(LCF.Line, LCF.Col)), LCF.InFunction); + } +}; +template <> struct hash { + size_t operator()(psr::LineColFunLambda LCF) const noexcept { + return llvm::hash_combine( + llvm::hash_value(std::make_pair(LCF.Line, LCF.Col)), LCF.InFunction); + } +}; +template <> struct hash { + size_t operator()(psr::LineColFunOp LCF) const noexcept { + return llvm::hash_combine( + llvm::hash_value(std::make_pair(LCF.Line, LCF.Col)), LCF.InFunction, + LCF.OpCode); + } +}; +template <> struct hash { + size_t operator()(psr::GlobalVar GV) const noexcept { + return llvm::hash_value(GV.Name); + } +}; +template <> struct hash { + size_t operator()(psr::ArgNo Arg) const noexcept { + return llvm::hash_value(Arg.Idx); + } +}; +template <> struct hash { + size_t operator()(psr::ArgInFun Arg) const noexcept { + return llvm::hash_combine(Arg.Idx, Arg.InFunction); + } +}; + +template <> struct hash { + size_t operator()(psr::RetVal Ret) const noexcept { + return llvm::hash_value(Ret.InFunction); + } +}; + +template <> struct hash { + size_t operator()(psr::RetStmt Ret) const noexcept { + return llvm::hash_value(Ret.InFunction); + } +}; + +template <> struct hash { + size_t operator()(psr::OperandOf Op) const noexcept { + return llvm::hash_combine(Op.OperandIndex, + hash{}(Op.Inst)); + } +}; + +template <> struct hash { + size_t operator()(const psr::TestingSrcLocation &Loc) const noexcept { + return std::hash{}(Loc); + } +}; +} // namespace std + +namespace psr { + +[[nodiscard]] inline const llvm::Value * +testingLocInIR(TestingSrcLocation Loc, + const ProjectIRDBBase &IRDB, + const llvm::Function *InterestingFunction = nullptr) { + const auto GetFunction = [&IRDB](llvm::StringRef Name) { + const auto *InFun = IRDB.getFunctionDefinition(Name); + if (!InFun) { + llvm::report_fatal_error("Required function '" + Name + + "' does not exist in the IR!"); + } + return InFun; + }; + return std::visit( + psr::Overloaded{ + [=](LineCol LC) -> llvm ::Value const * { + if (!InterestingFunction) { + llvm::report_fatal_error( + "You must provide an InterestingFunction as last parameter " + "to testingLocInIR(), if trying to resolve a LineCol; " + "alternatively use LineColFun instead."); + } + + return unittest::getInstAtOrNull(InterestingFunction, LC.Line, + LC.Col); + }, + [&](LineColFun LC) -> llvm ::Value const * { + const auto *InFun = GetFunction(LC.InFunction); + return unittest::getInstAtOrNull(InFun, LC.Line, LC.Col); + }, + [&](LineColFunLambda LC) -> llvm ::Value const * { + const auto *InFun = GetFunction(LC.InFunction); + return unittest::getInstAtOrNull(InFun, LC.Line, LC.Col, LC.Lambda); + }, + [&](LineColFunOp LC) -> llvm ::Value const * { + const auto *InFun = GetFunction(LC.InFunction); + return unittest::getInstAtOrNull( + InFun, LC.Line, LC.Col, [Op = LC.OpCode](const auto *Inst) { + return Inst->getOpcode() == Op; + }); + }, + [&IRDB](GlobalVar GV) -> llvm ::Value const * { + return IRDB.getModule()->getGlobalVariable(GV.Name, true); + }, + [=](ArgNo A) -> llvm ::Value const * { + if (!InterestingFunction) { + llvm::report_fatal_error( + "You must provide an InterestingFunction as last parameter " + "to testingLocInIR(), if trying to resolve an ArgNo; " + "alternatively use ArgInFun instead."); + } + if (InterestingFunction->arg_size() <= A.Idx) { + llvm::report_fatal_error( + "Argument index " + llvm::Twine(A.Idx) + + " is out of range (" + + llvm::Twine(InterestingFunction->arg_size()) + ")!"); + } + return InterestingFunction->getArg(A.Idx); + }, + [&](ArgInFun A) -> llvm ::Value const * { + const auto *InFun = GetFunction(A.InFunction); + if (InFun->arg_size() <= A.Idx) { + llvm::report_fatal_error("Argument index " + llvm::Twine(A.Idx) + + " is out of range (" + + llvm::Twine(InFun->arg_size()) + ")!"); + } + return InFun->getArg(A.Idx); + }, + [&](RetVal R) -> llvm::Value const * { + const auto *InFun = GetFunction(R.InFunction); + for (const auto &BB : llvm::reverse(InFun->getBasicBlockList())) { + if (const auto *Ret = + llvm::dyn_cast(BB.getTerminator())) { + return Ret->getReturnValue(); + } + } + llvm::report_fatal_error("No return stmt in function " + + R.InFunction); + }, + [&](RetStmt R) -> llvm::Value const * { + const auto *InFun = GetFunction(R.InFunction); + for (const auto &BB : llvm::reverse(InFun->getBasicBlockList())) { + if (const auto *Ret = + llvm::dyn_cast(BB.getTerminator())) { + return Ret; + } + } + llvm::report_fatal_error("No return stmt in function " + + R.InFunction); + }, + [&](OperandOf Op) -> llvm::Value const * { + const auto *Inst = llvm::dyn_cast_if_present( + testingLocInIR(Op.Inst, IRDB)); + if (!Inst) { + return nullptr; + } + + if (Inst->getNumOperands() <= Op.OperandIndex) { + llvm::report_fatal_error("Requested operand index " + + llvm::Twine(Op.OperandIndex) + + " is out of bounds for instruction " + + llvm::Twine(llvmIRToString(Inst))); + } + + return Inst->getOperand(Op.OperandIndex); + }, + }, + Loc); +} + +template +[[nodiscard]] inline std::set +convertTestingLocationSetInIR( + const SetTy &Locs, const ProjectIRDBBase &IRDB, + const llvm::Function *InterestingFunction = nullptr) { + std::set Ret; + llvm::transform(Locs, std::inserter(Ret, Ret.end()), + [&](TestingSrcLocation Loc) { + return testingLocInIR(Loc, IRDB, InterestingFunction); + }); + return Ret; +} + +template +[[nodiscard]] inline auto convertTestingLocationSetMapInIR( + const MapTy &Locs, const ProjectIRDBBase &IRDB, + const llvm::Function *InterestingFunction = nullptr) { + std::map> Ret; + llvm::transform( + Locs, std::inserter(Ret, Ret.end()), [&](const auto &LocAndSet) { + const auto &[InstLoc, Set] = LocAndSet; + const auto *LocVal = llvm::dyn_cast_if_present( + testingLocInIR(InstLoc, IRDB, InterestingFunction)); + auto ConvSet = + convertTestingLocationSetInIR(Set, IRDB, InterestingFunction); + return std::make_pair(LocVal, std::move(ConvSet)); + }); + return Ret; +} + +struct SrcCodeLocationEntry { + SrcCodeLocationEntry( + uint32_t Line, uint32_t Column, + std::variant + Context) + : Line(Line), Column(Column), Context(Context) {} + SrcCodeLocationEntry( + uint32_t Line, uint32_t Column, + std::variant + Context, + std::function LambdaFunc) + : Line(Line), Column(Column), LambdaFunc(std::move(LambdaFunc)), + Context(Context) {} + uint32_t Line = 0; + uint32_t Column = 0; + std::function LambdaFunc = nullptr; + std::variant Context; + + bool operator==(const SrcCodeLocationEntry &Other) const { + return Line == Other.Line && Column == Other.Column; + } + bool operator<(const SrcCodeLocationEntry &Other) const { + return std::tie(Line, Column) < std::tie(Other.Line, Other.Column); + } +}; + +inline const llvm::Instruction * +getGroundTruthInst(const SrcCodeLocationEntry &Entry) { + if (const auto *GlobalVar = + std::get_if(&Entry.Context)) { + return llvm::dyn_cast_or_null(*GlobalVar); + } + + if (const auto *Func = std::get_if(&Entry.Context)) { + if (Entry.LambdaFunc) { + return unittest::getInstAtOrNull(*Func, Entry.Line, Entry.Column, + Entry.LambdaFunc); + } + + return unittest::getInstAtOrNull(*Func, Entry.Line, Entry.Column); + } + + llvm::report_fatal_error("Unknown variant type.\n"); +} + +inline const llvm::Instruction * +getInstFromEntryOrNull(const SrcCodeLocationEntry &Entry) { + if (const auto *GlobalVar = + std::get_if(&Entry.Context)) { + return llvm::dyn_cast_or_null(*GlobalVar); + } + + if (const auto *Func = std::get_if(&Entry.Context)) { + if (Entry.LambdaFunc) { + return unittest::getInstAtOrNull(*Func, Entry.Line, Entry.Column, + Entry.LambdaFunc); + } + return unittest::getInstAtOrNull(*Func, Entry.Line, Entry.Column); + } + + llvm::report_fatal_error("Unknown variant type.\n"); +} + +inline const llvm::Value * +getValueFromEntryOrNull(const SrcCodeLocationEntry &Entry) { + if (const auto *GlobalVar = + std::get_if(&Entry.Context)) { + return llvm::dyn_cast_or_null(*GlobalVar); + } + + if (const auto *Func = std::get_if(&Entry.Context)) { + if (Entry.LambdaFunc) { + if (const auto *Inst = unittest::getInstAtOrNull( + *Func, Entry.Line, Entry.Column, Entry.LambdaFunc)) { + return llvm::dyn_cast_or_null(Inst); + } + } + if (const auto *Inst = + unittest::getInstAtOrNull(*Func, Entry.Line, Entry.Column)) { + return llvm::dyn_cast_or_null(Inst); + } + } + + llvm::report_fatal_error("Unknown variant type.\n"); +} + +inline std::set> +getGroundTruthInsts( + const std::set> + &GroundTruth, + bool PrintData = false) { + std::set> + GroundTruthEntries; + + for (const auto &Entry : GroundTruth) { + const auto &FirstEntry = std::get<0>(Entry); + const auto &SecondEntry = std::get<1>(Entry); + const llvm::Instruction *CurrInst = getInstFromEntryOrNull(FirstEntry); + const llvm::Value *CurrVal = getValueFromEntryOrNull(SecondEntry); + + if (!CurrInst) { + if (PrintData) { + llvm::outs() << "FirstEntry.Line: " << FirstEntry.Line + << " - FirstEntry.Column: " << FirstEntry.Column << "\n"; + } + llvm::report_fatal_error("Couldn't cast first entry to instruction\n"); + continue; + } + + if (!CurrVal) { + if (PrintData) { + llvm::outs() << "SecondEntry.Line: " << SecondEntry.Line + << " - SecondEntry.Column: " << SecondEntry.Column << "\n"; + } + llvm::report_fatal_error("Couldn't cast second entry to value\n"); + continue; + } + + if (PrintData) { + llvm::outs() << "FirstEntry.Line: " << FirstEntry.Line + << " - FirstEntry.Column: " << FirstEntry.Column << "\n"; + llvm::outs() << "CurrInst: " << CurrInst << "\n"; + llvm::outs() << "llvmIRToString(CurrInst): " << llvmIRToString(CurrInst) + << "\n"; + llvm::outs() << "\nSecondEntry.Line: " << SecondEntry.Line + << " - SecondEntry.Column: " << SecondEntry.Column << "\n"; + llvm::outs() << "CurrVal: " << CurrVal << "\n"; + llvm::outs() << "llvmIRToString(CurrVal): " << llvmIRToString(CurrVal) + << "\n"; + } + GroundTruthEntries.insert({CurrInst, CurrVal}); + } + + return GroundTruthEntries; +}; + +inline std::set +getGroundTruthInsts(const std::set &GroundTruth) { + std::set GroundTruthEntries; + + for (const auto &Entry : GroundTruth) { + if (std::get_if(&Entry.Context)) { + llvm::report_fatal_error("Cannot cast global variable to Instruction\n"); + } + + if (const auto *Func = + std::get_if(&Entry.Context)) { + if (Entry.LambdaFunc) { + GroundTruthEntries.insert(unittest::getInstAtOrNull( + *Func, Entry.Line, Entry.Column, Entry.LambdaFunc)); + } else { + GroundTruthEntries.insert( + unittest::getInstAtOrNull(*Func, Entry.Line, Entry.Column)); + } + continue; + } + llvm::report_fatal_error("Unknown variant type.\n"); + } + + return GroundTruthEntries; +}; + +inline std::set +getGroundTruthValues(const std::set &GroundTruth) { + std::set GroundTruthEntries; + + for (const auto &Entry : GroundTruth) { + if (const auto *Func = + std::get_if(&Entry.Context)) { + if (Entry.LambdaFunc) { + if (const auto *FuncVariantInst = unittest::getInstAtOrNull( + *Func, Entry.Line, Entry.Column, Entry.LambdaFunc)) { + if (const auto *CurrVal = + llvm::dyn_cast_or_null(FuncVariantInst)) { + GroundTruthEntries.insert(CurrVal); + continue; + } + llvm::errs() + << "FuncVariantInst Instruction couldn't be cast to value.\n"; + } + + continue; + } + + if (const auto *FuncVariantInst = + unittest::getInstAtOrNull(*Func, Entry.Line, Entry.Column)) { + llvm::outs() << "FuncVariantInst: " << FuncVariantInst << "\n"; + llvm::outs() << "*FuncVariantInst: " << *FuncVariantInst << "\n"; + if (const auto *CurrVal = + llvm::dyn_cast_or_null(FuncVariantInst)) { + GroundTruthEntries.insert(CurrVal); + continue; + } + + llvm::errs() + << "FuncVariantInst Instruction couldn't be cast to value.\n"; + } else { + llvm::errs() << "getInstAtOrNull returned null\n"; + llvm::errs() << "Entry.Line: " << Entry.Line << "\n"; + llvm::errs() << "Entry.Column: " << Entry.Column << "\n"; + llvm::errs() << "*Func: " << **Func << "\n"; + } + + continue; + } + + if (const auto *GlobalVar = + std::get_if(&Entry.Context)) { + GroundTruthEntries.insert(llvm::cast(*GlobalVar)); + continue; + } + + llvm::report_fatal_error("Unknown variant type.\n"); + } + + return GroundTruthEntries; +}; + +} // namespace psr + +#endif diff --git a/unittests/Utils/AnalysisPrinterTest.cpp b/unittests/Utils/AnalysisPrinterTest.cpp index 546c9d3049..3744c9f47d 100644 --- a/unittests/Utils/AnalysisPrinterTest.cpp +++ b/unittests/Utils/AnalysisPrinterTest.cpp @@ -11,10 +11,13 @@ #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/DefaultAnalysisPrinter.h" -#include "llvm/ADT/DenseMap.h" +#include "llvm/IR/Instruction.h" +#include "llvm/Support/raw_ostream.h" +#include "SrcCodeLocationEntry.h" #include "TestConfig.h" #include "gtest/gtest.h" + using namespace psr; using CallBackPairTy = std::pair::config_callback_t, IDEExtendedTaintAnalysis<>::config_callback_t>; @@ -29,34 +32,47 @@ class GroundTruthCollector public: // constructor init Groundtruth in each fixture - GroundTruthCollector(llvm::DenseMap> &GroundTruth) - : GroundTruth(GroundTruth){}; - - void findAndRemove(llvm::DenseMap> &Map1, - llvm::DenseMap> &Map2) { - for (auto Entry = Map1.begin(); Entry != Map1.end();) { - auto Iter = Map2.find(Entry->first); - if (Iter != Map2.end() && Iter->second == Entry->second) { - Map2.erase(Iter); - } - ++Entry; - } - } + GroundTruthCollector( + const LLVMProjectIRDB &IRDB, + const std::map> + &GroundTruth) + : GroundTruth(convertTestingLocationSetMapInIR(GroundTruth, IRDB)) {}; private: void doOnResult(n_t Instr, d_t DfFact, l_t /*LatticeElement*/, DataFlowAnalysisType /*AnalysisType*/) override { - llvm::DenseMap> FoundLeak; - int SinkId = stoi(getMetaDataID(Instr)); - std::set LeakedValueIds; - LeakedValueIds.insert(getMetaDataID((DfFact)->base())); - FoundLeak.try_emplace(SinkId, LeakedValueIds); - findAndRemove(FoundLeak, GroundTruth); + + auto It = GroundTruth.find(Instr); + EXPECT_TRUE(It != GroundTruth.end() && It->second.erase(DfFact->base())) + << "Did not expect finding a leak of " << DToString(DfFact) << " at " + << llvmIRToString(Instr) << '\n'; + if (It != GroundTruth.end() && It->second.empty()) { + GroundTruth.erase(It); + } } - void doOnFinalize() override { EXPECT_TRUE(GroundTruth.empty()); } + std::string printGroundTruth() { + std::string Ret; + llvm::raw_string_ostream OS(Ret); + OS << "{\n"; + for (const auto &[Inst, Facts] : GroundTruth) { + OS << " " << llvmIRToString(Inst) << ": {\n"; + for (const auto *Val : Facts) { + OS << " " << llvmIRToString(Val) << '\n'; + } + } + OS << "}\n"; + + return Ret; + } + + void doOnFinalize() override { + EXPECT_TRUE(GroundTruth.empty()) + << "Elements of GroundTruth not found: " << printGroundTruth(); + } - llvm::DenseMap> GroundTruth{}; + std::map> + GroundTruth{}; }; class AnalysisPrinterTest : public ::testing::Test { @@ -65,7 +81,8 @@ class AnalysisPrinterTest : public ::testing::Test { const std::vector EntryPoints = {"main"}; void doAnalysisTest( - llvm::StringRef IRFile, GroundTruthCollector >Printer, + llvm::StringRef IRFile, + const std::map> >, std::variant Config) { HelperAnalyses Helpers(PathToLlFiles + IRFile, EntryPoints); @@ -86,7 +103,8 @@ class AnalysisPrinterTest : public ::testing::Test { auto TaintProblem = createAnalysisProblem>( Helpers, TConfig, EntryPoints); - TaintProblem.setAnalysisPrinter(>Printer); + GroundTruthCollector GTCollector(Helpers.getProjectIRDB(), GT); + TaintProblem.setAnalysisPrinter(>Collector); IDESolver Solver(TaintProblem, &Helpers.getICFG()); Solver.solve(); @@ -97,8 +115,10 @@ class AnalysisPrinterTest : public ::testing::Test { /* ============== BASIC TESTS ============== */ TEST_F(AnalysisPrinterTest, HandleBasicTest_01) { - llvm::DenseMap> GroundTruth; - GroundTruth[7] = {"0"}; + std::map> GroundTruth; + GroundTruth[LineColFun{8, 3, "main"}] = { + LineColFun{4, 14, "main"}, + }; TaintConfigData Config; @@ -113,16 +133,16 @@ TEST_F(AnalysisPrinterTest, HandleBasicTest_01) { Config.Functions.push_back(std::move(FuncDataMain)); Config.Functions.push_back(std::move(FuncDataPrint)); - GroundTruthCollector GroundTruthPrinter = {GroundTruth}; - doAnalysisTest("xtaint01_json_cpp_dbg.ll", GroundTruthPrinter, &Config); + doAnalysisTest("xtaint01_json_cpp_dbg.ll", GroundTruth, &Config); } TEST_F(AnalysisPrinterTest, XTaint01) { - llvm::DenseMap> GroundTruth; + std::map> GroundTruth; - GroundTruth[13] = {"7"}; - GroundTruthCollector GroundTruthPrinter = {GroundTruth}; - doAnalysisTest("xtaint01_cpp.ll", GroundTruthPrinter, std::monostate{}); + GroundTruth[LineColFun{8, 3, "main"}] = { + LineColFun{7, 48, "main"}, + }; + doAnalysisTest("xtaint01_cpp_dbg.ll", GroundTruth, std::monostate{}); } // main function for the test case