AtlatestRepositorysigil-vt

sigil-vt / tree / spikefuzz.sh

1#!/usr/bin/env bash
2# M2 GATE: build + run the sigil-vt fuzz driver under the sanitizers.
3# The pure C core (native/vt.c under -DVT_FUZZ) is standalone — no libsigil.
4#
5# RUN IT LIKE THIS (compiler AND runtime must both come from the manifest):
6#
7# guix shell -m ../sigil/manifest.scm -- spike/fuzz.sh
8#
9# The monorepo manifest already carries gcc-toolchain, whose ASan is REAL.
10# Two ways to end up with a silently blind gate — both caught by the self-test
11# below, neither obvious from the output:
13# 1. THE PINNED ZIG HAS NO ASan RUNTIME. `zig cc -fsanitize=address` alone
14# fails to link (undefined __asan_report_load4); with `address,undefined`
15# it links and SILENTLY DROPS ASan (zero __asan symbols in the binary) and
16# still prints FUZZ CLEAN. gcc keeps ASan with the same flag combo — the
17# silent drop is zig-specific. Do not use zig for this gate.
18# 2. RUNNING OUTSIDE THE GUIX SHELL. The same gcc-built binary does NOT fault
19# when run outside the shell — it exits cleanly, looking exactly like a
20# pass. Compile AND run inside.
22# This is not hypothetical: a real heap over-read (t-d4c7) shipped through
23# 5,000,000 "clean" iterations of this gate.
24set -euo pipefail
25cd "$(dirname "$0")/.."
26CC="${CC:-gcc}"
27ITERS="${1:-3000000}"
28SAN_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all"
29mkdir -p build
31# ---------------------------------------------------------------------------
32# STEP 0 — PROVE THE GATE CAN FIRE, BEFORE TRUSTING ANYTHING IT SAYS.
33# Compile a KNOWN heap over-read with the SAME compiler and flags, and require
34# it to be caught. A gate that cannot demonstrate it fires is not a gate. This
35# check covers BOTH failure modes above without having to detect either.
36# ---------------------------------------------------------------------------
37echo "== sanitizer self-test (can this build detect a heap over-read?) =="
38"$CC" -std=c99 -O1 -g $SAN_FLAGS spike/sanitizer-selftest.c -o build/san-selftest
39set +e
40san_out="$(ASAN_OPTIONS=abort_on_error=1 UBSAN_OPTIONS=halt_on_error=1 \
41 ./build/san-selftest 2>&1)"
42rc=$?
43set -e
44# Match the DIAGNOSTIC, not the exit code. A caught over-read ABORTS (SIGABRT,
45# rc 134) — it can never exit 0 — while a bare non-zero exit could just mean the
46# binary failed to launch. Only an actual ASan report proves the gate fired.
47if printf '%s' "$san_out" | grep -qE "AddressSanitizer.*(heap-buffer-overflow|SEGV)"; then
48 echo " ok: a 1456-byte heap over-read was caught — sanitizer is real."
49elif [ "$rc" -eq 1 ]; then
50 cat >&2 <<'MSG'
52 SANITIZER SELF-TEST FAILED — THIS BUILD IS BLIND.
54 A deliberate 1456-byte heap over-read was NOT detected, so this build has no
55 working AddressSanitizer. Any "FUZZ CLEAN" from it is meaningless: it cannot
56 see heap-buffer-overflow, use-after-free, or leaks — the exact bug classes
57 this gate exists to catch (the parser consumes UNTRUSTED pty bytes).
59 This is how the t-d4c7 scrollback over-read shipped through 5,000,000
60 "clean" iterations.
62 Almost always one of:
63 1. you used zig -> it has no ASan runtime and drops it silently
64 2. you ran OUTSIDE the guix shell -> the runtime never engages
66 Fix by running the whole thing inside the manifest shell:
67 guix shell -m ../sigil/manifest.scm -- spike/fuzz.sh
69 Do NOT silence this check.
71 If you only want the UBSan coverage (which IS real — it caught the CSI param
72 int overflow), run: SAN_UBSAN_ONLY=1 spike/fuzz.sh
73 That is NOT the M2 memory-safety gate and must never be reported as one.
74MSG
75 if [ "${SAN_UBSAN_ONLY:-0}" = "1" ]; then
76 echo "" >&2
77 echo " SAN_UBSAN_ONLY=1 set — continuing WITHOUT memory-safety coverage." >&2
78 echo " This run CANNOT satisfy the M2 gate. Report it as UBSAN-ONLY." >&2
79 echo "" >&2
80 UBSAN_ONLY=1
81 else
82 exit 1
83 fi
84else
85 echo " self-test exited $rc with no AddressSanitizer diagnostic." >&2
86 echo " That is neither a clean catch nor a clean miss — refusing to guess." >&2
87 printf '%s\n' "$san_out" | head -5 >&2
88 exit 1
89fi
91echo "== compiling vt-fuzz =="
92"$CC" -std=c99 -O1 -g -DVT_FUZZ \
93 -Wall -Wextra -Wno-unused-parameter \
94 $SAN_FLAGS \
95 native/vt-fuzz.c -o build/vt-fuzz
96echo "== running $ITERS iterations =="
97ASAN_OPTIONS=detect_leaks=1:abort_on_error=1 \
98UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 \
99 ./build/vt-fuzz "$ITERS"
101if [ "${UBSAN_ONLY:-0}" = "1" ]; then
102 cat >&2 <<'MSG'
104 ^ UBSAN-ONLY RUN. This did NOT check memory safety (no working ASan).
105 It does not satisfy the M2 gate. Do not record it as "ASan/UBSan clean".
106MSG
107fi