The ShortString array-of-const leak assertion cannot run — its subject allocates 33 times
Symptom
tools/assert_no_leak.sh test_ssvarrec26 200 .../test_ssvarrec_census26
assert_no_leak[test_ssvarrec26]: only 33 allocations — too few to show anything.
pxx-census: allocs=33 frees=13 live=20 bytes=1328 reuse=12 list=0 bump=21 arenas=1
make: *** [Makefile:11159: test-core] Error 1
tools/assert_no_leak.sh:55 refuses when allocs < 100, with the comment
"A run that allocated almost nothing cannot demonstrate the absence of a
per-iteration leak either: the subject has to have run." That guard is
correct, and it is exactly the precondition-assertion discipline CLAUDE.md
asks for. The subject is what is wrong: the row asks for 200 iterations and
the program performs a single pass, so it cannot reach the floor no matter
what the compiler does.
It is NOT anyone's in-flight change
Measured by ablation while landing an unrelated aarch64/arm32 backend fix
(binary 5c72f8297ee1): stash the change, rebuild — converged after 1 round(s), binary 80a3f9e73673 — and the census is identical,
allocs=33 frees=13 live=20 bytes=1328, still exit 1. Restoring the change
rebuilt back to 5c72f8297ee1, the same sha as before the ablation, which is
also a determinism check on the two rebuilds.
The two files that fix touches are ir_codegen_aarch64.inc and
ir_codegen_arm32.inc, neither of which a native x86-64 compile reaches, so
the ablation confirmed a structural argument rather than testing a live
hypothesis — but the number is the number, and "no observable difference" is a
claim about one target, so it was worth the two minutes.
Where it came from
The row arrived with 1cac1742a "fix(A): a ShortString in array of const
boxed a pointer nobody could use", whose Makefile comment says the fix parks
each ShortString element in an owning hidden AnsiString local — "exactly the
shape that leaks if the handle never gets an owner. A value assertion CANNOT
see that." The reasoning for wanting a leak assertion here is right, and it
is the same reasoning assert_no_leak exists for. The assertion simply never
got a subject that could satisfy it.
Fix
Either give test_shortstring_in_array_of_const.pas a loop around the
array of const calls so the census has something to count — the shape every
other assert_no_leak subject already has — or drop the row to an assertion
class the single-pass program can satisfy, and say which in the Makefile
comment.
Do not "fix" it by lowering assert_no_leak's floor. The floor is what makes it a guard rather than a row that prints PASS, and it is shared by every other leak subject in the suite.
Cost
The heavy gate mode is RED for every lane until this lands, so anyone who runs
the wide suite their change genuinely warrants gets a red that is not theirs
and has to spend an ablation to discover that. The quick tier is unaffected,
and so is make compiler/pascal26.
Resolved by frankB in 1c274a83b, before I could take it
Measured at HEAD b351b7030, compiler dad98c7a5537 (the pull that brought
the fix touched zero files under compiler/ or lib/, so the binary I had
was still correct for this tree and no rebuild was needed to read this):
assert_no_leak[test_ssvarrec26]: ok (allocs=5411 frees=5387 live=24, bound 200)
rc=0
33 -> 5411. The value row passes too.
And it was fixed the right way round. 1c274a83b changes
test/test_shortstring_in_array_of_const.pas and nothing else in the harness —
tools/assert_no_leak.sh is untouched and its floor is still 100. So the
SUBJECT gained the iterations it needed rather than the GUARD being lowered to
meet it, which is what this ticket asked for and the failure mode it warned
about.
Both shas in the record are real; neither is a ghost. 1cac1742a
(2026-09-04) is where the row ARRIVED, which is what this ticket said;
1c274a83b (2026-09-05 01:46) is where it was FIXED. Both are ancestors of
origin/master. My red was measured before that second commit existed, so it was
true when taken and stale within hours — worth recording because "different sha
in two reports" reads exactly like a ghost, and here it was two correct
citations of two different events.
Log
- 2026-09-05 — resolved; this names the commit that carried the resolve, which is not always the one that carried the change — commit 746c6ea1d.