diff options
| author | EuAndreh <eu@euandre.org> | 2026-05-01 07:44:58 -0300 |
|---|---|---|
| committer | EuAndreh <eu@euandre.org> | 2026-05-01 07:44:58 -0300 |
| commit | 4ea09f1e389fe410aa67faab866e67bc781214fa (patch) | |
| tree | d7f51900de3f666019dfcda4076297a9411cdb34 /tests/functional | |
| parent | Bump welcome-banner counts after RPL_005 split (diff) | |
| download | papod-4ea09f1e389fe410aa67faab866e67bc781214fa.tar.gz papod-4ea09f1e389fe410aa67faab866e67bc781214fa.tar.xz | |
Fix JOIN race: pin NAMES/broadcast to atomic membership snapshot
Two clients JOINing the same channel concurrently could each see the
other in their own NAMES reply, and both could end up auto-opped on
a freshly-created channel. The cause was that join-one! did:
(swap! channels update handle (fnil conj #{}) nick)
...
(get @channels handle) ;; for NAMES + broadcast + auto-op
Between the swap! and the @channels read, a peer's swap! could land,
so the read returned a set that already included them.
Switch the swap to swap-vals!, capture members-before / members-after
as a snapshot of state at the moment of our atomic update, and feed
that snapshot to the broadcast loop, the metadata-2 push, the away-
notify push, the auto-op decision, and the NAMES reply (via a new
:members keyword on names-for). Auto-op now keys off (empty?
members-before) instead of comparing the live atom to #{nick}.
Surfaced and verified by the differential test in chat.papo.im,
which previously had to insert quiesce checkpoints between concurrent
JOINs to dodge the race; those checkpoints are no longer needed.
Diffstat (limited to 'tests/functional')
0 files changed, 0 insertions, 0 deletions
