diff --git a/analysis/tests/test_foundry_run_showmap_args.py b/analysis/tests/test_foundry_run_showmap_args.py index 43e02f1..f0e8f89 100644 --- a/analysis/tests/test_foundry_run_showmap_args.py +++ b/analysis/tests/test_foundry_run_showmap_args.py @@ -152,7 +152,7 @@ def test_showmap_replay_uses_explicit_corpus_override_only_when_set(self): corpus_idx = replay_args.index("--showmap-corpus-dir") self.assertEqual(replay_args[corpus_idx + 1], str(corpus_dir)) - def test_showmap_replay_uses_bounded_default_timeout(self): + def test_showmap_replay_scales_timeout_with_fuzz_budget(self): def run_case(timeout: str, override: str | None = None) -> list[list[str]]: with tempfile.TemporaryDirectory() as tmp: tmp_dir = Path(tmp) @@ -179,14 +179,16 @@ def run_case(timeout: str, override: str | None = None) -> list[list[str]]: lines = (log_dir / "commands.tsv").read_text(encoding="utf-8").splitlines() return [line.split("\t") for line in lines] + # Replay budget scales with the fuzz budget, not a fixed cap. long_campaign = run_case("86400") self.assertEqual(long_campaign[0][1], "86400") - self.assertEqual(long_campaign[1][1], "1800") + self.assertEqual(long_campaign[1][1], "86400") short_campaign = run_case("60") self.assertEqual(short_campaign[0][1], "60") self.assertEqual(short_campaign[1][1], "60") + # Explicit override still wins. explicit_override = run_case("86400", "42") self.assertEqual(explicit_override[0][1], "86400") self.assertEqual(explicit_override[1][1], "42") diff --git a/fuzzers/foundry/run.sh b/fuzzers/foundry/run.sh index 09ce9dc..c05efa7 100644 --- a/fuzzers/foundry/run.sh +++ b/fuzzers/foundry/run.sh @@ -137,9 +137,14 @@ if [[ "${showmap_enabled}" == "1" || "${showmap_enabled_lc}" == "true" || "${sho original_timeout="${SCFUZZBENCH_TIMEOUT_SECONDS:-}" showmap_timeout="${SCFUZZBENCH_FOUNDRY_SHOWMAP_TIMEOUT_SECONDS:-}" if [[ -z "${showmap_timeout}" ]]; then - showmap_timeout=1800 - if [[ "${original_timeout}" =~ ^[0-9]+$ ]] && [[ "${original_timeout}" -gt 0 ]] && [[ "${original_timeout}" -lt "${showmap_timeout}" ]]; then + # Replay cost grows with corpus size, which grows with the fuzz budget, so + # scale the budget rather than capping it: a fixed cap silently truncated + # the replay on slow targets and dropped their coverage. Replay is normally + # far faster than fuzzing, so the ceiling is only reached by slow targets. + if [[ "${original_timeout}" =~ ^[0-9]+$ ]] && [[ "${original_timeout}" -gt 0 ]]; then showmap_timeout="${original_timeout}" + else + showmap_timeout=1800 fi fi SCFUZZBENCH_TIMEOUT_SECONDS="${showmap_timeout}"