# NUL-terminated string model (self-hosting unblocker) Tag `v3-nul-strings`. Main suite 111/111. ## Why 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: ```modula2 WHILE (i < HIGH(d)) AND (s[i] # CHR(0)) DO ... END; (* s[n] out of bounds *) ``` ## Change: every CHAR array reserves a terminator slot - **Model**: a CHAR array of count `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`. - **Emission**: `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`. - **Bounds**: `Design`'s index handlers use `ArrayHi+1` (fixed) or `OpenHiChar` = count (open) for CHAR-element arrays (`SymTab.IsCharArray`). - **Shim**: `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). - **stdlib `Strings`**: rewritten NUL-based (`Length` scans; `Assign`/ `Concat`/`Delete`/`Append` copy by scanned length bounded by `HIGH(dst)` and NUL-terminate). ## Result - Suite 111/111; the small `NEW` + inline-array-field repro now runs. - The **self-compiled compiler now runs**: it opens its input (self- hosted `FileIO` + shim) and starts parsing. - It then segfaults in the scanner's `Reset` (`Parse → Reset`) — the next runtime bug to chase. ## Note `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. ## Files `runtime/syslib/shim.c`, `stdlib/strings.mod`, `compiler/src/{M2.atg,SymTab.def,SymTab.mod,QbeGen.def,QbeGen.mod,M2.lst}`.