← board

Huge C struct: a field past 64 KB offset reads/writes the wrong slot

Repro

struct s { int f0; int f1; /* ... */ int f16999; };   /* 17000 int fields */
int main(void){ struct s b; b.f0 = 7; b.f16999 = 35; return b.f0 + b.f16999; }

ROOT CAUSE (2026-07-18) — NOT a 16-bit offset wrap

Original "16-bit offset wrap / >64 KB" suspicion was WRONG. Real cause: the C struct-body parser (CParseStructBody in cparser.inc) buffers a struct's fields in fixed local arrays bf* sized const MAX_BF = 256, and every buffer site was guarded if bfCount < MAX_BF then .... A struct with > 256 fields SILENTLY DROPS every field past #256 — they are never handed to AddUField, so FindUField can't find them and RecFieldOffset returns its default 0, aliasing them onto field 0. The running byte offset (and hence struct SIZE / frame layout) is computed separately and stays correct, which is why the size looked fine and only named access broke.

Corrected facts: the trigger is field COUNT > 256, not offset > 64 KB (a 3-field struct with a field at byte offset 70004 is fine; a 300-int struct — 1200 bytes — aliases f256..). Exactly index 256 is the cliff. C-only — Pascal records add fields directly per field (no bf* buffer) and a 400-field Pascal record was verified correct.

Fix (DONE)

Made the bf* buffers local dynamic arrays (array of, recursion-safe for nested/anon structs — a global buffer would be clobbered by the recursive sub-struct parse) pre-sized per struct to a field-count upper bound (endIdx - startIdx + 2: every buffered field owns ≥1 identifier token in the struct's token range, so the token span bounds the count). The < MAX_BF cap guards became < bfCap. Nested-function growth was tried first but hit the "too many params after capture" limit (17 captured arrays), so pre-sizing is used instead.

Acceptance — MET

Note

Not as rare as first thought: 256 fields is reachable in generated / large C structs, and the failure is SILENT (wrong value, no diagnostic).

Log