tools/sizelint + CLAUDE.md rule 13: gate hardcoded size literals
Drew's Hare-discipline framing: "no hardcoded size literals anywhere in the compiler." This session spent 32 commits sweeping after-the-fact and STILL kept introducing new bypass sites in our own structural work (A.5's tupleelemslot/fieldslotsize most recently). The cure is a gate that catches new violations at commit time, not a deeper sweep. tools/sizelint (sh+gawk): - Always-on: `.size = NN` / `->size = NN` / `prim(...,"name",NN,...)`. - Context-gated literals (NN(u64|i64) and `return NN`) in files or fns matching size|slot|elem|field|stride|paramfield|tinfo|primtype| slotsize|letemit|tagged. - Allow-list via `// sizelint-ok: <reason>` or `/* sizelint-ok: ... */`. - Comment strip happens after allow-list match so prose mentions of 16/24 stay quiet. Makefile: `test: all sizelint $(TESTS)` so the gate runs before any binary builds. CLAUDE.md rule 13 documents the discipline + escape hatch + optional pre-commit-hook symlink. Audit caught 3 real cstage bugs (cmd/wcc/check.c resolve_type:1002, 1079, 1531 hardcoded `tt->size = 16` / `= 32` for tagged-with-ptr and tagged-with-slice payloads — should read `8 + sub.size`). Fixed inline; behavioral no-op today (pt->size=16, st->size=24, sub.size=24 match the prior literals) but the SSoT seam carries forward through #1/#34/#65. 8 SSoT-seed allow-lists added (cstage type.c ty_str/ty_slice prim factories; wwstage primtypesize/tyslicesize; lib/ww/typ.ww tystr + slice fields + their main.combined.ww mirrors). One amalloc-overalloc allow-list at lib/ww/typ.ww:273 cites pending #36 (typed amalloc). #66 filed for extending the filter once #65 routes lib/bytes + lib/getopt's sizeof(slice) / sizeof(option) literals through SSoT — naive line-pattern extension would false-positive on 22+ ELF wire- format sites in dynout.ww. 131/131 + 994 + 995 + bootstrap green with `make sizelint` exit 0.
This commit is contained in:
@@ -6613,7 +6613,7 @@ export fn typesinit(c: *tctx, a: *arena) void = {
|
||||
c.tyuintptr= prim(a, tykind.TY_UINTPTR, "uintptr", 8u64, 8u64);
|
||||
c.tyf32 = prim(a, tykind.TY_F32, "f32", 4u64, 4u64);
|
||||
c.tyf64 = prim(a, tykind.TY_F64, "f64", 8u64, 8u64);
|
||||
c.tystr = prim(a, tykind.TY_STR, "str", 16u64, 8u64);
|
||||
c.tystr = prim(a, tykind.TY_STR, "str", 16u64, 8u64); // sizelint-ok: SSoT for tystr (#64)
|
||||
c.tyerr = prim(a, tykind.TY_ERR, "<err>", 0u64, 1u64);
|
||||
c.tynever = prim(a, tykind.TY_NEVER, "never", 0u64, 1u64);
|
||||
|
||||
@@ -6637,9 +6637,9 @@ export fn typeptr(a: *arena, sub: *tinfo) *tinfo = {
|
||||
export fn typeslice(a: *arena, sub: *tinfo) *tinfo = {
|
||||
let t: *tinfo = newtype(a, tykind.TY_SLICE);
|
||||
t.sub = sub;
|
||||
t.size = 24u64;
|
||||
t.size = 24u64; // sizelint-ok: SSoT for slice header (#64)
|
||||
t.align = 8u64;
|
||||
t.slotsize = 24u64;
|
||||
t.slotsize = 24u64; // sizelint-ok: SSoT for slice slotsize (#64)
|
||||
return t;
|
||||
};
|
||||
|
||||
@@ -6697,7 +6697,9 @@ export fn tinfocachelookup(c: *tctx, key: *node) *tinfo = {
|
||||
};
|
||||
|
||||
export fn tinfocachebind(c: *tctx, key: *node, val: *tinfo) void = {
|
||||
let e: *tinfocacheent = amalloc(c.a, 32u64): *tinfocacheent;
|
||||
// #36 (typed amalloc) — over-size the 24B tinfocacheent struct to
|
||||
// dodge the cstage amalloc<size silent corruption (selfhost/CLAUDE.md).
|
||||
let e: *tinfocacheent = amalloc(c.a, 32u64): *tinfocacheent; // sizelint-ok: amalloc over-size pending #36
|
||||
e.key = key;
|
||||
e.val = val;
|
||||
e.cnext = c.tinfocache;
|
||||
@@ -7757,14 +7759,14 @@ fn primtypesize(nm: str) i64 = {
|
||||
if (streq(nm, "i32") || streq(nm, "u32") || streq(nm, "f32") || streq(nm, "rune")) { return 4i64; };
|
||||
if (streq(nm, "i64") || streq(nm, "u64") || streq(nm, "f64")) { return 8i64; };
|
||||
if (streq(nm, "int") || streq(nm, "uint") || streq(nm, "uintptr")) { return 8i64; };
|
||||
if (streq(nm, "str")) { return 16i64; };
|
||||
if (streq(nm, "str")) { return 16i64; }; // sizelint-ok: SSoT for ty_str primtype (#64)
|
||||
return -1i64;
|
||||
};
|
||||
|
||||
// #43: SSoT for slice header size (ptr+len+cap = 24B today). Mirrors
|
||||
// cstage cmd/wcc/type.c:103 (ty_slice->size = 24). Bumping a slice's
|
||||
// header layout in #34 touches only this constant.
|
||||
fn tyslicesize() i64 = { return 24i64; };
|
||||
fn tyslicesize() i64 = { return 24i64; }; // sizelint-ok: SSoT for ty_slice header (#64)
|
||||
|
||||
// #42: AST-level layout helpers for the size(T)/align(T)/offset(e.f)
|
||||
// fold. Mirror cstage resolve_type's size/align computation
|
||||
|
||||
@@ -670,14 +670,14 @@ fn primtypesize(nm: str) i64 = {
|
||||
if (streq(nm, "i32") || streq(nm, "u32") || streq(nm, "f32") || streq(nm, "rune")) { return 4i64; };
|
||||
if (streq(nm, "i64") || streq(nm, "u64") || streq(nm, "f64")) { return 8i64; };
|
||||
if (streq(nm, "int") || streq(nm, "uint") || streq(nm, "uintptr")) { return 8i64; };
|
||||
if (streq(nm, "str")) { return 16i64; };
|
||||
if (streq(nm, "str")) { return 16i64; }; // sizelint-ok: SSoT for ty_str primtype (#64)
|
||||
return -1i64;
|
||||
};
|
||||
|
||||
// #43: SSoT for slice header size (ptr+len+cap = 24B today). Mirrors
|
||||
// cstage cmd/wcc/type.c:103 (ty_slice->size = 24). Bumping a slice's
|
||||
// header layout in #34 touches only this constant.
|
||||
fn tyslicesize() i64 = { return 24i64; };
|
||||
fn tyslicesize() i64 = { return 24i64; }; // sizelint-ok: SSoT for ty_slice header (#64)
|
||||
|
||||
// #42: AST-level layout helpers for the size(T)/align(T)/offset(e.f)
|
||||
// fold. Mirror cstage resolve_type's size/align computation
|
||||
|
||||
@@ -6613,7 +6613,7 @@ export fn typesinit(c: *tctx, a: *arena) void = {
|
||||
c.tyuintptr= prim(a, tykind.TY_UINTPTR, "uintptr", 8u64, 8u64);
|
||||
c.tyf32 = prim(a, tykind.TY_F32, "f32", 4u64, 4u64);
|
||||
c.tyf64 = prim(a, tykind.TY_F64, "f64", 8u64, 8u64);
|
||||
c.tystr = prim(a, tykind.TY_STR, "str", 16u64, 8u64);
|
||||
c.tystr = prim(a, tykind.TY_STR, "str", 16u64, 8u64); // sizelint-ok: SSoT for tystr (#64)
|
||||
c.tyerr = prim(a, tykind.TY_ERR, "<err>", 0u64, 1u64);
|
||||
c.tynever = prim(a, tykind.TY_NEVER, "never", 0u64, 1u64);
|
||||
|
||||
@@ -6637,9 +6637,9 @@ export fn typeptr(a: *arena, sub: *tinfo) *tinfo = {
|
||||
export fn typeslice(a: *arena, sub: *tinfo) *tinfo = {
|
||||
let t: *tinfo = newtype(a, tykind.TY_SLICE);
|
||||
t.sub = sub;
|
||||
t.size = 24u64;
|
||||
t.size = 24u64; // sizelint-ok: SSoT for slice header (#64)
|
||||
t.align = 8u64;
|
||||
t.slotsize = 24u64;
|
||||
t.slotsize = 24u64; // sizelint-ok: SSoT for slice slotsize (#64)
|
||||
return t;
|
||||
};
|
||||
|
||||
@@ -6697,7 +6697,9 @@ export fn tinfocachelookup(c: *tctx, key: *node) *tinfo = {
|
||||
};
|
||||
|
||||
export fn tinfocachebind(c: *tctx, key: *node, val: *tinfo) void = {
|
||||
let e: *tinfocacheent = amalloc(c.a, 32u64): *tinfocacheent;
|
||||
// #36 (typed amalloc) — over-size the 24B tinfocacheent struct to
|
||||
// dodge the cstage amalloc<size silent corruption (selfhost/CLAUDE.md).
|
||||
let e: *tinfocacheent = amalloc(c.a, 32u64): *tinfocacheent; // sizelint-ok: amalloc over-size pending #36
|
||||
e.key = key;
|
||||
e.val = val;
|
||||
e.cnext = c.tinfocache;
|
||||
@@ -7757,14 +7759,14 @@ fn primtypesize(nm: str) i64 = {
|
||||
if (streq(nm, "i32") || streq(nm, "u32") || streq(nm, "f32") || streq(nm, "rune")) { return 4i64; };
|
||||
if (streq(nm, "i64") || streq(nm, "u64") || streq(nm, "f64")) { return 8i64; };
|
||||
if (streq(nm, "int") || streq(nm, "uint") || streq(nm, "uintptr")) { return 8i64; };
|
||||
if (streq(nm, "str")) { return 16i64; };
|
||||
if (streq(nm, "str")) { return 16i64; }; // sizelint-ok: SSoT for ty_str primtype (#64)
|
||||
return -1i64;
|
||||
};
|
||||
|
||||
// #43: SSoT for slice header size (ptr+len+cap = 24B today). Mirrors
|
||||
// cstage cmd/wcc/type.c:103 (ty_slice->size = 24). Bumping a slice's
|
||||
// header layout in #34 touches only this constant.
|
||||
fn tyslicesize() i64 = { return 24i64; };
|
||||
fn tyslicesize() i64 = { return 24i64; }; // sizelint-ok: SSoT for ty_slice header (#64)
|
||||
|
||||
// #42: AST-level layout helpers for the size(T)/align(T)/offset(e.f)
|
||||
// fold. Mirror cstage resolve_type's size/align computation
|
||||
|
||||
Reference in New Issue
Block a user