selfhost+cstage+test: module-scope mklabel labels (#13)

Latent silent miscompile: cstage + wwstage mklabel emitted
<fn>_<prefix>_<seq> with no module qualification, so two top-level
fns sharing a leaf across modules (e.g. bytes.index + strings.index)
emitted colliding labels into the same combined .s. Last assembler
symbol-definition won; JNE/JMP rel32 resolved to the wrong fn's body.

Repro (HEAD pre-fix): two_modules_same_leaf row in 750 — mod1.locate
+ mod2.locate sharing match-over-(u8|[]u8)+for shape. mod1.locate's
JMP misresolved into mod2's body, exit 10. Post-fix: exit 0.

Latent already at HEAD: bytes.contains_match_next_1 +
strings.contains_match_next_1 collide today but the corpus had no
forwarding path that surfaced it.

cmd/w6c/cgen.c + selfhost/cmd/wcc/cgen.ww mklabel: prepend
<module>. when c->cur_mod / c.curmod non-NULL/non-empty. Plan-9
convention extension: TEXT directive already uses <module>.<fnname>
(lex.c:18 a_isidcont accepts '.'); mklabel now mirrors that for
local labels. Both stages symmetric per rule 10. Fragment input
(no `package`) collapses to pre-fix shape — no cross-unit risk.

750_mklabel_modscoped: table-driven 3 rows x 2 stages = 6 sub-cases
(two_modules_same_leaf, bytes_strings_contains, same_module_same_leaf
non-regression). All required substrings asserted via grep + runtime
rc check.

make test 124/124; ww2==ww3==ww4 byte-id holds via 995_self_rebuild.
@-prefix slot keys (cg_tagbase, cg_tagscr, @retscr) are orthogonal
(local_alloc keys, not mklabel emissions).
This commit is contained in:
2026-05-19 03:39:42 +09:00
parent cbf10427df
commit d2c64bc962
6 changed files with 380 additions and 11 deletions

View File

@@ -1028,8 +1028,12 @@ abranch(const char *s)
static char *
mklabel(Cg *c, const char *prefix)
{
return aprintf(c->a, "%s_%s_%d", c->fnname ? c->fnname : "_", prefix,
c->labelseq++);
/* Module-qualified to avoid cross-module same-leaf collisions
* (task #13). w6a accepts '.' in label-cont (lex.c:18). */
return aprintf(c->a, "%s%s%s_%s_%d",
c->cur_mod ? c->cur_mod : "",
c->cur_mod ? "." : "",
c->fnname ? c->fnname : "_", prefix, c->labelseq++);
}
static void