Skip to content

refactor: convert IP addresses to text without allocating - #69

Merged
sbogomolov merged 2 commits into
mainfrom
addr/non-allocating-text
Aug 8, 2026
Merged

refactor: convert IP addresses to text without allocating#69
sbogomolov merged 2 commits into
mainfrom
addr/non-allocating-text

Conversation

@sbogomolov

Copy link
Copy Markdown
Owner

IpAddress's formatter went through ToString, allocating a string per formatted address — including IPv4, which sized its buffer to 16 and stepped just past libstdc++'s small-string capacity. ToChars writes into a caller-provided buffer and returns a view of it; ToString stays for the one caller that needs an owning string.

Nine raw_socket log sites passed ToString into a formatter that already handles IpAddress, so they pass the address itself now — the rest of the codebase, including the test util, already did. Behaviour note: IPv6 prints bracketed in those nine lines as a result ([ff02::c]), matching every other site.

MacAddress needed no change — it has no ToString and its formatter always wrote straight to the output iterator.

Enforcing it

Three changes now rest on formatting staying off the heap, with nothing checking it. ScopedAllocationCounter counts allocations via the sanitizer's malloc hooks. Two earlier designs were discarded for concrete reasons worth recording:

  • replacing global operator new collided with ASan's own nothrow/aligned overloads (alloc-dealloc-mismatch, whole suite down);
  • watching __sanitizer_get_current_allocated_bytes is a net figure, so a string built and freed inside the window reads as zero — it passed with the regression deliberately reinstated.

The hook version catches it: 1 allocation with ToString restored in the formatter, 0 with ToChars. It needs a long IPv6 literal, since ff02::c fits libc++'s SSO and never allocated either way.

Sanitizer-gated, so the test is #if-guarded to match.

Native (893), docker Debug (880) and docker Release (879, test correctly excluded) all green.

The formatter went through ToString, which allocated a string per
formatted address -- including IPv4, since it sized the buffer to 16
and stepped past the small-string capacity. ToChars now writes into a
caller-provided buffer and returns a view of it; ToString keeps the
owning form for callers that need one.

raw_socket passed ToString into log calls whose formatter already
handles IpAddress, so those pass the address itself now. IPv6 prints
bracketed there as a result, matching every other site.
Three changes have now rested on formatting staying off the heap with
nothing enforcing it. ScopedAllocationCounter counts allocations
through the sanitizer's malloc hooks -- counting each call, not
watching allocated bytes, because a string built and freed inside the
window nets to zero and is exactly what should fail.

Sanitized builds only, so the test is guarded to match; the Debug gate
always qualifies.
@sbogomolov sbogomolov self-assigned this Aug 8, 2026
@sbogomolov
sbogomolov merged commit f83139a into main Aug 8, 2026
17 checks passed
@sbogomolov
sbogomolov deleted the addr/non-allocating-text branch August 8, 2026 23:16
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