wire.fetch leaks the child stdin fd (wfd) on every error path
wire.fetch spawns upload-pack, holding wfd=child.stdin / rfd=child.stdout / pid (wire.js:136-137). wfd is closed only at wire.js:170, INSIDE the try after the request is written; the finally (wire.js:188-191) closes rfd and reaps pid but NEVER wfd. Any throw before :170 — peer advertised no usable ref (:160), a pkt parse error draining the advert, a mid-loop io.writeAll failure — leaks wfd, and reaping with the child's stdin still open can block the peer. WIRECLI.c closes both fds before reaping. Method: Issues.
wire.js:137: `const wfd = child.stdin, rfd = child.stdout, pid =
child.pid; — wfd` owned for the whole fetch.
wire.js:160: if (!want) throw "… no usable ref" — throws with wfdstill open (before the :170 close).
wire.js:169-170: `for (const r of reqs) io.writeAll(wfd, r);
io.close(wfd); — a write failure here also leaks wfd`.
wire.js:188-191 finally: io.close(rfd) + io.reap(pid) ONLY —
wfd is absent; the reap can block on a peer still reading stdin.
WIRECLI.c:1035-1039: `if (wfd>=0) close(wfd); if (rfd>=0)
close(rfd); THEN FILEReap(pid,…)` — both fds closed before the reap.
wfd is closed on EVERY exit path (success + each throw), before thereap, so a failed fetch never leaks an fd or blocks the peer.
finally re-close —
guard with try{ io.close(wfd) }catch{} (double-close is a no-op).
wfd (and rfd) BEFORE io.reap(pid), matching WIRECLI.c order.wire.fetch; no protocol change.wfd close into the finally as a guarded try/catch, keepor drop the inline :170 close (guarded re-close makes it idempotent).
finally: close wfd, close rfd, then reap(pid).test/js/wire/*: force a pre-:170 throw (peer advert with
no usable ref) and assert wfd is closed (no leaked fd / no hang).
io.close(wfd) to finally, before the reap.io.close on an already-closed fd is a harmless no-op (catchEBADF) so the happy-path double-close is safe.
shared/wire.js:42 owns
wfd; :62 closes it inline INSIDE the try; the :80-83 finally closes only rfd + reaps pid, never wfd. A pre-:62 throw still leaks wfd.