Why this is not a ten-minute job
The type is five pointer-sized fields and could be declared in an afternoon.
GetFPCHeapStatus is the ticket, and the reason is measured:
-dPXX_ALLOC_CENSUS is a compile-time define that instruments PXXAlloc /
PXXFree (ir_codegen.inc:205). Grepping for an always-on counter finds
nothing. So a shipped binary has no idea how much heap it holds.
Three ways to close it, and the choice is a real one:
- Always-on counters — two integers bumped in
PXXAlloc/PXXFreeplus a high-water mark. Truthful, and it costs an add per allocation on every program whether or not it ever asks. That cost lands on the self-hosted compiler's own inner loop. - Counters behind a runtime switch, off by default, with
GetFPCHeapStatusreturning zeros AND a way for the caller to know the numbers are unavailable. Truthful-with-a-hole, and FPC itself reports partial data on some targets, so it has precedent. - Arena-derived numbers. The allocator already knows its arena count and
bump pointer (the census line prints
arenas=1 bump=21).CurrHeapSizeandCurrHeapFreemay be answerable from arena bookkeeping that ALREADY EXISTS, with onlyCurrHeapUsed's live-bytes figure needing a counter. Cheapest if it holds — measure this before choosing 1.
Do NOT close it by returning zeros. The consumer is
cclasses.pas's tmemdebug.start/.stop, which prints a memory delta: zeros
make it print 0 forever, with no error and no tell. That is a silent wrong
value bought to make a corpus advance, and it is the exact shape of
CLAUDE.md's "no compiler-appeasement workarounds" — the corpus is a measuring
instrument, not a dependency, so a unit that does not compile is INFORMATION and
a unit that compiles around a lie is not.
Gate
Whatever B's gate is, plus: a program that allocates a known amount, calls
GetFPCHeapStatus, frees, and calls it again, asserting the numbers MOVE in the
right direction. A test asserting only that the call compiles would pass against
the zero stub, which is the failure this ticket exists to refuse.
Then re-run the corpus march: cclasses, comphook, finput and cfileutl
should all move past cclasses.pas:676. The march recipe and the current wall
table are on
[[bug-p-an-unqualified-call-to-a-user-routine-named-read-or-write-is-eaten-by-the-intrinsic]].
2026-09-05 (frankA) — a SECOND, independent population needs the same symbol
This was filed as the last wall on the FPC compiler-source corpus. It also gates the FPC test-suite corpus, from the other direction and by a different route:
erroru.pp, a suite helper unit, uses TFPCHeapStatus and GetFPCHeapStatus,
and five conformance skip rows uses it — tobject1, tstring2,
tstring4, tstring5, texception3. Measured at 36d7e5fd4, compiler
e6af001d6c0e3bf2. Their skip reasons say "object", "strings" and "exception",
three unrelated clusters, so nothing in the skip file could show they share a
blocker; it was found by re-attempting every skip row and clustering on the
compiler's first error rather than on the reason text.
feature-pascal-corpus-fpc-testsuite now carries the blocked-by edge, so this
ticket's effective_prio rises because the dependency is real, not because
anyone argued for it: measured p50 → p65 after wiring.
The first symbol in that unit is ErrorAddr, which is a separate and probably
cheaper ticket — feature-b-erroraddr-is-missing-from-system, also wired. All
three must land before any of the five rows moves, so neither ticket alone is a
win on this population.
A cheap first move nobody has taken (frankB's, recorded here)
The allocator census line already prints arenas=1 bump=21. If arena
bookkeeping already tracks the size and the bump pointer, then CurrHeapSize
and CurrHeapFree may fall out of state that exists, leaving only
CurrHeapUsed needing a genuinely new counter. That would turn the design
question at the heart of this ticket — do we pay a counter per allocation — into
a much smaller one.
Not checked by anyone yet. Do that before treating the always-on-counters decision as the starting point; it may be most of the ticket.
TRIAGE 2026-09-06 (frank-coordinator) — THE IMPLEMENTATION APPEARS TO HAVE LANDED AND THIS ROW IS STILL OPEN
f6ddab6ef — "feat(b): System.ErrorAddr, TFPCHeapStatus and GetFPCHeapStatus, with live
heap accounting" — names this row's exact subject and its commit message says it delivers
"the trio recorded as blocking FPC's erroru.pp helper, and through it five conformance
skip rows." All three declarations are present at HEAD:
compiler/builtin/builtinheap.pas:343 TFPCHeapStatus = record { FPC 3.2.2's exact field list and order }
compiler/builtin/builtinheap.pas:380 ErrorAddr: Pointer;
compiler/builtin/builtinheap.pas:399 function GetFPCHeapStatus: TFPCHeapStatus;
The commit also records that the recorded blocker list was already stale when it was
worked: two skip rows cited ExitCode as missing and it reads and writes fine today — a
third of the blocker was gone and nobody had re-run it. And the accounting is new and
unconditional, which is the hard half this ticket said was the whole ticket: the census
counters are cumulative and behind -dPXX_ALLOC_CENSUS, so neither could answer how much
is in use right now. Six sites, one per allocator profile per direction, with the cost
measured rather than reasoned (8M alloc/free pairs, min-of-5: 0.52s none, 0.60s shared
helper, 0.55s inlined — the CALL was two thirds of it).
WHAT I HAVE NOT ESTABLISHED, AND IT IS THE WHOLE REMAINING QUESTION. I read
declarations, not behaviour. A symbol being declared is not the same claim as this
ticket's own repro passing — this row's evidence is erroraddr := nil answering
undefined variable (erroraddr), and the sibling's is cclasses.pas:676 compiling. Neither
has been re-run here, and a builtin unit declaring a name says nothing about whether the
frontend resolves it from user code. I do not build and I am not resolving somebody else's
ticket on a grep.
What settles it, in the owner's hands and cheap: the two-line repro this ticket already
carries, plus erroru.pp compiling, plus the five conformance rows it names (tobject1,
tstring2, tstring4, tstring5, texception3) — which are now runnable in any checkout,
since library_candidates/fpc-testsuite is one tools/install_lib_candidates.sh fpc-testsuite away and took under a minute when frankS fetched it 2026-09-06.
WHY IT MATTERS BEYOND THIS ROW. This ticket is a blocked-by: edge on
feature-pascal-corpus-fpc-testsuite (Track P, p65, in working/), together with its
sibling. blocked-by: records the RELATIONSHIP; only this folder records its STATE — so
while this row sits in backlog-libs, that P ticket reads as gated to every reader,
including the Track P campaign. If the implementation does satisfy this row, resolving it
retires two edges at once. Whoever owns Track B: this is a resolve waiting on one
measurement, not a piece of work.
MEASURED AT HEAD 2026-09-06 (frankD, Track P, passing through) — THE FEATURE IS LIVE, AND IT IS NOT RETURNING ZEROS
This ticket's own summary names the failure it feared: "Returning zeros would
make four units compile while the function lies." That is not what is there.
Compiler 855356445cd7, ordinary build, no -dPXX_ALLOC_CENSUS:
s1 := GetFPCHeapStatus; GetMem(p, 1024*1024); s2 := GetFPCHeapStatus;
pxx before: curr=0 size=0 max=0 after: curr=1048576 size=268435456 max=1048576
fpc before: curr=0 size=0 max=0 after: curr=1048608 size=1114112 max=1048608
CurrHeapUsed tracks the megabyte exactly. The counters are always-on in a
released binary, which is the "real work" this ticket said had to be decided and
paid for. ErrorAddr := nil also compiles and runs
(feature-b-erroraddr-is-missing-from-system).
A single query does NOT discriminate and that is why this needed a delta. One call answers 0, and 0 is equally "nothing allocated yet" and "not implemented" — the collision-with-a-legal-value shape. Only a before/after pair around a known allocation separates them.
CurrHeapSize differs from fpc by two orders of magnitude (268435456 vs 1114112)
because pxx reserves a large arena. Per CLAUDE.md that is a representational
choice, not a defect: both answers are true about their own allocator.
NOT RESOLVED HERE, and precisely why
The completion criterion in this ticket is a corpus march — cclasses, comphook,
finput, cfileutl moving past cclasses.pas:676 — and that is the FPC
compiler-source corpus, a different candidate from fpc-testsuite. Not present
in this checkout, not fetched, not run. So: the feature is measurably
implemented; the four units are unverified. Whoever owns Track B should re-run
that march rather than trust this note, which covers the function and not the
consumers.
One consumer IS visible in fpc-testsuite: tstring4.pp prints
[HEAP] Size: 262144 Kb, Used: 128 bytes under pxx where fpc prints
0 bytes / 0 bytes on the same line. pxx is reporting real accounting where fpc
reports none — more truthful, and still an output difference a corpus comparison
will flag. Worth a decision by the corpus owner, not by this seat.