#!/usr/bin/env bash
set -uo pipefail
ROOT="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
cd "$ROOT" || { echo "仓根不可达: $ROOT" >&2; exit 1; }
TC="nightly-2026-09-29"
FUZZ_DIR="$ROOT/fuzz"
[ -d "$FUZZ_DIR" ] || { echo "::error::fuzz 门(AC2): 缺 $FUZZ_DIR"; exit 1; }
N_TARGETS="$(find "$FUZZ_DIR/fuzz_targets" -maxdepth 1 -name '*.rs' 2>/dev/null | wc -l)"
[ "$N_TARGETS" -ge 1 ] || { echo "::error::fuzz 门(AC2): 靶面空(fuzz_targets/*.rs = 0)—— 禁空跑绿"; exit 1; }
TARGET="$(find "$FUZZ_DIR/fuzz_targets" -maxdepth 1 -name '*.rs' -printf '%f\n' 2>/dev/null | sed 's/\.rs$//' | head -1)"
CORPUS="$FUZZ_DIR/corpus/$TARGET"
[ -d "$CORPUS" ] || { echo "::error::fuzz 门(AC2): 缺语料库 $CORPUS"; exit 1; }
N_EMPTY="$(find "$CORPUS" -maxdepth 1 -type f -size 0 | wc -l)"
[ "$N_EMPTY" -eq 0 ] || { echo "::error::fuzz 门(AC2): 语料库含 $N_EMPTY 个 0 字节档 —— libFuzzer 不加载之 ⇒ 不入回放面(高估覆盖面)"; exit 1; }
N_CORPUS="$(find "$CORPUS" -maxdepth 1 -type f | wc -l)"
[ "$N_CORPUS" -ge 1 ] || { echo "::error::fuzz 门(AC2): 语料库空 ⇒ 回放无对象(禁空跑绿)"; exit 1; }
echo "[fuzz] 靶 = $TARGET ∧ 靶面 = $N_TARGETS 档 ∧ 语料 = $N_CORPUS 档($CORPUS)"
OUT="$(cd "$FUZZ_DIR" && timeout 1800 cargo "+$TC" fuzz run "$TARGET" "corpus/$TARGET" -- -runs=0 2>&1)"
RC=$?
printf '%s\n' "$OUT" | grep -E 'files found|seed corpus|DONE|Done [0-9]+ runs|ERROR|SUMMARY' | tail -6
if [ "$RC" -ne 0 ]; then
echo "::error::fuzz 门(AC2): 语料回归 rc=$RC ⇒ **存在崩溃输入**(新崩溃 ⇒ 必红 · 承 AC2 逐字)"
printf '%s\n' "$OUT" | grep -iE 'crash|panic|ERROR|SUMMARY|artifact' | tail -8
exit 1
fi
printf '%s\n' "$OUT" | grep -q 'seed corpus' \
|| { echo "::error::fuzz 门(AC2): 未见 seed corpus 行 ⇒ 回放未真跑(禁空跑绿)"; exit 1; }
echo "[fuzz] 语料回归 rc=0 ⇒ 零崩溃 ✓"
exit 0