171 lines
5.6 KiB
C++
171 lines
5.6 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
#include <vector>
|
|
|
|
#include "fold/fuzz/prediction_match.hpp"
|
|
|
|
TEST_CASE("fuzz correlation selects the hazard compatible with the sanitizer crash",
|
|
"[fuzz][prediction-match]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "heap-buffer-overflow";
|
|
report.file = "/tmp/project/target.cpp";
|
|
report.line = 42;
|
|
report.column = 7;
|
|
|
|
std::vector<fold::fuzz::FindingPrediction> predictions = {
|
|
{"null-deref:/tmp/project/target.cpp:42:7",
|
|
"target",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/target.cpp", 42, 7}},
|
|
{"oob-access:/tmp/project/target.cpp:42:7",
|
|
"target",
|
|
fold::FindingKind::OOBAccess,
|
|
{"/tmp/project/target.cpp", 42, 7}},
|
|
};
|
|
|
|
auto matched = fold::fuzz::matchSanitizerReport(report, predictions);
|
|
REQUIRE(matched == 1);
|
|
}
|
|
|
|
TEST_CASE("fuzz correlation rejects same-basename crashes from another directory",
|
|
"[fuzz][prediction-match]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "SEGV";
|
|
report.file = "/tmp/other/target.cpp";
|
|
report.line = 12;
|
|
|
|
std::vector<fold::fuzz::FindingPrediction> predictions = {
|
|
{"null-deref:/tmp/project/target.cpp:12:0",
|
|
"target",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/target.cpp", 12, 0}},
|
|
};
|
|
|
|
REQUIRE_FALSE(fold::fuzz::matchSanitizerReport(report, predictions));
|
|
}
|
|
|
|
TEST_CASE("fuzz correlation accepts relative ASan source paths", "[fuzz][prediction-match]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "SEGV";
|
|
report.file = "fixture.c";
|
|
report.line = 6;
|
|
report.function = "leaky";
|
|
|
|
std::vector<fold::fuzz::FindingPrediction> predictions = {
|
|
{"null-deref:fixture.c:6:16",
|
|
"leaky",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/fixture.c", 6, 16}},
|
|
};
|
|
|
|
REQUIRE(fold::fuzz::matchSanitizerReport(report, predictions) == 0);
|
|
}
|
|
|
|
TEST_CASE("fuzz correlation rejects incompatible concrete failure classes",
|
|
"[fuzz][prediction-match]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "heap-buffer-overflow";
|
|
report.file = "/tmp/project/target.cpp";
|
|
report.line = 9;
|
|
|
|
std::vector<fold::fuzz::FindingPrediction> predictions = {
|
|
{"null-deref:/tmp/project/target.cpp:9:0",
|
|
"target",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/target.cpp", 9, 0}},
|
|
};
|
|
|
|
REQUIRE_FALSE(fold::fuzz::matchSanitizerReport(report, predictions));
|
|
}
|
|
|
|
TEST_CASE("fuzz correlation accepts a unique compatible function for locationless reports",
|
|
"[fuzz][prediction-match]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "SEGV";
|
|
report.function = "leaky+0x70";
|
|
|
|
std::vector<fold::fuzz::FindingPrediction> predictions = {
|
|
{"null-deref:fixture.c:6:16",
|
|
"leaky",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/fixture.c", 6, 16}},
|
|
{"oob-access:fixture.c:9:3",
|
|
"other",
|
|
fold::FindingKind::OOBAccess,
|
|
{"/tmp/project/fixture.c", 9, 3}},
|
|
};
|
|
|
|
REQUIRE(fold::fuzz::matchSanitizerReport(report, predictions) == 0);
|
|
}
|
|
|
|
TEST_CASE("fuzz correlation rejects ambiguous locationless reports", "[fuzz][prediction-match]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "SEGV";
|
|
report.function = "leaky+0x70";
|
|
|
|
std::vector<fold::fuzz::FindingPrediction> predictions = {
|
|
{"null-deref:fixture.c:6:16",
|
|
"leaky",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/fixture.c", 6, 16}},
|
|
{"null-deref:fixture.c:8:16",
|
|
"leaky",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/fixture.c", 8, 16}},
|
|
};
|
|
|
|
REQUIRE_FALSE(fold::fuzz::matchSanitizerReport(report, predictions));
|
|
}
|
|
|
|
TEST_CASE("fuzz correlation accepts duplicate seeds for the same finding",
|
|
"[fuzz][prediction-match]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "SEGV";
|
|
report.function = "leaky+0x70";
|
|
|
|
std::vector<fold::fuzz::FindingPrediction> predictions = {
|
|
{"null-deref:fixture.c:6:16",
|
|
"leaky",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/fixture.c", 6, 16}},
|
|
{"null-deref:fixture.c:6:16",
|
|
"leaky",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/fixture.c", 6, 16}},
|
|
};
|
|
|
|
REQUIRE(fold::fuzz::matchSanitizerReport(report, predictions) == 0);
|
|
}
|
|
|
|
TEST_CASE("fuzz correlation rejects a locationless report from another function",
|
|
"[fuzz][prediction-match]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "SEGV";
|
|
report.function = "leaky_more+0x70";
|
|
|
|
std::vector<fold::fuzz::FindingPrediction> predictions = {
|
|
{"null-deref:fixture.c:6:16",
|
|
"leaky",
|
|
fold::FindingKind::NullDeref,
|
|
{"/tmp/project/fixture.c", 6, 16}},
|
|
};
|
|
|
|
REQUIRE_FALSE(fold::fuzz::matchSanitizerReport(report, predictions));
|
|
}
|
|
|
|
TEST_CASE("unpredicted crash IDs are stable and artifact-specific", "[fuzz][crash-id]") {
|
|
fold::fuzz::AsanReport report;
|
|
report.kind = "SEGV";
|
|
report.function = "parse input+0x70";
|
|
|
|
const auto first =
|
|
fold::fuzz::unpredictedCrashFindingId(report, "/tmp/run/crashes/crash-0123456789abcdef");
|
|
const auto repeated =
|
|
fold::fuzz::unpredictedCrashFindingId(report, "/tmp/run/crashes/crash-0123456789abcdef");
|
|
const auto other =
|
|
fold::fuzz::unpredictedCrashFindingId(report, "/tmp/run/crashes/crash-fedcba9876543210");
|
|
|
|
REQUIRE(first == repeated);
|
|
REQUIRE(first != other);
|
|
REQUIRE(first == "fuzz-crash:SEGV:parse-input+0x70:crash-0123456789abcdef");
|
|
REQUIRE(first.find("::0:0") == std::string::npos);
|
|
}
|