w6c+selfhost+lib: zero-init multi-word no-rhs lets
`let x: T;` for str/slice/tuple/struct/tagged previously left the slot holding stack garbage — only 8B-primitive slots were zeroed. This bit `expectbindname` in lib/ww/parse: `let empty: str; *into = empty;` was copying stack bytes (often a recently-vacated str descriptor) into the caller's `id`, so wwstage emitted `_` discard nodes carrying random text instead of "". Both stages now zero the full slot on no-rhs lets; `[N]T` arrays keep the per-index-write contract. Also tightens the two known buggy sites: parse.ww `expectbindname` writes `*into = ""` directly, expr.ww `_` primary returns the bare newnode (amalloc already zeroes).
This commit is contained in:
@@ -4158,8 +4158,31 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
}
|
||||
} else if (sz == 8) {
|
||||
ins2(c, A_MOVQ, aimm(0), amem(D_BP, off));
|
||||
} else if (!n->rhs && sz > 8 && lu && lu->kind != TY_ARRAY) {
|
||||
/* `let x: T;` with no rhs for a multi-word composite
|
||||
* (str/slice/tuple/struct/tagged). Zero the slot so
|
||||
* reads after the bare let see {0...} rather than
|
||||
* whatever the stack already held. Arrays keep the
|
||||
* per-index-write contract — leave them uninit. */
|
||||
ins2(c, A_XORQ, areg(D_AX), areg(D_AX));
|
||||
int zi = 0;
|
||||
while (zi + 8 <= sz) {
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BP, off + zi));
|
||||
zi += 8;
|
||||
}
|
||||
while (zi + 4 <= sz) {
|
||||
ins2(c, A_MOVL, areg(D_AX),
|
||||
amem(D_BP, off + zi));
|
||||
zi += 4;
|
||||
}
|
||||
while (zi < sz) {
|
||||
ins2(c, A_MOVB, areg(D_AX),
|
||||
amem(D_BP, off + zi));
|
||||
zi += 1;
|
||||
}
|
||||
}
|
||||
/* arrays/slices left uninitialised — caller writes via index */
|
||||
/* arrays left uninitialised — caller writes via index */
|
||||
break;
|
||||
}
|
||||
case N_RETURN:
|
||||
|
||||
Reference in New Issue
Block a user