← board

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