W14: pin C1/C1b command-channel crash guards (test-only)
Pre-fix, one malformed or non-ASCII line on sx_server's top-level command
channel raised an uncaught Parse_error and killed the whole shared process
(bridges + conformance runners). dc7aa709 guards the parse; the server now
answers (error N "Malformed command line: ...") and keeps serving.
Add scripts/test-protocol-gate.sh: per case, spawn a fresh timeout-bounded
sx_server.exe (never touches a shared process) and assert the error
response, the follow-up epoch still evaluating, and a clean exit. Cases:
C1 unterminated list + garbage line, C1b non-ASCII byte (exact review
repros from plans/sx-review/hosts.md), plus a well-formed control. 4/4
green. Structured to grow into W14 section E's protocol fuzz suite (C3-C7).
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,7 +52,8 @@ Pin each confirmed-and-fixed finding with a minimal repro. Add suites to
|
|||||||
is K16 [W8], still OPEN — not a W14 pin target until its fix lands
|
is K16 [W8], still OPEN — not a W14 pin target until its fix lands
|
||||||
- [x] crit-2 [W1] — signal-return kont pinned NON-VACUOUSLY (side-effect
|
- [x] crit-2 [W1] — signal-return kont pinned NON-VACUOUSLY (side-effect
|
||||||
sentinel across two tests; a plain assert would inherit the vacuity)
|
sentinel across two tests; a plain assert would inherit the vacuity)
|
||||||
- [ ] C1/C1b [W3] — HTTP-mode concurrency fixes, pin
|
- [x] C1/C1b [W3] — command-channel crash guards pinned
|
||||||
|
(`scripts/test-protocol-gate.sh`, seed for section E's fuzz suite)
|
||||||
- [ ] S4 [conformance] — housekeeping repro, pin
|
- [ ] S4 [conformance] — housekeeping repro, pin
|
||||||
|
|
||||||
### B. Runner/production env unification
|
### B. Runner/production env unification
|
||||||
@@ -80,6 +81,16 @@ Pin each confirmed-and-fixed finding with a minimal repro. Add suites to
|
|||||||
|
|
||||||
## Progress log (newest first)
|
## Progress log (newest first)
|
||||||
|
|
||||||
|
- 2026-07-04 — **C1/C1b command-channel pins (item A.6)**. These are
|
||||||
|
protocol-level, not .sx-suite pins: authored
|
||||||
|
`scripts/test-protocol-gate.sh` — each case spawns its OWN timeout-bounded
|
||||||
|
`sx_server.exe` (no shared process touched) and asserts three things: an
|
||||||
|
`(error N "Malformed command line: ...")` response is emitted, the
|
||||||
|
follow-up epoch still evaluates (process survived), and no `Fatal error`
|
||||||
|
escapes / exit is clean. Cases: C1 unterminated list (exact review repro),
|
||||||
|
C1 plain-garbage line, C1b non-ASCII byte (`café`), plus a well-formed
|
||||||
|
control session. 4/4 green. The script is deliberately structured to grow
|
||||||
|
into section E's fuzz suite (C3–C7). Test-only.
|
||||||
- 2026-07-04 — **crit-2 non-vacuous pin (item A.5)**. The original bug's
|
- 2026-07-04 — **crit-2 non-vacuous pin (item A.5)**. The original bug's
|
||||||
signature — handler value becomes the WHOLE program result, discarding
|
signature — handler value becomes the WHOLE program result, discarding
|
||||||
every outer frame *including the covering test's own assert* — means a
|
every outer frame *including the covering test's own assert* — means a
|
||||||
|
|||||||
89
scripts/test-protocol-gate.sh
Executable file
89
scripts/test-protocol-gate.sh
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# test-protocol-gate.sh — W14 pins for the epoch/command-channel protocol.
|
||||||
|
#
|
||||||
|
# Pins C1/C1b (review, plans/sx-review/hosts.md): a malformed or non-ASCII
|
||||||
|
# line on the top-level command channel used to raise an uncaught
|
||||||
|
# Sx_types.Parse_error and KILL the whole sx_server process (the shared
|
||||||
|
# channel used by bridges and conformance runners). Fixed in dc7aa709:
|
||||||
|
# the server now answers `(error N "Malformed command line: ...")` and
|
||||||
|
# keeps serving.
|
||||||
|
#
|
||||||
|
# Each case spawns its OWN timeout-bounded sx_server.exe subprocess —
|
||||||
|
# no shared/sibling process is ever touched. Designed to grow into the
|
||||||
|
# W14 section-E protocol fuzz suite (C3-C7).
|
||||||
|
#
|
||||||
|
# Usage: bash scripts/test-protocol-gate.sh
|
||||||
|
# Exit: 0 = all pins green; 1 = a pin failed (fix regressed).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
SERVER=hosts/ocaml/_build/default/bin/sx_server.exe
|
||||||
|
|
||||||
|
if [[ ! -x "$SERVER" ]]; then
|
||||||
|
echo "SKIP: $SERVER not built (run sx_build target=ocaml first)" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
pass=0
|
||||||
|
fail=0
|
||||||
|
|
||||||
|
# run_case NAME INPUT EXPECT_SENTINEL
|
||||||
|
# Feeds INPUT to a fresh server. Asserts:
|
||||||
|
# 1. an (error ... "Malformed command line: ...") response is emitted
|
||||||
|
# 2. the follow-up epoch still evaluates (EXPECT_SENTINEL in output)
|
||||||
|
# 3. the process exits cleanly (no Fatal error, exit 0 on stdin EOF)
|
||||||
|
run_case() {
|
||||||
|
local name="$1" input="$2" sentinel="$3"
|
||||||
|
local out rc
|
||||||
|
out=$(printf '%b' "$input" | timeout 60 "$SERVER" 2>&1)
|
||||||
|
rc=$?
|
||||||
|
local ok=1
|
||||||
|
if ! grep -q 'Malformed command line' <<<"$out"; then
|
||||||
|
echo "FAIL: $name — no malformed-line error response"; ok=0
|
||||||
|
fi
|
||||||
|
if ! grep -q "^${sentinel}\$" <<<"$out"; then
|
||||||
|
echo "FAIL: $name — follow-up epoch did not run (process died?)"; ok=0
|
||||||
|
fi
|
||||||
|
if grep -q 'Fatal error' <<<"$out"; then
|
||||||
|
echo "FAIL: $name — Fatal error escaped to the top level"; ok=0
|
||||||
|
fi
|
||||||
|
if [[ $rc -ne 0 ]]; then
|
||||||
|
echo "FAIL: $name — nonzero exit ($rc)"; ok=0
|
||||||
|
fi
|
||||||
|
if [[ $ok -eq 1 ]]; then
|
||||||
|
echo "PASS: $name"
|
||||||
|
pass=$((pass+1))
|
||||||
|
else
|
||||||
|
echo " --- output ---"; sed 's/^/ /' <<<"$out"; echo " --------------"
|
||||||
|
fail=$((fail+1))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# C1: unterminated list on the command channel (exact review repro)
|
||||||
|
run_case "C1 unterminated list survives" \
|
||||||
|
'(epoch 2)\n(eval "(+ 1 2"\n(epoch 3)\n(eval "99")\n' \
|
||||||
|
'99'
|
||||||
|
|
||||||
|
# C1: plain-garbage line (second C1 repro shape)
|
||||||
|
run_case "C1 garbage line survives" \
|
||||||
|
'(epoch 1)\nnot an s-expr ]]] {{{\n(epoch 2)\n(eval "42")\n' \
|
||||||
|
'42'
|
||||||
|
|
||||||
|
# C1b: non-ASCII byte on the command channel (exact review repro; \xc3\xa9 = é)
|
||||||
|
run_case "C1b non-ASCII line survives" \
|
||||||
|
'(epoch 1)\n(eval (quote caf\xc3\xa9))\n(epoch 2)\n(eval "99")\n' \
|
||||||
|
'99'
|
||||||
|
|
||||||
|
# Control: a well-formed session still works end to end
|
||||||
|
ctrl=$(printf '(epoch 1)\n(eval "(+ 40 2)")\n' | timeout 60 "$SERVER" 2>&1)
|
||||||
|
if grep -q '^42$' <<<"$ctrl"; then
|
||||||
|
echo "PASS: control well-formed session"
|
||||||
|
pass=$((pass+1))
|
||||||
|
else
|
||||||
|
echo "FAIL: control well-formed session"; sed 's/^/ /' <<<"$ctrl"
|
||||||
|
fail=$((fail+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "protocol-gate: $pass passed, $fail failed"
|
||||||
|
[[ $fail -eq 0 ]]
|
||||||
Reference in New Issue
Block a user