a73x

2f007823

test: the coverage run finishes the suite — three more pids that were the tracer's

a73x   2026-08-26 17:54

Commit message
test: the coverage run finishes the suite — three more pids that were the tracer's

82 of 82 under kcov, for the first time. Each stop was a leg asking the OS
about the daemon through a pid that, under `make coverage`, is the wrapper:

- the upgrade candidate is `cp $MUXD`, and $MUXD is the shim script — an
  exec into it can never show the candidate on /proc/pid/exe. coverage.sh
  names the binary behind the shim (MUXD_ELF; natively it is $MUXD).
- the resumed-argv check read the wrapper's cmdline. `real_pid` is the
  hardkill rule for /proc reads: the tracee, when the pid held is kcov.
- the stop-gone leg's instant `kill -0` must name the pid `stop` itself
  waited on, captured before the stop — kcov's first child at that
  instant can be a reparented zombie, which still answers kill -0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

test/coverage.sh
Old New
@@ -140,6 +140,9 @@ export E2E_OK_LOG="$OK_LOG"
140 # told to wait longer — not to demand less. See e2e.sh's TIME_SCALE note. 140 # told to wait longer — not to demand less. See e2e.sh's TIME_SCALE note.
141 export E2E_TIME_SCALE="${COV_TIME_SCALE:-4}" 141 export E2E_TIME_SCALE="${COV_TIME_SCALE:-4}"
142 142
143 # The upgrade legs copy a candidate binary and watch it exec; a shim cannot be
144 # exec'd into. The real path goes beside the shim.
145 MUXD_ELF="$MUXD"; export MUXD_ELF
143 set +e 146 set +e
144 # Each argument is the shim if that binary is wrapped, the real thing if not. 147 # Each argument is the shim if that binary is wrapped, the real thing if not.
145 pick() { if [ -x "$SHIM/$1" ]; then echo "$SHIM/$1"; else echo "$2"; fi; } 148 pick() { if [ -x "$SHIM/$1" ]; then echo "$SHIM/$1"; else echo "$2"; fi; }
test/e2e.sh
Old New
@@ -3,6 +3,10 @@
3 # output flows pty -> engine -> snapshot -> client replica -> client stdout. 3 # output flows pty -> engine -> snapshot -> client replica -> client stdout.
4 set -eu 4 set -eu
5 MUXD="$1" 5 MUXD="$1"
6 # The upgrade candidate must be an ELF: the daemon execs it and the leg reads
7 # the exec'd process's /proc exe link. Under the coverage tracer $MUXD is a
8 # shim script, so coverage.sh names the binary behind it here.
9 MUXD_ELF="${MUXD_ELF:-$MUXD}"
6 MUX="$2" 10 MUX="$2"
7 # M9 prediction helpers: a deterministic stand-in for an editor, and a pipe 11 # M9 prediction helpers: a deterministic stand-in for an editor, and a pipe
8 # that makes a slow round trip without netem or root. 12 # that makes a slow round trip without netem or root.
@@ -689,6 +693,17 @@ hardkill() {
689 # its own — measured on the hub leg, where `kill $W3PID` left both alive and 693 # its own — measured on the hub leg, where `kill $W3PID` left both alive and
690 # wait_pid_gone timed out. TERM the tracee; the wrapper exits with it and 694 # wait_pid_gone timed out. TERM the tracee; the wrapper exits with it and
691 # writes its database. Off the tracer this is a plain kill, same exit status. 695 # writes its database. Off the tracer this is a plain kill, same exit status.
696 # A /proc claim about the daemon is read off the tracee: under `make coverage`
697 # the pid the suite holds is the tracer's (hardkill's reason), and kcov's own
698 # cmdline is what a resumed-argv check would otherwise read.
699 real_pid() {
700 if [ "$(ps -o comm= -p "$1" 2>/dev/null)" = kcov ]; then
701 ps -o pid= --ppid "$1" 2>/dev/null | head -1 | tr -d ' '
702 else
703 echo "$1"
704 fi
705 }
706
692 softkill() { 707 softkill() {
693 if [ "$(ps -o comm= -p "$1" 2>/dev/null)" = kcov ]; then 708 if [ "$(ps -o comm= -p "$1" 2>/dev/null)" = kcov ]; then
694 _rc=1 709 _rc=1
@@ -9234,7 +9249,7 @@ grep -qF "refused: version: $UPVER is not newer than $UPVER" "$OUT.upref1" || {
9234 # `readlink /proc/PID/exe` is the witness that the copy has already 9249 # `readlink /proc/PID/exe` is the witness that the copy has already
9235 # exec'd, so the chmod cannot beat it and turn the leg into an exec 9250 # exec'd, so the chmod cannot beat it and turn the leg into an exec
9236 # failure that asserts nothing. 9251 # failure that asserts nothing.
9237 cp "$MUXD" "$UPBIN" 9252 cp "$MUXD_ELF" "$UPBIN"
9238 chmod 755 "$UPBIN" 9253 chmod 755 "$UPBIN"
9239 kill -STOP "$D69PID" 9254 kill -STOP "$D69PID"
9240 "$UPBIN" upgrade --sock "$SOCK69" --allow-same-version > "$OUT.upref2" 2>&1 & 9255 "$UPBIN" upgrade --sock "$SOCK69" --allow-same-version > "$OUT.upref2" 2>&1 &
@@ -9289,7 +9304,7 @@ grep -qF "muxd: upgraded to $UPVER" "$OUT.upok" || {
9289 kill -0 "$D69PID" 2>/dev/null || { 9304 kill -0 "$D69PID" 2>/dev/null || {
9290 echo "e2e FAIL: upgrade: the daemon pid $D69PID is gone — that is a restart, not an upgrade" 9305 echo "e2e FAIL: upgrade: the daemon pid $D69PID is gone — that is a restart, not an upgrade"
9291 cat "$OUT.up.d"; exit 1; } 9306 cat "$OUT.up.d"; exit 1; }
9292 tr '\0' ' ' < "/proc/$D69PID/cmdline" > "$OUT.upst2" 2>/dev/null || true 9307 tr '\0' ' ' < "/proc/$(real_pid "$D69PID")/cmdline" > "$OUT.upst2" 2>/dev/null || true
9293 grep -qF -- "--resume-fd" "$OUT.upst2" || { 9308 grep -qF -- "--resume-fd" "$OUT.upst2" || {
9294 echo "e2e FAIL: upgrade: pid $D69PID is not running the resumed argv; it holds:" 9309 echo "e2e FAIL: upgrade: pid $D69PID is not running the resumed argv; it holds:"
9295 cat "$OUT.upst2"; exit 1; } 9310 cat "$OUT.upst2"; exit 1; }
@@ -9639,10 +9654,11 @@ sleep 0.5
9639 pipe_detach "stop-gone: the second session's client" 9654 pipe_detach "stop-gone: the second session's client"
9640 [ "$("$MUXD" stats --sock "$SOCK73" | sed -n 's/.*sessions=\([0-9]*\).*/\1/p')" = "2" ] || { 9655 [ "$("$MUXD" stats --sock "$SOCK73" | sed -n 's/.*sessions=\([0-9]*\).*/\1/p')" = "2" ] || {
9641 echo "e2e FAIL: stop-gone: wanted two sessions of stubborn shells"; exit 1; } 9656 echo "e2e FAIL: stop-gone: wanted two sessions of stubborn shells"; exit 1; }
9657 D73REAL=$(real_pid "$D73PID")
9642 "$MUXD" stop --sock "$SOCK73" 2> "$OUT.sg.stop" || { 9658 "$MUXD" stop --sock "$SOCK73" 2> "$OUT.sg.stop" || {
9643 echo "e2e FAIL: stop-gone: stop failed"; cat "$OUT.sg.stop"; exit 1; } 9659 echo "e2e FAIL: stop-gone: stop failed"; cat "$OUT.sg.stop"; exit 1; }
9644 # Asked of the OS the instant stop returns — no wait, no retry. 9660 # Asked of the OS the instant stop returns — no wait, no retry.
9645 if kill -0 "$D73PID" 2>/dev/null; then 9661 if kill -0 "$D73REAL" 2>/dev/null; then
9646 echo "e2e FAIL: stop said stopped, but pid $D73PID is still running"; cat "$OUT.sg.stop"; exit 1 9662 echo "e2e FAIL: stop said stopped, but pid $D73PID is still running"; cat "$OUT.sg.stop"; exit 1
9647 fi 9663 fi
9648 grep -q '^muxd: stopped' "$OUT.sg.stop" || { 9664 grep -q '^muxd: stopped' "$OUT.sg.stop" || {