Skip to content

as370: an undeclared SET symbol is accepted and substituted — IFOX00 flags IFO006 and emits nothing #97

Description

@mgrossmann

Assembler XF requires a macro's local variable symbols to be declared with LCLA/LCLB/LCLC (or GBLA/GBLB/GBLC). as370 accepts an undeclared one, assigns it, and substitutes it. IFOX00 flags every use — IFO006 UNDEFINED VARIABLE SYMBOL, severity 8 — never substitutes it, and generates nothing.

So this is not only a missing diagnostic. The same source produces a different object module.

Reproducer

Ours:

* A macro SET symbol used without an LCLA/LCLB/LCLC declaration.
         MACRO
&NAME    UNDECL
&LOOSE   SETC  'LOOSE'
&TIGHT   SETC  'TIGHT'
LOOSEDC  DC    C'/&LOOSE/'
TIGHTDC  DC    C'/&TIGHT/'
         MEND
T        CSECT
         UNDECL
         END
IFOX00 (JOB02903) as370
RC 8 0
messages 8 × IFO006 UNDEFINED VARIABLE SYMBOL none
statements flagged 8 0
&LOOSE in the model statement not substituted — the card reads DC C'/&LOOSE/' substituted → C'/LOOSE/'
LOOSEDC / TIGHTDC not defined (cross-reference holds only T) defined
section length 000000 00000E

IFOX flags the cards twice: statements 4–7, inside the macro definition, before any call, and 11–14 in the expansion. So the check runs at definition time as well as at expansion time.

What IFOX does

erms.asm:15

         GENERR ERR6,'UNDEFINED VARIABLE SYMBOL $        '

raised at ifnx1j.asm:860, in the dictionary lookup, with IBM's own comment naming the case:

VERRC    MVC   DSEVCD(D2),=AL1(SEV6,ERR6) FLAG UNDECLARED VAR SYMB

SEV6 EQU 8 (jermsgcd.asm:33).

Where as370 lets it through

as370.c:1477-1479SETA/SETB/SETC canonicalise the name and set_put it, with no check that anything declared it:

if (!strcmp(op, "SETA")) { long v = eval_seta(c, opnd); ... set_put(c, sn, nb); return 1; }

The declarations themselves are handled just above (:1471-1474): an array form goes into c->arrb, a scalar is set_put with its type's default. So a declared scalar exists in the store before its first assignment and an undeclared one does not — which is the whole test the SET path is missing.

Risk of enforcing it: measured, and it is nil

An instrumented build reported every first assignment to a SET symbol that no LCL/GBL declared:

corpus modules with an undeclared SET symbol
ecosystem (libc370 743, rexx370, ufsd, ftpd, httpd, httplua, httprexx, lua370, mvsmf, lstring370, nsf370) 826 0
a local tree of real IBM MVS assembler, spread sample 277 0

Nothing measured relies on the leniency — unsurprising for the second corpus, which was written for this assembler in the first place.

How it surfaced

Writing the fixture for #94. The first capture came back with 22 statements flagged and nothing else wrong: a fixture written against as370 is not automatically a fixture the guest will take, and the difference was exactly this. Recorded in tests/listref/README.md at the time.

Two halves to a fix

  • The diagnostic is small: check at SETA/SETB/SETC that the canonical name was declared, and at the reference site in vref. Severity 8, and IFOX checks inside the definition as well as in the expansion.
  • The code effect is the larger half: IFOX leaves the reference unsubstituted and the statement generates nothing, so the section comes out empty. Matching that means the substitution path has to distinguish "undeclared" from "declared but null", which today it does not.

The first half alone already turns silent divergence into a loud one, and the measurement says no module pays for it. Worth doing even if the second half waits.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions