fix(as370): an undefined symbol is IFO188, and the instruction is zeroed (#82) - #87
Merged
Merged
Conversation
…oed (#82) x_factor returned 0 for a symbol that is in no table, in pass 2 as much as in pass 1, and recorded nothing. IFOX00 rejects it -- IFO188 <symbol> IS AN UNDEFINED SYMBOL, severity 8 (erms.asm:193 / jermsgcd.asm SEV188) -- and assembles the whole machine instruction as zero. The bytes matter as much as the message. IFOX00's all-zero instruction is an invalid opcode and program-checks the moment it is reached; as370's kept its opcode and ran -- a branch to address 0, a load from base+0, an MVC into offset 0 of whatever the base register happened to hold. Silent corruption where the guest gives an S0C1. That is how nsf370's two modules lost a DCBD, two EQUs and a whole instruction to the column-72 continuation rule (#72) without one diagnostic between them: the swallowed cards defined symbols, and every reference to them went quiet. Machine instructions take the IFO236 path -- scan_undef_terms runs in the else-if before the format switch, so a flagged statement never reaches resolve() and the same symbol cannot be reported twice. Every other statement (DC/DS/EQU/ORG/USING/ END) is recorded from x_factor, where IFOX zeroes the value but leaves the statement alone; the value and the relocation count there are deliberately untouched, so no deck moves. A literal is the one operand not zeroed: IFOX assembles `L 4,=A(NOVAL)` normally and flags NOVAL against the pool, which emit_lit now does against the statement that wrote the literal, the way IFO158 already attributes one. "Undefined" is neither !sym_find nor !defined: sym_get enters EXTRN/WXTRN, V-con and =V symbols that keep defined == 0 for the whole assembly, so !defined alone would have flagged every external in the corpus. They carry S_ER, and nothing else undefined does. Counted whether or not printed, per bce32d8: the list stops at 512 and the overflow says so. Measured over 826 ecosystem modules (libc370 743, rexx370, ufsd, ftpd, httpd, httplua, httprexx, lua370, mvsmf, lstring370, nsf370): zero raise IFO188, the same 825 assemble as before, and the differential corpus gate reports no module moved. Against nsf370 at 9012263^ -- before its own fix for the eaten cards -- the two modules the issue names now report five and three undefined symbols: DCBDDNAM, IHADCB, DCBOFLGS, DCBOFOPN and ANCVERNO, ASCBASID, DOUNSTG. tests/run.sh replaces the #82 tripwire with the oracle's numbers and adds the control for what must NOT be read as a symbol: X'40', C'A', B'1111', L'FIELD and a literal, every reference forward, at RC 0.
mgrossmann
force-pushed
the
fix/undefined-symbol-ifo188
branch
from
August 29, 2026 06:16
df180fb to
1ae5a84
Compare
This was referenced Aug 29, 2026
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.
Closes #82.
x_factorreturned 0 for a symbol in no table, in pass 2 as much as in pass 1, and recorded nothing. IFOX00 rejects it —IFO188 <symbol> IS AN UNDEFINED SYMBOL, severity 8 (erms.asm:193/jermsgcd.asmSEV188) — and assembles the whole machine instruction as zero.The bytes matter as much as the message. IFOX00's all-zero instruction is an invalid opcode and program-checks when reached; as370's kept its opcode and ran — a branch to address 0, a load from base+0, an MVC into offset 0 of whatever the base register held.
Shape of the fix
scan_undef_termsin theelse ifbefore the format switch — instruction zeroed,hasa1(andhasa2for SS) set to 0x_factor, pass 2 only — IFOX zeroes the value, not the statement=A(NOVAL))L 4,=A(NOVAL)normally and flags the pool;emit_litflags the statement that wrote the literal, the way IFO158 already doesBecause a flagged instruction never reaches
resolve()/expr_val(), the two halves cannot report the same symbol twice.The predicate is neither
!sym_findnor!defined.sym_getenters symbols that are only referenced — EXTRN/WXTRN, a V-con, a=Vliteral — and those keepdefined == 0for the whole assembly.!definedalone would have flagged every external in the corpus. They carryS_ER, and nothing else undefined does:!s || (!s->defined && s->type != S_ER).At the
x_factorsite the value and the relocation count are deliberately untouched — the change there is diagnostic only, which is why no deck moves.Counted whether or not printed, per bce32d8: list stops at 512, the overflow says so (verified with 600 undefined symbols: 512 printed,
... and 88 further undefined-symbol diagnostics, RC 8).Verification
listref/ifox-listing-undefsym.txt5840 F018; RC 8, 5× IFO188tests/corpus/check.shno module moved— 743 decks byte-identicaltests/run.shALL SAMPLES BYTE-IDENTICAL TO IFOX00(incl. hello/litmove/arith/ksdsnatr with a SYS1.MACLIB extract)tests/listref/check.shModules probed: libc370 (743), rexx370, ufsd, ftpd, httpd, httplua, httprexx, lua370, mvsmf, lstring370, nsf370.
The positive control. nsf370 has since fixed its eaten cards (
9012263), so its current tree is clean. Assembled at9012263^— the state the issue measured — the two modules report exactly the symbols the issue names:L R3,REQFUNC(,R8)is absent from that list because the card was eaten whole — that one is #72's diagnostic, not this one.Tests
The #82 tripwire is replaced by the oracle's numbers: RC 8, the five messages at their statements, the 14 zero bytes followed by an intact
L, and the single RLD entry (so an undefined term invents no relocation).A second case guards what must not be read as a symbol —
X'40',C'A',B'1111',L'FIELD,=A(…)— with every symbol a forward reference, which is what proves the diagnostic stays silent in pass 1. Without the self-defining-term skip,MVI FLAG,X'40'would report an undefined symbol namedXand zero a good instruction.Known divergences, documented not fixed
NUMBER OF STATEMENTS FLAGGED: IFOX says 4, as370 says 5 — as370's counter counts messages. Second recorder to inherit this knowingly; filed separately.A EQU BwithBdefined further down: IFOX resolves EQU in pass 1 and flags IFO188; as370's pass-2 gate keeps it silent and givesAthe pass-1 value 0. Its own defect, adjacent to this one; filed separately.tests/undefsym.sis frozen — IFOX00's listing prints its five comment cards verbatim and numbers every statement from them, so its now-stale header cannot be corrected without the fixture and the oracle drifting apart. Noted intests/run.shandtests/listref/README.md.