Tag v3-nul-strings. Main suite 111/111.
The compiler's own sources (and gm2) assume NUL-terminated
strings: helpers like SymTab.Assign/Equal scan WHILE s[i] # CHR(0).
V3 stored [count, bytes] with no terminator and trapped when
indexing past the count, so those scans aborted. Minimal repro:
WHILE (i < HIGH(d)) AND (s[i] # CHR(0)) DO ... END; (* s[n] out of bounds *)
n has n data bytes plus one zero
byte at index n; indexed access is allowed for 0 .. n (the
terminator is readable/writable). LEN/HIGH still report n/n-1.ArrBodyItems emits z (n+1) for CHAR arrays; string
literals get a trailing b 0; ArrObjSize/HeapSize add 1; a
heap/local array's terminator is zeroed in InitHeap.Design's index handlers use ArrayHi+1 (fixed) or
OpenHiChar = count (open) for CHAR-element arrays (SymTab.IsCharArray).m2write/m2fputs/m2cstr derive length by scanning
(strnlen, bounded by the capacity); m2arg copies + NUL-terminates
and keeps the capacity in desc[0] (it no longer overwrites it
with the length — that destroyed fixed-buffer capacity).Strings: rewritten NUL-based (Length scans; Assign/
Concat/Delete/Append copy by scanned length bounded by
HIGH(dst) and NUL-terminate).NEW + inline-array-field repro now runs.FileIO + shim) and starts parsing.Reset (Parse → Reset) — the
next runtime bug to chase.desc[0] is now a capacity for arrays (and the literal length for
string literals); string length is derived by scanning. m2setlen is
effectively unused.
runtime/syslib/shim.c, stdlib/strings.mod,
compiler/src/{M2.atg,SymTab.def,SymTab.mod,QbeGen.def,QbeGen.mod,M2.lst}.