Concurrent connections for the same UUID may both be admitted because finaliseConn checks Server.Player before sending to srv.incoming, while the UUID is only inserted into srv.p later by Accept.
A possible interleaving is:
- Two
finaliseConn goroutines for the same UUID both observe no online player.
- Both call
createPlayer and enqueue an incoming session, incrementing pwg twice.
Accept processes both and the second assignment overwrites the first entry in srv.p.
- Session teardown can save the wrong session, skip one save, or fail to balance one
pwg.Done(), depending on close timing.
The duplicate check and reservation need to be one atomic lifecycle transition. A likely fix is a per-UUID joining reservation protected by pmu, released on every failed load/start/enqueue path and transitioned to online when Accept admits the player.
This predates #1363 and should be fixed separately from that PR asynchronous-save changes.
Concurrent connections for the same UUID may both be admitted because
finaliseConnchecksServer.Playerbefore sending tosrv.incoming, while the UUID is only inserted intosrv.plater byAccept.A possible interleaving is:
finaliseConngoroutines for the same UUID both observe no online player.createPlayerand enqueue an incoming session, incrementingpwgtwice.Acceptprocesses both and the second assignment overwrites the first entry insrv.p.pwg.Done(), depending on close timing.The duplicate check and reservation need to be one atomic lifecycle transition. A likely fix is a per-UUID joining reservation protected by
pmu, released on every failed load/start/enqueue path and transitioned to online whenAcceptadmits the player.This predates #1363 and should be fixed separately from that PR asynchronous-save changes.