#include #include #include #include #include #include #include #include #include "fold/cli/scan_options.hpp" #include "fold/cli/scan_runner.hpp" #include "fold/detect/summary_store.hpp" #include "fold/frontend/comp_db.hpp" namespace { struct TempDir { std::filesystem::path path; TempDir() : path(std::filesystem::temp_directory_path() / ("fold-yams-integration-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()))) { std::filesystem::create_directories(path); } ~TempDir() { std::filesystem::remove_all(path); } }; void writeFile(const std::filesystem::path& path, const std::string& content) { std::ofstream(path) << content; } void writeCompileDb(const std::filesystem::path& dir, const std::filesystem::path& src) { nlohmann::json db = nlohmann::json::array(); db.push_back({ {"directory", dir.string()}, {"command", std::string("clang++ -std=c++20 -c ") + src.string()}, {"file", src.string()}, }); writeFile(dir / "compile_commands.json", db.dump()); } } // namespace TEST_CASE("yams taint integration: readString to system", "[integration][yams][taint]") { TempDir dir; const auto src = dir.path / "main.cpp"; writeFile(src, "namespace std {\n" " class string {\n" " public:\n" " const char* c_str() const;\n" " };\n" "}\n" "namespace yams::daemon {\n" " struct BinaryDeserializer {\n" " std::string readString();\n" " };\n" "}\n" "extern \"C\" int system(const char*);\n" "int run(yams::daemon::BinaryDeserializer& bd) {\n" " std::string cmd = bd.readString();\n" " return system(cmd.c_str());\n" "}\n"); writeCompileDb(dir.path, src); std::string err; auto db = fold::loadCompilationDatabase(dir.path.string(), err); REQUIRE(db); fold::cli::ScanOptions opts; opts.compile_db = dir.path.string(); opts.detectors = {"taint-track"}; auto result = fold::cli::runDetectorsOnShard(*db, opts, {src.string()}, /*include_clone_clustering=*/false); bool saw_taint = false; for (const auto& finding : result.findings) { if (finding.kind == fold::FindingKind::TaintTrack) { saw_taint = true; } } REQUIRE(saw_taint); } TEST_CASE("yams taint integration: Result::value() propagation", "[integration][yams][taint]") { TempDir dir; const auto src = dir.path / "main.cpp"; writeFile(src, "namespace std {\n" " class string {\n" " public:\n" " const char* c_str() const;\n" " };\n" "}\n" "template\n" "struct Result {\n" " T val;\n" " T& value() { return val; }\n" "};\n" "namespace yams::daemon {\n" " struct BinaryDeserializer {\n" " std::string readString();\n" " };\n" "}\n" "extern \"C\" int system(const char*);\n" "int run(yams::daemon::BinaryDeserializer& bd) {\n" " Result cmd;\n" " cmd.val = bd.readString();\n" " return system(cmd.value().c_str());\n" "}\n"); writeCompileDb(dir.path, src); std::string err; auto db = fold::loadCompilationDatabase(dir.path.string(), err); REQUIRE(db); fold::cli::ScanOptions opts; opts.compile_db = dir.path.string(); opts.detectors = {"taint-track"}; auto result = fold::cli::runDetectorsOnShard(*db, opts, {src.string()}, /*include_clone_clustering=*/false); bool saw_taint = false; for (const auto& finding : result.findings) { if (finding.kind == fold::FindingKind::TaintTrack) { saw_taint = true; } } REQUIRE(saw_taint); }