Repository navigation
netfix-disconnect-callback-cannot-reenter-a-clearing-slot: a slot being disconnected is not disconnected again - #196
Merged
Conversation
…or a disconnect re-entered from the callback By: Rowan Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng disconnected is not disconnected again The disconnect callback runs while the slot still holds its client. The slot is now marked as disconnecting for the length of the callback: a disconnect of it from inside the callback is a no-op, stop skips it in its disconnect loops and then clears it without a second callback, and the outer disconnect returns at once when the callback has stopped the server. The encryption manager's back pointer is cleared only for a valid encryption index. The loopback disconnect takes the same guard. By: Rowan Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Card:
netfix-disconnect-callback-cannot-reenter-a-clearing-slot(stream netcode-audit-fixes, NET-AUDIT 2026-10-13, audit J finding 7 / audit E E-20, E-23).Defect. The disconnect callback runs while the slot is still connected. A callback that disconnects the same client re-enters
netcode_server_disconnect_client_internal; the inner call clears the slot (encryption index -1, count decremented), then the outer frame readsencryption_manager.address[-1]innetcode_encryption_manager_touch, writesencryption_manager.client_index[-1], and decrementsnum_connected_clientsto -1. A callback that callsnetcode_server_stopreaches the same slot throughnetcode_server_disconnect_all_clients.Fix (netcode.c only).
client_disconnecting[NETCODE_MAX_CLIENTS]on the server: set before the callback, cleared innetcode_server_reset_client_slot.netcode_server_disconnect_client,netcode_server_disconnect_all_clients,netcode_server_disconnect_loopback_clientand stop's loopback loop skip a slot that is disconnecting.netcode_server_stopclears a slot whose callback called stop, without a second callback, so a restart finds every slot empty.!running || !client_connected(the loopback disconnect does the same).client_index[...] = -1write runs only for an encryption index >= 0.Test.
test_disconnect_callback_reentry_is_harmless. It brings up a server with the script override hooks (no socket, time passed in) and admits one client through a real handshake. It runs three cases: (A) the callback disconnects the same client, (B) the callback stops the server, then a restart, (C) a timeout insidenetcode_server_updatewhose callback stops the server. Each case checks that no assert fired, that the callback ran exactly once, that it saw the reason, id and user data, that the count is 0, that the slot and encryption index are clear, that the mapping count is 0, and that nothing in the manager points at the slot.Red (f94c32b, hetzner1):
check failed: ( num_ignored_asserts == 0 ), function test_reentry_check_slot_cleared ... line 11172, exit 132netcode.c:3901:68: runtime error: index -1 out of bounds for type 'netcode_address_t [1024]', exit 1Green (be2e702, hetzner1):
./build/bin/testand./build-asan/bin/test(-DNETCODE_SANITIZE=ON) both print*** ALL TESTS PASSED ***, exit 0, 58 tests.Planted regression. Removing the disconnecting skip in
netcode_server_disconnect_clientturns the test red again (check failed: ( num_ignored_asserts == 0 ), exit 132). After the restore it is green in both builds.Not done.
netcode_server_receive_packetstriggered (a disconnect packet) returns to a receive loop that keeps reading packets on the stopped server. That path is not covered here.yojifix-server-stop-inside-a-disconnect-callback-is-deferredare separate cards.Worked by Rowan (Opus lane)
🤖 Generated with Claude Code