w6c: fall to the place resolver for indexed dot-chain aggregate sources
The dot-chain SOURCE-address walkers (cg_dotchain_addr / dotchainaddr) deliberately have no index hop — their AX-clean spill contract serves the chained dotbase arm — so an aggregate copy from elem[k].field (N_DOT over N_INDEX) fell out of the walk. Every aggarg_srcaddr consumer loud-stopped (arg push #271, aggregate return #272, field assign, structlit fill, ident reassign) EXCEPT the indexed element-store arm, which left the walker's result UNCHECKED and copied through a stale SI — a silent both-stage miscompile (out[j] = hs[k].result read garbage). Task #6. Both stages, two twin edits each: the aggarg_srcaddr N_DOT arm falls back to cgplaceaddr (the C4/#40 place resolver, emission-free-on- failure so the fallback starts clean), and the indexed store site checks the walker before the same fallback. Still loud (filed follow-ups): auto-deref pointer-to-array indexed bases (hs: *[4]T; hs[k].field — cgplaceaddr's index arm takes no deref hop; the explicit (*hs)[k].field form works), and the bare N_INDEX slice-element aggregate source.
This commit is contained in:
@@ -2079,6 +2079,7 @@ cg_base_cap(Cg *c, Node *base, Type *bu, Local *locals, int dst)
|
||||
|
||||
static void cgexpr(Cg*, Node*, Local*);
|
||||
static void cgstmt(Cg*, Node*, Local**, int*);
|
||||
static int cgplaceaddr(Cg*, Node*, int, Local*);
|
||||
static void cg_widen_tagged_push(Cg*, Local**, Type*, Node*, int);
|
||||
static void cg_widen_tagged_store(Cg*, Local**, Type*, Node*, int, int, int);
|
||||
static void cg_widen_tag_remap(Cg*, Type*, Type*, int);
|
||||
@@ -2278,8 +2279,16 @@ aggarg_srcaddr(Cg *c, Node *src, int dst, Local *locals)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (src->kind == N_DOT)
|
||||
return cg_dotchain_addr(c, src, dst, locals);
|
||||
if (src->kind == N_DOT) {
|
||||
if (cg_dotchain_addr(c, src, dst, locals))
|
||||
return 1;
|
||||
/* task #6: an N_INDEX link inside the dot chain
|
||||
* (handles[k].result) — the chain walker has no index hop
|
||||
* (AX-clean spill contract for cg_dotbase_addr); the place
|
||||
* resolver is the C4/#40 fallback, and the failed walk is
|
||||
* emission-free so the fallback starts clean. */
|
||||
return cgplaceaddr(c, src, dst, locals);
|
||||
}
|
||||
if (src->kind == N_INDEX) {
|
||||
Node *base = src->lhs;
|
||||
Node *idx = src->rhs;
|
||||
@@ -7373,11 +7382,21 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, n->rhs->str),
|
||||
areg(D_SI));
|
||||
} else if (n->rhs->kind == N_DOT) {
|
||||
cg_dotchain_addr(c, n->rhs, D_SI, locals);
|
||||
} else if (!cgplaceaddr(c, n->rhs, D_SI, locals)) {
|
||||
fatal("indexed aggregate assignment source "
|
||||
"unresolved");
|
||||
} else {
|
||||
/* task #6: the chain walker declines an
|
||||
* N_INDEX link (emission-free) — its
|
||||
* result was unchecked here, so the copy
|
||||
* below read through a stale SI. Fall to
|
||||
* the generic place resolver. */
|
||||
int dok = 0;
|
||||
if (n->rhs->kind == N_DOT)
|
||||
dok = cg_dotchain_addr(c,
|
||||
n->rhs, D_SI, locals);
|
||||
if (!dok && !cgplaceaddr(c, n->rhs,
|
||||
D_SI, locals))
|
||||
fatal("indexed aggregate "
|
||||
"assignment source "
|
||||
"unresolved");
|
||||
}
|
||||
ins1(c, A_POPQ, areg(D_BX)); /* dest */
|
||||
int k = 0;
|
||||
|
||||
Reference in New Issue
Block a user