Skip to content

Add runtime bounds guards to assert-only public entry points#146

Merged
gafferongames merged 1 commit into
mainfrom
runtime-guards
Jul 9, 2026
Merged

Add runtime bounds guards to assert-only public entry points#146
gafferongames merged 1 commit into
mainfrom
runtime-guards

Conversation

@gafferongames

Copy link
Copy Markdown
Contributor

Summary

Closes the Debug-vs-Release memory-safety gap in the public API: functions taking max_clients or a client_index validated them with netcode_assert only, which compiles out under NDEBUG. In release builds, netcode_server_start( server, 500 ) wrote past the per-client arrays, and the assert-only accessors (netcode_server_client_user_data, netcode_server_next_packet_sequence, netcode_server_client_loopback, the loopback connect/disconnect/process functions, netcode_server_send_packet, netcode_server_receive_packet, netcode_server_disconnect_client) read or wrote out of bounds for an out-of-range index.

  • Every such entry point now pairs its asserts with runtime guards that return cleanly (same belt-and-suspenders pattern the send paths already used for packet sizes). netcode_server_start logs an error for out-of-range max_clients.
  • Guards are ordered before any assert that indexes an array, since custom assert handlers may continue past a failed assert.
  • Loopback packet sizes are now guarded to (0, NETCODE_MAX_PACKET_SIZE], consistent with the network path's rejection of zero-byte payloads.
  • New test_runtime_guards (suite is now 38 tests) installs a continuing assert handler so the guards are exercised in Debug builds too, and verifies out-of-range arguments return cleanly without starting/connecting/corrupting anything.

Test plan

  • Local macOS: Release, Debug, and ASan+UBSan builds all pass the full suite including the new test
  • CI green on all 9 jobs

🤖 Generated with Claude Code

Public functions taking max_clients or a client index validated them with
netcode_assert only, which compiles out under NDEBUG. In release builds,
netcode_server_start( server, 500 ) wrote past the per-client arrays
(sized NETCODE_MAX_CLIENTS), and the per-client accessors and loopback
functions read or wrote out of bounds for an out of range client index.

Every such entry point now pairs its asserts with runtime guards that
return cleanly, following the existing pattern in the send packet paths.
Guards are ordered before any assert that indexes an array, since a custom
assert handler may continue past a failed assert.

Also guards loopback packet sizes to (0, NETCODE_MAX_PACKET_SIZE], making
loopback consistent with the network path, which rejects zero-byte
payloads.

Adds test_runtime_guards, which installs a continuing assert handler so
the guards are exercised in debug builds as well as release, and verifies
out of range arguments return cleanly without starting, connecting, or
corrupting anything. Verified under ASan+UBSan.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gafferongames gafferongames merged commit e6a1690 into main Jul 9, 2026
8 checks passed
@gafferongames gafferongames deleted the runtime-guards branch July 9, 2026 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant