fix: size heap allocations with sizeof(T), unblocking aether v0.643.0 - #107
Merged
Conversation
aether 0.643.0 (commit 1307dfa8) moves the hidden `int _heap_<field>` string-ownership trackers from a trailing block to inline, immediately after each string field. That grows the sizeof of pure-Aether structs whose string field isn't last — and this repo allocated ~158 structs with a hand-computed byte count (`malloc(40) as *SvgNode`) sized for the old trailing layout. Every one under-allocated by an int under the new layout, and the final tracker store ran off the end of the block: ASan shows a 4-byte heap-buffer-overflow in SvgNode (needs 48, we malloc'd 40), surfacing as glibc `malloc assertion failure in sysmalloc` / `invalid size` / `free(): invalid pointer` across 14 vg unit suites. Bisected 0.641 GOOD / 0.642 GOOD / 0.643 BAD; culprit confirmed by building 1307dfa8 directly. Fix: sweep all 158 sites `malloc(N)` -> `malloc(sizeof(T))`, across vg/, ui/, apps/ and examples/. sizeof is layout-exact and >= the old count, so it is correct under both the old and new tracker layouts and immune to any future placement change. Raw `malloc(8)` byte buffers with no struct cast are left untouched. This also hardens against the earlier 0.624.0 setter-tracker class (#1866): the boxes are now correctly sized. Pins moved together and re-verified all-green on the local matrix: - AETHER_REF v0.627.0 -> v0.643.0 - AEB_REF v0.283 -> v0.296 (aeb is not implicated; the failing suites compile via aetherc + gcc with no aeb in the loop) Regression documented for the aether line in asks/REGRESSION-0643-inline-heap-tracker-grows-struct.md (bisect, ASan, reproducer, and a design question on size-stability / a malloc-size lint). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q5pckLB6QCPfjVQAYcE9LZ
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.
What
Bump the CI toolchain pins aether v0.627.0 → v0.643.0 and aeb v0.283 → v0.296, and make the source change that the aether bump requires.
Why it wasn't a one-line pin bump
Pinning to aether 0.643.0 turned 14 pure-Aether
vg/unit suites red with glibc heap-corruption aborts (malloc assertion failure in sysmalloc,malloc(): invalid size,free(): invalid pointer— three different detectors, i.e. general metadata corruption).Bisected to aether commit
1307dfa8(first commit after v0.642.0, "Place heap trackers inline so struct-prefix punning stays sound"). It moves the hiddenint _heap_<field>string-ownership trackers from a trailing block to inline (right after each string field). That's a correct fix for the punning bug it targets, but it grows thesizeofof any pure-Aether struct whose string field isn't last.This repo allocated ~158 structs with a hand-computed byte count (
malloc(40) as *SvgNode), each sized for the old trailing layout. Under inline layout every one under-allocates by anint, and the final tracker store runs off the end of the block. ASan pinpointed it: a 4-byte heap-buffer-overflow inSvgNode(needs 48 bytes, wemalloc'd 40).vg/test/test_parser1307dfa8directThe fix
Swept all 158 sites
malloc(N)→malloc(sizeof(T))acrossvg/,ui/,apps/,examples/(98 files).sizeofis layout-exact and ≥ the old count, so it's correct under both the old and new tracker layouts and immune to any future placement change. Rawmalloc(8)byte buffers (no struct cast) left untouched. This also hardens against the earlier 0.624.0 setter-tracker class (#1866), since the boxes are now correctly sized.Verification
=== CI result: all phases passed ===).aetherc+gccwith no aeb in the loop; the aeb bump was verified independently building the whole fan-out.For the aether line
asks/REGRESSION-0643-inline-heap-tracker-grows-struct.md— full bisect, ASan output, 30-second reproducer, plus a design question (should inline placement preserve total struct size? could the compiler lintmalloc(literal) < sizeof(cast target)?). Framed as FYI, not a revert request.🤖 Generated with Claude Code