Merge pull request #20 from logos-blockchain/fix-add-timeout-stateful-lockstep

fix: Add timeout to model based stateful lockstep
This commit is contained in:
Roman Zajic 2026-07-14 09:46:28 +02:00 committed by GitHub
commit aa0c8b7c4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 53 additions and 6 deletions

View File

@ -162,9 +162,16 @@ jobs:
run: |
T="${{ matrix.target }}"
mkdir -p "afl-output/$T"
# The lockstep target's execs (~0.8 s on accept-heavy seeds) exceed AFL++'s
# default 1000 ms calibration limit and abort the dry run; give only it an
# auto-scaled cap (-t 5000+).
TFLAG=""
if [ "$T" = "fuzz_stateful_model_lockstep" ]; then
TFLAG="-t 5000+"
fi
set +e
timeout ${{ needs.config.outputs.duration }} \
afl-fuzz -i "afl-seeds/$T" -o "afl-output/$T" -- "fuzz/target/release/$T"
afl-fuzz $TFLAG -i "afl-seeds/$T" -o "afl-output/$T" -- "fuzz/target/release/$T"
rc=$?
set -e
# 124 = SIGALRM from timeout (expected end); 0 = clean exit; else real failure
@ -203,8 +210,15 @@ jobs:
exit 0
fi
before=$(ls "$SRC" | wc -l)
# The lockstep target's accept-heavy seeds run ~0.8 s/exec; with the default
# 1000 ms limit afl-cmin would drop them as timeouts and corrupt the minimised
# corpus. cmin's arg parser rejects the '+' suffix, so use a plain 5 s cap.
TFLAG=""
if [ "$T" = "fuzz_stateful_model_lockstep" ]; then
TFLAG="-t 5000"
fi
# afl-cmin can fail on pathological corpora; fall back to leaving SRC as-is.
if afl-cmin -i "$SRC" -o "afl-cmin/$T" -- "fuzz/target/release/$T"; then
if afl-cmin $TFLAG -i "$SRC" -o "afl-cmin/$T" -- "fuzz/target/release/$T"; then
rm -rf "$SRC"
mkdir -p "$SRC"
cp "afl-cmin/$T"/* "$SRC"/ 2>/dev/null || true

View File

@ -5,7 +5,7 @@ on:
- cron: "0 2 * * *"
workflow_dispatch:
push:
branches: [main, chore-corpus-update]
branches: [main, fix-add-timeout-stateful-lockstep]
env:
RISC0_DEV_MODE: "1"
@ -90,11 +90,20 @@ jobs:
run: |
TARGET="${{ matrix.target }}"
mkdir -p afl-output/${TARGET}
# The model-based lockstep target runs the real state machine (risc0 executor)
# once per command, so accept-heavy seeds take ~0.8 s/exec — over AFL++'s default
# 1000 ms calibration limit, which aborts the dry run. Give only that target an
# auto-scaled cap (-t 5000+); all others keep the default timeout.
TFLAG=""
if [ "$TARGET" = "fuzz_stateful_model_lockstep" ]; then
TFLAG="-t 5000+"
fi
# Disable errexit so that timeout's exit code 124 (expected signal) does not
# cause bash -e to abort the script before the guard below can run.
set +e
timeout 60 \
afl-fuzz \
$TFLAG \
-i afl-seeds/${TARGET} \
-o afl-output/${TARGET} \
-- fuzz/target/release/${TARGET}
@ -124,8 +133,15 @@ jobs:
BINARY="fuzz/target/release/${TARGET}"
showmap_filled="n/a"
showmap_pct="n/a"
# The lockstep target's accept-heavy seeds run ~0.8 s/exec; without a raised
# timeout afl-showmap would skip them, undercounting edge coverage. afl-showmap
# takes a fixed cap only (no '+' auto-scale), so use a plain 5 s cap for it.
SHOWMAP_TFLAG=""
if [ "$TARGET" = "fuzz_stateful_model_lockstep" ]; then
SHOWMAP_TFLAG="-t 5000"
fi
if [ -d "$CORPUS" ] && [ -f "$BINARY" ]; then
afl-showmap -C \
afl-showmap -C $SHOWMAP_TFLAG \
-i "$CORPUS" \
-o "afl-edges-${TARGET}.txt" \
-- "$BINARY" 2>/dev/null || true

View File

@ -299,9 +299,18 @@ fuzz-afl TARGET="" TIME="30":
echo "Binary not found — building $t first…"
just afl-build-target "$t"
fi
# Per-target execution timeout. The model-based lockstep target runs the real
# state machine (risc0 executor) once per command, so accept-heavy seeds take
# ~0.8 s/exec — over AFL++'s default 1000 ms calibration limit, which aborts the
# dry run. Give it an auto-scaled cap (-t 5000+); all other targets keep the
# default. Unquoted so an empty value expands to no argument (bash 3.2 safe).
local TFLAG=""
if [ "$t" = "fuzz_stateful_model_lockstep" ]; then
TFLAG="-t 5000+"
fi
# Use afl-fuzz's own -V (run for N seconds then exit) instead of GNU
# `timeout`, which is not installed by default on macOS.
afl-fuzz -V "$TIME" -i "$CORPUS" -o "$OUTPUT" -- "$BINARY" || true
afl-fuzz -V "$TIME" $TFLAG -i "$CORPUS" -o "$OUTPUT" -- "$BINARY" || true
}
for t in "${TARGETS[@]}"; do
echo "=== afl++ $t for ${TIME}s ==="
@ -429,9 +438,17 @@ fuzz-afl-parallel TIME="30" JOBS="4":
echo "Binary not found — building $t first…"
just afl-build-target "$t"
fi
# Per-target execution timeout — see the note in `fuzz-afl`. The lockstep target
# runs the risc0 executor per command (~0.8 s/exec on accept-heavy seeds), which
# exceeds AFL++'s default 1000 ms calibration limit; give it -t 5000+. Unquoted so
# an empty value expands to no argument (bash 3.2 safe).
local TFLAG=""
if [ "$t" = "fuzz_stateful_model_lockstep" ]; then
TFLAG="-t 5000+"
fi
# Use afl-fuzz's own -V (run for N seconds then exit) instead of GNU
# `timeout`, which is not installed by default on macOS.
afl-fuzz -V {{TIME}} -i "$CORPUS" -o "$OUTPUT" -- "$BINARY" || true
afl-fuzz -V {{TIME}} $TFLAG -i "$CORPUS" -o "$OUTPUT" -- "$BINARY" || true
}
echo "Targets: ${#TARGETS[@]} | max parallel: {{JOBS}} | time per target: {{TIME}}s"
for t in "${TARGETS[@]}"; do