Skip to content

Resources that outlive their connection act on the slot's next occupant (handle reuse) #78

Description

@lannbot

ConnectionHandle is a slab slot: noq frees it once a connection is fully drained, and the next accepted or dialed connection reuses it. Every resource (connection, send-stream, recv-stream) holds a raw handle and looks the entry up per call — so a resource that outlives its connection starts answering for (and acting on!) whatever connection now occupies the slot.

The sharpest consequence, observed live from wosh: SendStreamRes's drop-implied reset(0) fired at a reused slot and reset stream 0 of a stranger's fresh connection. The victim was a tunnel-resume loop: every resumed connection was killed at birth by the previous attachment's dying stream resource (wosh holds the old attachment's send stream until the next attach replaces it — legal per the WIT). Reproduction: freeze a wosh client mid-session (SIGSTOP, 45s), let the listener's connection idle out, thaw; every resume then died with Reset(0) on the hello read, forever.

Same family, not yet observed but reachable:

  • accept() hands out the slot's next occupant when a queued-but-unclaimed connection dies and the slot is reused — one connection delivered to two acceptors (the queue also double-counts in accept_backlog).
  • Every expect("connection entry") lookup was one conns.remove away from a guest trap (entries are only ever overwritten today, so the panic was latent).

Fix shape (PR to follow): stamp every ConnEntry with a never-reused epoch, stamp every resource (and DialGuard, and the accept-queue entries) with the epoch it was minted under, and gate every resource-side lookup on it. A stale resource observes "connection gone": methods fail error.closed, state() reports closed, wait-closed resolves (none), drops do nothing. Pump-side lookups (noq events, datagram dispatch) speak of the current occupant by construction and stay unstamped.

  • the epoch guard itself
  • a conformance/matrix case: kill a connection, force slot reuse with a fresh dial, late-drop the old connection's stream resources, assert the fresh connection is unharmed (needs cross-role sequencing in the demo guest; the wosh freeze gates cover it end-to-end meanwhile)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions