blob: 131b6a005a9eaf27119e3463e69d286f2731bb81 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
#!/bin/sh
# Long-running fuzz loop per TESTING_PLAN.md's "Fuzz testing" section:
# repeatedly draw a fresh random batch of setboard/go records from the full
# 200k-position tests/cross_sectional_200k.ep_ pool, run them through a
# DEBUG=1 build under gdb (so any assert/SIGTRAP/SIGSEGV leaves a full
# backtrace instead of just a bare crash), shallow-depth, small/no hash
# (setboard memsets the hash table as a side effect, so a large --hash
# wastes time on every single record), --cpus 2 to exercise split.c's
# parallel search path too. Runs until stopped (^C) or a crash is found.
#
# Usage: ./fuzz_test.sh [binary] [depth] [batch_size] [cpus]
BIN="${1:-./_typhoon}"
DEPTH="${2:-6}"
BATCH="${3:-200}"
CPUS="${4:-2}"
SUITE=../tests/cross_sectional_200k.ep_
LOGDIR=/usr/local/tmp/typhoon/fuzz
mkdir -p "$LOGDIR"
if [ ! -x "$BIN" ]; then
echo "ERROR: $BIN not found/executable (build first: gmake clean; gmake DEBUG=1 MP=1)"
exit 1
fi
if [ ! -f "$SUITE" ]; then
echo "ERROR: $SUITE not found (run from src/)"
exit 1
fi
# Copy the binary out to a stable, private path rather than exec'ing $BIN
# in place. A concurrent "gmake clean" (e.g. update_head_reference.sh,
# precommit_check.sh) unlinks ./_typhoon/./typhoon out from under a loop
# that's mid-run, silently breaking every subsequent iteration with
# "not found/executable" -- observed live running this alongside
# update_head_reference.sh. Copying once up front means later rebuilds in
# the working tree can't touch what this loop is actually running.
FUZZ_BIN="$LOGDIR/fuzz_bin_$$"
cp "$BIN" "$FUZZ_BIN"
chmod +x "$FUZZ_BIN"
trap 'rm -f "$FUZZ_BIN"' EXIT
BIN="$FUZZ_BIN"
TOTAL_RECORDS=$(grep -c '^go' "$SUITE")
ITER=0
while :; do
ITER=$((ITER + 1))
SAMPLE="$LOGDIR/batch_${ITER}.ep_"
awk -v k="$BATCH" -v n="$TOTAL_RECORDS" 'BEGIN { srand() }
{ sub(/\r$/, "") }
/^setboard/ { rec = $0; next }
/^go[ \t]*$/ { rec = rec "\n" $0; c++; recs[c] = rec; rec = ""; next }
rec != "" { rec = rec "\n" $0 }
END {
picked = 0
while (picked < k && picked < c) {
r = int(rand() * c) + 1
if (!(r in used)) { used[r] = 1; print recs[r]; picked++ }
}
}' "$SUITE" > "$SAMPLE"
STAMP=$(date +%Y%m%d_%H%M%S)
LOG="$LOGDIR/run_${ITER}_${STAMP}.log"
GDBOUT="$LOGDIR/run_${ITER}_${STAMP}.gdb.txt"
echo "=== iter $ITER: $BATCH positions from $SUITE (sd $DEPTH, cpus $CPUS) -> $GDBOUT ==="
gdb -q -batch \
-ex "set pagination off" \
-ex run \
-ex "bt full" \
-ex "info registers" \
--args "$BIN" --cpus "$CPUS" --hash 1m --logfile "$LOG" \
--batch --command "force; book name /nonexistent.book.bin; sd $DEPTH; script $SAMPLE" \
> "$GDBOUT" 2>&1
STATUS=$?
if grep -qE 'Program terminated with signal (SIGSEGV|SIGABRT|SIGBUS|SIGILL|SIGFPE)|Assertion failure' "$GDBOUT"; then
echo "*** CRASH/ASSERT DETECTED on iter $ITER -- see $GDBOUT ***"
echo " positions: $SAMPLE"
echo " engine log: $LOG"
exit 1
fi
echo " iter $ITER clean (exit=$STATUS)"
done
|