selfhost/cmd/wcc/cgen: size amalloc slots to struct, not sizeof(str)@16
Nine sites used hardcoded byte counts sized for str=16. With str's in-memory size invariant about to grow under #1, the next-pointer or field write would land past the slot and corrupt the next bump allocation — selfhost/CLAUDE.md flags this exact pattern. Over-alloc by 8B is harmless under the bump allocator, so bumping the constants is correct at str=16 too. Sites: fnret, enumtype, modent (×4), ffi, strlit, enummember slot sizes; loopendbuf, loopcontbuf, yieldbuf LOOP_MAX strides. Latent bug found by str-size-hang-debug worker via PC trace on a str=24 probe: fnretlookup spun forever because the frnext write fell into the string heap, forming a cycle. Fix verified at str=16 (130/130 + 994/995) and probed at str=24 (994 still green; further graduation work tracked by #1).
This commit is contained in:
@@ -19854,7 +19854,8 @@ fn collectenums(c: *cgen, file: *node) void = {
|
||||
let body: *node = d.lhs;
|
||||
if (body != nil) {
|
||||
if (body.kind == nkind.N_TENUM) {
|
||||
let et: *enumtype = amalloc(c.a, 64u64): *enumtype;
|
||||
// #35: sizeof(enumtype) = 72 under str=24 ({str,str,*node,*enummember,*enumtype}); amalloc < struct corrupts the next slot.
|
||||
let et: *enumtype = amalloc(c.a, 80u64): *enumtype;
|
||||
et.ename = d.str;
|
||||
et.emod = d.nmod;
|
||||
et.storage = body.lhs;
|
||||
@@ -19873,7 +19874,8 @@ fn collectenums(c: *cgen, file: *node) void = {
|
||||
};
|
||||
};
|
||||
prev = val;
|
||||
let em: *enummember = amalloc(c.a, 32u64): *enummember;
|
||||
// #35: sizeof(enummember) = 40 under str=24 ({str,u64,*enummember}).
|
||||
let em: *enummember = amalloc(c.a, 48u64): *enummember;
|
||||
em.mname = m.str;
|
||||
em.mval = val;
|
||||
em.emnext = nil;
|
||||
@@ -20162,10 +20164,14 @@ fn cgeninit(c: *cgen, a: *arena) void = {
|
||||
// persist across cgfn calls within one file. cgfile resets them
|
||||
// at the start of each compilation unit.
|
||||
c.looptop = 0;
|
||||
c.loopendbuf = amalloc(a, (LOOP_MAX: u64) * 16u64): *str;
|
||||
c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 16u64): *str;
|
||||
// #35: per-slot stride is sizeof(str); the bare 16 is the str=16
|
||||
// width and undershoots under str=24, so indices past (LOOP_MAX*16)/24
|
||||
// = 10 would spill into the next amalloc. Bumped to 24/slot; +8/slot
|
||||
// over-alloc under str=16 is harmless under the bump arena.
|
||||
c.loopendbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
|
||||
c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
|
||||
c.yieldtop = 0;
|
||||
c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 16u64): *str;
|
||||
c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
|
||||
c.defertop = 0;
|
||||
c.deferbuf = amalloc(a, (DEFER_MAX: u64) * 8u64): **node;
|
||||
};
|
||||
@@ -20521,7 +20527,8 @@ fn internstrlit(c: *cgen, bytes: str) str = {
|
||||
let lab: str;
|
||||
lab.ptr = p;
|
||||
lab.len = total;
|
||||
let nw: *strlit = amalloc(c.a, 48u64): *strlit;
|
||||
// #35: sizeof(strlit) = 56 under str=24 ({str,str,*strlit}).
|
||||
let nw: *strlit = amalloc(c.a, 64u64): *strlit;
|
||||
nw.label = lab;
|
||||
nw.bytes = bytes;
|
||||
nw.slnext = c.strlits;
|
||||
@@ -21250,7 +21257,8 @@ fn collectfnrets(c: *cgen, file: *node) void = {
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == nkind.N_FNDECL) {
|
||||
let f: *fnret = amalloc(c.a, 64u64): *fnret;
|
||||
// #35: sizeof(fnret) = 72 under str=24 ({str,str,*node,*node,*fnret}); was the trigger that hung w6c_ww on the hangtest — frnext overflowed into the next amalloc, breaking fnretlookup's chain walk.
|
||||
let f: *fnret = amalloc(c.a, 80u64): *fnret;
|
||||
f.fname = d.str;
|
||||
f.fmod = d.nmod;
|
||||
f.rtype = d.lhs;
|
||||
@@ -21490,6 +21498,9 @@ type modent = struct {
|
||||
mnext: *modent,
|
||||
};
|
||||
|
||||
// #35: sizeof(modent) = 56 under str=24 ({str,str,*modent}); each
|
||||
// of the four amallocs below grew from 48 to 64 to keep mnext inside
|
||||
// the slot.
|
||||
fn collectmods(c: *cgen, file: *node) void = {
|
||||
c.mods = nil;
|
||||
if (file == nil) { return; };
|
||||
@@ -21513,7 +21524,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
||||
};
|
||||
if (!isffi) {
|
||||
if (!streq(d.str, "main")) {
|
||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||
let m: *modent = amalloc(c.a, 64u64): *modent;
|
||||
m.mname = d.str;
|
||||
m.nmod = d.nmod;
|
||||
m.mnext = c.mods;
|
||||
@@ -21525,7 +21536,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
||||
if (d.kind == nkind.N_DEF) {
|
||||
if (d.exported == 0) {
|
||||
if (d.nmod.len > 0) {
|
||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||
let m: *modent = amalloc(c.a, 64u64): *modent;
|
||||
m.mname = d.str;
|
||||
m.nmod = d.nmod;
|
||||
m.mnext = c.mods;
|
||||
@@ -21536,7 +21547,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
||||
if (d.kind == nkind.N_TYPEDECL) {
|
||||
if (d.exported == 0) {
|
||||
if (d.nmod.len > 0) {
|
||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||
let m: *modent = amalloc(c.a, 64u64): *modent;
|
||||
m.mname = d.str;
|
||||
m.nmod = d.nmod;
|
||||
m.mnext = c.mods;
|
||||
@@ -21547,7 +21558,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
||||
if (d.kind == nkind.N_LET) {
|
||||
if (d.exported == 0) {
|
||||
if (d.nmod.len > 0) {
|
||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||
let m: *modent = amalloc(c.a, 64u64): *modent;
|
||||
m.mname = d.str;
|
||||
m.nmod = d.nmod;
|
||||
m.mnext = c.mods;
|
||||
@@ -21653,7 +21664,8 @@ fn fficollect(c: *cgen, file: *node) void = {
|
||||
let symnode: *node = a.list;
|
||||
if (symnode != nil) {
|
||||
if (symnode.kind == nkind.N_STRLIT) {
|
||||
let f: *ffi = amalloc(c.a, 48u64): *ffi;
|
||||
// #35: sizeof(ffi) = 56 under str=24 ({str,str,*ffi}).
|
||||
let f: *ffi = amalloc(c.a, 64u64): *ffi;
|
||||
f.ident = d.str;
|
||||
f.symbol = symnode.str;
|
||||
f.fnext = c.ffis;
|
||||
|
||||
Reference in New Issue
Block a user