Read-side deadlock in `Connection::poll` under symmetric back-pressure
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 250
- Forks
- 62
- PR merge metrics
- No merged PRs in 30d
Description
We hit this running a downstream fork (the TLSN MPC stack) under heavy concurrent multi-stream load. Patched it on our side in [tlsnotary/tlsn-utils@b452352][1], and the author flagged that the underlying coupling is inherited from upstream rust-yamux. Looking at current master, the same shape is still there, so filing rather than just sitting on it.
## What happens
`Connection::poll` gates socket reads on having no pending control reply queued — [yamux/src/connection.rs#L456][2]:
```rust
if self.pending_read_frame.is_none() {
match self.socket.poll_next_unpin(cx) { ... }
}
```
`pending_read_frame` is a one-slot buffer for control frames produced inside the read loop — a Pong in reply to an inbound Ping, or a GoAway
from a protocol error. The gate is clobber-prevention: if you read another inbound frame while the slot is full, its processing might also
produce a reply that has nowhere to go.
That's fine as long as the slot drains quickly. It only drains via `start_send_unpin`, which only runs when
`socket.poll_ready_unpin().is_ready()` — i.e., when the TCP send buffer has room. So the implicit assumption is "writes never block for long."
Under symmetric back-pressure that assumption fails. With both peers pushing stream data, each side's send buffer fills. A Ping arriving at
either side gets a Pong queued into `pending_read_frame` — and stays there, because the socket isn't writable. Both sides now have the read gate
closed; neither drains the other's send buffer; nothing recovers. Stream commands sit stranded in `stream_receivers` indefinitely. It's a
deadlock, not a transient stall.
This isn't a pathological workload — it's what symmetric application-level multiplexing tends to produce. We see it under heavy concurrent
multi-stream traffic where both peers are simultaneously busy enough for their send buffers to fill.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in yamux/src/connection.rs at Connection::poll, especially the pending_read_frame gate around line 456, and compare the behavior with tlsnotary/tlsn-utils@b452352. Exercise symmetric multi-stream back-pressure with both peers sending data; done means stream commands continue progressing instead of remaining stranded in stream_receivers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 48/100