The Pascal i386 relocation row is a guard that cannot fail
Measured
The row (Makefile, the Pascal-object arm of test-emit-obj, just below the
C-object arm):
readelf -rW $(TESTTMP)/test_emit_obj_386.o | awk '/Relocation section/{s=($$0 ~ /rel\.text/)} s && /R_386_32/{n++} END{exit (n+0)==0 ? 0 : 1}' || { echo "..."; exit 1; }
n is unset when nothing matches, n+0 is 0, and 0 is the expected value. So:
| input | exit | reads as |
|---|---|---|
an object with no R_386_32 in .rel.text |
0 | PASS (correct) |
an object with no .rel.text at all |
0 | PASS (vacuous) |
the literal text not an elf file |
0 | PASS |
The third row is the one that settles it: the assertion cannot tell a correct answer from having read nothing. It is CLAUDE.md's own rule twice over — if the machinery did nothing at all, would this row still pass? (yes), and assert the PRECONDITION, not just the comparison (a comparison whose inputs were never proven to exist cannot fail).
The fix is already in the file, one block up
The C-object arm asserts two things and explains itself:
if [ "$$pcr" -le "$$abs" ]; then echo "... $$abs absolute vs $$pcr PC-relative -- the data-reference conversion regressed"; exit 1; fi
if [ "$$abs" -ne 0 ]; then echo "... still has $$abs absolute relocation(s)"; exit 1; fi
.textmust be MOSTLY position-independent for this subject, not merely partly. A bare nonzero PC32 count stays green after a whole family stops converting; this does not. It is a guard that can fail and has: before families B and C landed, the same subject was 332 absolute against 120 PC-relative and this line was RED.
pcr > abs is exactly the missing precondition — it cannot hold unless
relocations were actually read. The author wrote the reasoning down and the
next arm did not inherit it, which is the ordinary way this happens: the two
arms are different claims (the comment says so, correctly — the Pascal object
also carries @proc addresses via ProcAddrFix and external calls through a
.data slot via DynCall, arrays the C emitters never touch), and being
different claims is what stopped anyone reading them as one pattern.
A second, independent weakness — frankD, not re-measured by me
From the row they cleared at HEAD 2699f5769: the count can reach 0 by
accident. One extra unrelated local in PXXIoCheck moves code off -0x10,
the shape that needed an absolute relocation stops occurring, and the count goes
1 -> 0 with the conversion mechanism untouched. They confirmed that
particular green is real by checking the load-bearing condition in the artefact
directly (8b 45 f0 still at 28f22, the store converted anyway, 0 absolute
against 587 PC-relative) — which is the right check and is not what the row
performs.
So there are two separate ways to be green here and neither is "the conversion works": read nothing, or have the input construct quietly stop occurring. They compose — the second produces a genuine zero, the first produces a zero from no data, and the row prints the same thing for both and for the real success.
What to do
Not "add a positive control" in the abstract. Copy the pattern already twenty lines above:
- Assert the population is non-empty — some minimum count of
.rel.textrelocations of any kind, so an unreadable file or a missing section is RED rather than green. - Assert a RELATION rather than a bare count —
pcr > abs, which carries no expected constant, cannot be satisfied by silence, and stays meaningful as the object grows. - Keep
abs == 0as the second assertion. It is the stricter claim and it is worth having; it is only unsafe alone.
Then corrupt each arm on purpose and check it goes RED before landing — the step that found this class three times tonight and was skipped the times it did not.
Scope
The -rW | awk shape is worth grepping for elsewhere in the Makefile before
closing: any END{exit (n+0)==0 ...} over a filtered stream has this property,
and the expected value being zero is what makes the vacuous case invisible.
This ticket is about the one row that was measured.
Not this ticket
bug-t-a-tier-job-identifier-is-a-selector-doing-double-duty-as-a-label — that
one is about the identifier and the reason describing something other than the
defect. This one is about the assertion. They met because the same row surfaced
both.