w6c_ww/cgen: uniform tinfo esz for global str/slice addr-of + store (fix #11)
Three sibling arms of the #10 global-str/slice INDEX miscompile (23670d7,
the READ path) shared the identical N_TARRAY/N_TPTR tnode-KIND whitelist in
their global-ident resolution arm and were still LIVE and silently cs!=ww:
- cgun `&s[1]` / `&g[1]` (cgenexpr.ww N_INDEX addr-of) — a global str
(tnode N_TNAME) / slice (N_TSLICE) matched neither arm, so esz stayed at
the default 8 and the base fell to the complex-base fallback: a wide
{ptr,len,cap} header + 8-byte stride instead of MOVQ name(SB) (.ptr) +
ADDQ.
- cgassign `g[1] = v` store AND `g[1] OP= v` compound (two arms) — same
whitelist; a global slice store emitted a full-word MOVQ at an 8-byte
stride: an 8-BYTE OUT-OF-BOUNDS WRITE past a 1-byte element (memory
corruption) instead of MOVB at .ptr+1.
cstage (cmd/w6c/cgen.c) is the runtime-correct reference and was already
uniform across all three: esz off idx_eff(base->type)->sub->size and the
base load gated by is_arr (TY_ARRAY -> LEAQ name(SB), every other -> MOVQ
name(SB), since a str/slice's .ptr IS the symbol's first word). Align the
wwstage UP to that, mirroring the just-landed cgindex template (#10): resolve
esz via elemsizeofc with no kind gate, dispatch the base by N_TARRAY ? LEAQ :
MOVQ name(SB). The store/compound arms also resolve elemtn exactly like their
local branch (element node for ARRAY/SLICE/PTR; nil for str so tnodestoreop
picks MOVB) so a global []str store routes to the 3-word header store and the
compound arm's str/slice hard-error still fires.
Close-by-construction: the global element base/stride is now computed off the
resolved type at every wwstage index site — read (cgindex, #10), addr-of
(cgun), store + compound (cgassign) — with no remaining tnode-kind whitelist.
cgslice/cgbaselen already resolved via elemsizeofc.
803_globalidx_run extends from 9 to 18 rows: global str/slice addr-of (read
back through the pointer), global slice store AND compound store `g[i] OP= v`
(the distinct third fixed arm, with adjacent-element addends as the OOB-write
guard on both), a WIDTH>1 signed variant of each (esz=4 stride/store-width pin),
and local addr-of/store regression pins. Runtime (cstage build+run) + cs==ww
byte-id per row. combined.ww embeds (w6c + wwdump) regenerate.
This commit is contained in:
@@ -23170,17 +23170,26 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
if (tn.kind == nkind.N_TARRAY) { isarr = true; };
|
||||
};
|
||||
} else {
|
||||
// #11: addr-of twin of the #10 cgindex read
|
||||
// fix. Dispatch esz + base load off the
|
||||
// global's RESOLVED type, NOT an N_TARRAY/
|
||||
// N_TPTR kind whitelist — a global str (tnode
|
||||
// N_TNAME) / slice (N_TSLICE) matched NEITHER
|
||||
// old arm, so esz stayed at the default 8 and
|
||||
// the base fell to the complex-base fallback,
|
||||
// yielding a wide-stride &s[i]. cstage's
|
||||
// TK_AMP N_INDEX (cmd/w6c/cgen.c) is uniform:
|
||||
// esz=bu->sub->size, base is_arr?LEAQ:MOVQ
|
||||
// name(SB) (a str/slice's .ptr IS the symbol's
|
||||
// first word). Align UP, mirroring cgindex.
|
||||
let tn: *node = letvartnode(c, base.str);
|
||||
if (tn != nil) {
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -24797,19 +24806,34 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (bk == nkind.N_TPTR) { elemtn = btn.lhs; };
|
||||
};
|
||||
} else {
|
||||
// #11: store/compound twin of the #10 cgindex
|
||||
// read fix. A global str/slice element store hit
|
||||
// the same kind whitelist — N_TNAME (str) /
|
||||
// N_TSLICE matched NEITHER arm, so esz stayed 8
|
||||
// and the store emitted a full-word MOVQ — an
|
||||
// 8-byte OUT-OF-BOUNDS write past a 1-byte
|
||||
// element — instead of MOVB. cstage
|
||||
// (cmd/w6c/cgen.c N_INDEX store) dispatches esz
|
||||
// off idx_eff->sub->size + the elem-kind flags
|
||||
// off eff->sub uniformly, base is_arr?LEAQ:MOVQ
|
||||
// name(SB). Align UP and resolve elemtn exactly
|
||||
// like the local branch above (element node for
|
||||
// ARRAY/SLICE/PTR; nil for str so tnodestoreop
|
||||
// picks MOVB on the store arm, and the compound
|
||||
// arm's str/slice hard-error still fires on a
|
||||
// []str element).
|
||||
let tn: *node = letvartnode(c, bn);
|
||||
if (tn != nil) {
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
let bk: nkind = tn.kind;
|
||||
if (bk == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
if (bk == nkind.N_TSLICE) { elemtn = tn.lhs; };
|
||||
if (bk == nkind.N_TPTR) { elemtn = tn.lhs; };
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -25229,19 +25253,34 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (bk == nkind.N_TPTR) { elemtn = btn.lhs; };
|
||||
};
|
||||
} else {
|
||||
// #11: store/compound twin of the #10 cgindex
|
||||
// read fix. A global str/slice element store hit
|
||||
// the same kind whitelist — N_TNAME (str) /
|
||||
// N_TSLICE matched NEITHER arm, so esz stayed 8
|
||||
// and the store emitted a full-word MOVQ — an
|
||||
// 8-byte OUT-OF-BOUNDS write past a 1-byte
|
||||
// element — instead of MOVB. cstage
|
||||
// (cmd/w6c/cgen.c N_INDEX store) dispatches esz
|
||||
// off idx_eff->sub->size + the elem-kind flags
|
||||
// off eff->sub uniformly, base is_arr?LEAQ:MOVQ
|
||||
// name(SB). Align UP and resolve elemtn exactly
|
||||
// like the local branch above (element node for
|
||||
// ARRAY/SLICE/PTR; nil for str so tnodestoreop
|
||||
// picks MOVB on the store arm, and the compound
|
||||
// arm's str/slice hard-error still fires on a
|
||||
// []str element).
|
||||
let tn: *node = letvartnode(c, bn);
|
||||
if (tn != nil) {
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
let bk: nkind = tn.kind;
|
||||
if (bk == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
if (bk == nkind.N_TSLICE) { elemtn = tn.lhs; };
|
||||
if (bk == nkind.N_TPTR) { elemtn = tn.lhs; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3446,17 +3446,26 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
if (tn.kind == nkind.N_TARRAY) { isarr = true; };
|
||||
};
|
||||
} else {
|
||||
// #11: addr-of twin of the #10 cgindex read
|
||||
// fix. Dispatch esz + base load off the
|
||||
// global's RESOLVED type, NOT an N_TARRAY/
|
||||
// N_TPTR kind whitelist — a global str (tnode
|
||||
// N_TNAME) / slice (N_TSLICE) matched NEITHER
|
||||
// old arm, so esz stayed at the default 8 and
|
||||
// the base fell to the complex-base fallback,
|
||||
// yielding a wide-stride &s[i]. cstage's
|
||||
// TK_AMP N_INDEX (cmd/w6c/cgen.c) is uniform:
|
||||
// esz=bu->sub->size, base is_arr?LEAQ:MOVQ
|
||||
// name(SB) (a str/slice's .ptr IS the symbol's
|
||||
// first word). Align UP, mirroring cgindex.
|
||||
let tn: *node = letvartnode(c, base.str);
|
||||
if (tn != nil) {
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -5073,19 +5082,34 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (bk == nkind.N_TPTR) { elemtn = btn.lhs; };
|
||||
};
|
||||
} else {
|
||||
// #11: store/compound twin of the #10 cgindex
|
||||
// read fix. A global str/slice element store hit
|
||||
// the same kind whitelist — N_TNAME (str) /
|
||||
// N_TSLICE matched NEITHER arm, so esz stayed 8
|
||||
// and the store emitted a full-word MOVQ — an
|
||||
// 8-byte OUT-OF-BOUNDS write past a 1-byte
|
||||
// element — instead of MOVB. cstage
|
||||
// (cmd/w6c/cgen.c N_INDEX store) dispatches esz
|
||||
// off idx_eff->sub->size + the elem-kind flags
|
||||
// off eff->sub uniformly, base is_arr?LEAQ:MOVQ
|
||||
// name(SB). Align UP and resolve elemtn exactly
|
||||
// like the local branch above (element node for
|
||||
// ARRAY/SLICE/PTR; nil for str so tnodestoreop
|
||||
// picks MOVB on the store arm, and the compound
|
||||
// arm's str/slice hard-error still fires on a
|
||||
// []str element).
|
||||
let tn: *node = letvartnode(c, bn);
|
||||
if (tn != nil) {
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
let bk: nkind = tn.kind;
|
||||
if (bk == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
if (bk == nkind.N_TSLICE) { elemtn = tn.lhs; };
|
||||
if (bk == nkind.N_TPTR) { elemtn = tn.lhs; };
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -5505,19 +5529,34 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (bk == nkind.N_TPTR) { elemtn = btn.lhs; };
|
||||
};
|
||||
} else {
|
||||
// #11: store/compound twin of the #10 cgindex
|
||||
// read fix. A global str/slice element store hit
|
||||
// the same kind whitelist — N_TNAME (str) /
|
||||
// N_TSLICE matched NEITHER arm, so esz stayed 8
|
||||
// and the store emitted a full-word MOVQ — an
|
||||
// 8-byte OUT-OF-BOUNDS write past a 1-byte
|
||||
// element — instead of MOVB. cstage
|
||||
// (cmd/w6c/cgen.c N_INDEX store) dispatches esz
|
||||
// off idx_eff->sub->size + the elem-kind flags
|
||||
// off eff->sub uniformly, base is_arr?LEAQ:MOVQ
|
||||
// name(SB). Align UP and resolve elemtn exactly
|
||||
// like the local branch above (element node for
|
||||
// ARRAY/SLICE/PTR; nil for str so tnodestoreop
|
||||
// picks MOVB on the store arm, and the compound
|
||||
// arm's str/slice hard-error still fires on a
|
||||
// []str element).
|
||||
let tn: *node = letvartnode(c, bn);
|
||||
if (tn != nil) {
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
let bk: nkind = tn.kind;
|
||||
if (bk == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
if (bk == nkind.N_TSLICE) { elemtn = tn.lhs; };
|
||||
if (bk == nkind.N_TPTR) { elemtn = tn.lhs; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -23170,17 +23170,26 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
if (tn.kind == nkind.N_TARRAY) { isarr = true; };
|
||||
};
|
||||
} else {
|
||||
// #11: addr-of twin of the #10 cgindex read
|
||||
// fix. Dispatch esz + base load off the
|
||||
// global's RESOLVED type, NOT an N_TARRAY/
|
||||
// N_TPTR kind whitelist — a global str (tnode
|
||||
// N_TNAME) / slice (N_TSLICE) matched NEITHER
|
||||
// old arm, so esz stayed at the default 8 and
|
||||
// the base fell to the complex-base fallback,
|
||||
// yielding a wide-stride &s[i]. cstage's
|
||||
// TK_AMP N_INDEX (cmd/w6c/cgen.c) is uniform:
|
||||
// esz=bu->sub->size, base is_arr?LEAQ:MOVQ
|
||||
// name(SB) (a str/slice's .ptr IS the symbol's
|
||||
// first word). Align UP, mirroring cgindex.
|
||||
let tn: *node = letvartnode(c, base.str);
|
||||
if (tn != nil) {
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = base.str;
|
||||
esz = elemsizeofc(c, tn);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -24797,19 +24806,34 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (bk == nkind.N_TPTR) { elemtn = btn.lhs; };
|
||||
};
|
||||
} else {
|
||||
// #11: store/compound twin of the #10 cgindex
|
||||
// read fix. A global str/slice element store hit
|
||||
// the same kind whitelist — N_TNAME (str) /
|
||||
// N_TSLICE matched NEITHER arm, so esz stayed 8
|
||||
// and the store emitted a full-word MOVQ — an
|
||||
// 8-byte OUT-OF-BOUNDS write past a 1-byte
|
||||
// element — instead of MOVB. cstage
|
||||
// (cmd/w6c/cgen.c N_INDEX store) dispatches esz
|
||||
// off idx_eff->sub->size + the elem-kind flags
|
||||
// off eff->sub uniformly, base is_arr?LEAQ:MOVQ
|
||||
// name(SB). Align UP and resolve elemtn exactly
|
||||
// like the local branch above (element node for
|
||||
// ARRAY/SLICE/PTR; nil for str so tnodestoreop
|
||||
// picks MOVB on the store arm, and the compound
|
||||
// arm's str/slice hard-error still fires on a
|
||||
// []str element).
|
||||
let tn: *node = letvartnode(c, bn);
|
||||
if (tn != nil) {
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
let bk: nkind = tn.kind;
|
||||
if (bk == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
if (bk == nkind.N_TSLICE) { elemtn = tn.lhs; };
|
||||
if (bk == nkind.N_TPTR) { elemtn = tn.lhs; };
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -25229,19 +25253,34 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (bk == nkind.N_TPTR) { elemtn = btn.lhs; };
|
||||
};
|
||||
} else {
|
||||
// #11: store/compound twin of the #10 cgindex
|
||||
// read fix. A global str/slice element store hit
|
||||
// the same kind whitelist — N_TNAME (str) /
|
||||
// N_TSLICE matched NEITHER arm, so esz stayed 8
|
||||
// and the store emitted a full-word MOVQ — an
|
||||
// 8-byte OUT-OF-BOUNDS write past a 1-byte
|
||||
// element — instead of MOVB. cstage
|
||||
// (cmd/w6c/cgen.c N_INDEX store) dispatches esz
|
||||
// off idx_eff->sub->size + the elem-kind flags
|
||||
// off eff->sub uniformly, base is_arr?LEAQ:MOVQ
|
||||
// name(SB). Align UP and resolve elemtn exactly
|
||||
// like the local branch above (element node for
|
||||
// ARRAY/SLICE/PTR; nil for str so tnodestoreop
|
||||
// picks MOVB on the store arm, and the compound
|
||||
// arm's str/slice hard-error still fires on a
|
||||
// []str element).
|
||||
let tn: *node = letvartnode(c, bn);
|
||||
if (tn != nil) {
|
||||
if (tn.kind == nkind.N_TARRAY) {
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
let bk: nkind = tn.kind;
|
||||
if (bk == nkind.N_TARRAY) {
|
||||
isglobalarr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
};
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
} else {
|
||||
isglobalptr = true;
|
||||
globalname = bn;
|
||||
esz = elemsizeofc(c, tn);
|
||||
elemtn = tn.lhs;
|
||||
if (bk == nkind.N_TSLICE) { elemtn = tn.lhs; };
|
||||
if (bk == nkind.N_TPTR) { elemtn = tn.lhs; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user