Skip to content

Fix message_buffer under-allocation in receive_messages#305

Open
caniko wants to merge 2 commits intoNoxime:masterfrom
caniko:fix/message-buffer-reserve
Open

Fix message_buffer under-allocation in receive_messages#305
caniko wants to merge 2 commits intoNoxime:masterfrom
caniko:fix/message-buffer-reserve

Conversation

@caniko
Copy link

@caniko caniko commented Feb 24, 2026

What

Fixes a buffer under-allocation bug in NetConnection::receive_messages, receive_messages_into, and NetPollGroup::receive_messages.

Why

The old code did reserve(batch_size - capacity), but Vec::reserve(additional) guarantees capacity >= len + additional — not capacity + additional. When the internal message buffer had some leftover capacity but less than batch_size, the reservation fell short. The Steam API could then write messages beyond the allocated region, causing undefined behavior.

Since the buffer is always drained between calls (len == 0), passing batch_size directly gives the correct guarantee: capacity >= batch_size.

Changes

Three call sites, same one-line fix each — replaced reserve(batch_size - capacity) with reserve(batch_size).

Currently `send_messages()` is only available on `ListenSocket`, but the
underlying C++ API `ISteamNetworkingSockets::SendMessages()` is a
top-level interface method that works with any connection handle.

This means P2P dial-side connections (from `connect_p2p()`) have no way
to use the efficient batched send path with per-message channel/lane
tagging — the dialer never gets a `ListenSocket`, only a `NetConnection`.

This is needed to use connection lanes (`ConfigureConnectionLanes`) from
both sides of a P2P connection. Without it you can configure lanes but
only the listener can actually send on them.

The implementation is identical to `ListenSocket::send_messages()` — both
structs hold the same `*mut ISteamNetworkingSockets` pointer, just in
different fields.

Closes Noxime#302
`Vec::reserve(additional)` ensures `capacity >= len + additional`, not
`capacity >= capacity + additional`.  When the buffer had some leftover
capacity (0 < capacity < batch_size), the old expression
`reserve(batch_size - capacity)` would guarantee only
`capacity >= batch_size - old_capacity`, which is less than batch_size.
The Steam API could then write past the allocated region.

Pass `batch_size` directly so the guarantee becomes
`capacity >= 0 + batch_size = batch_size`, which is correct since the
buffer is always drained between calls (len == 0).
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