Skip to content

Prevent concurrent close from reopening a closed transport - #633

Merged
bsergean merged 1 commit into
masterfrom
fix/close-state-race
Nov 5, 2026
Merged

bsergean merged 1 commit into
masterfrom
fix/close-state-race

Conversation

@bsergean

@bsergean bsergean commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

A concurrent WebSocketServer::stop() and peer shutdown can let WebSocketTransport::close() act on a stale OPEN state. After the connection thread finishes CLOSED and clears its message callback, the close caller moves the transport back to CLOSING. A second close notification then calls the cleared callback and throws std::bad_function_call.

Recheck the state and perform the initial close metadata update and CLOSING transition under _setReadyStateMutex. Preserve the fast path and poll interrupt for an ongoing/completed close: callbacks run under that mutex and may request close again. Sending the frame and waking the socket remain outside the state lock. C++11 compatibility and public APIs are unchanged.

Add regressions that pause close initiation while shutdown or another close caller runs, and verify callback reentry. They check that CLOSED is never reopened, the first close request is preserved, only one Close frame is sent, and clearing the callback after shutdown is safe.

Validation:

  • On unchanged master, the two race regressions fail, including the reported std::bad_function_call; the reentry test passes.
  • With the fix, all 15 dispatch cases pass (422 assertions), and 100 repeated runs of the three race cases pass.
  • All 24 native suites pass; ThreadSanitizer reports no races in the full dispatch suite.
  • Targeted Docker Autobahn checks pass all 51 cases in each role, covering closing, reserved opcodes, and UTF-8 failure timing. The autobahn label enables the full suite in CI.
  • Strict C++11 build, formatting, and git diff --check pass.

Closes #632.

@bsergean bsergean added the autobahn Run the Docker Autobahn client and server compliance check label Nov 5, 2026
@bsergean
bsergean merged commit b651e91 into master Nov 5, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autobahn Run the Docker Autobahn client and server compliance check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebSocketTransport::close() race: CLOSED -> CLOSING again, second close callback calls a cleared std::function (terminate)

1 participant