From be363f445102a97f60583bc92150c1b130a55b51 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 21 May 2026 17:05:58 +0900 Subject: [PATCH] test/wcc/995_self_rebuild: stage source in workdir to avoid main.s race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ww_ww build writes its intermediates (.combined.ww/.s/.o/binary) next to the source path. When 995 invoked `ww_ww build /abs/path/ selfhost/cmd/wwdump/main.ww` in parallel with 991/992/994 (which read selfhost/cmd//main.s as a fixture), the build mid-wrote main.s and the fixture-reading test saw a partial 520B view of the 1.4MB file → "C 1422712 vs ww 520 bytes" assembler-byte-diff fail. The race was latent pre-31594e4 too: parallel test/run + serial 995 always finished 995 last (3min wall), so 991 was already done by the time 995's wwdump build wrote main.s. Internal-parallel 995 finishes in 1m47, opening the window. Fix: cp the source to /build.ww before invoking ww_ww, build from build.ww. Driver writes intermediates as build.{combined.ww, s,o} and binary `build` in workdir; canonical selfhost/cmd// main.* are never touched by 995. Imports still resolve via -I, but those paths are read-only fixtures. Verified 3 consecutive `make test` runs 132/132 (4:18, 3:22, 3:16). --- test/wcc/995_self_rebuild.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/test/wcc/995_self_rebuild.c b/test/wcc/995_self_rebuild.c index 592f5ab6..ac0f072a 100644 --- a/test/wcc/995_self_rebuild.c +++ b/test/wcc/995_self_rebuild.c @@ -82,15 +82,21 @@ struct buildjob { /* Fork a child that runs the `ww_ww build` for this tool. The child * inherits no concurrent siblings — system() spawns a fresh /bin/sh -c. * stderr lands in /build.err so concurrent builds don't merge - * their diagnostics. */ + * their diagnostics. + * + * The source is staged at /build.ww before the build so the + * driver writes its .combined.ww/.s/.o intermediates inside workdir — + * not next to the canonical selfhost/cmd//main.ww, where 991/992/ + * 994 read main.s as a fixture. Without staging, parallel test/run sees + * 991 race against 995's wwdump-build mid-write of main.s. */ static int spawn_build(const char *bin, const char *cwd, struct buildjob *j) { snprintf(j->workdir, sizeof j->workdir, "/tmp/wwsr_%d_%s", getpid(), j->tool); - char setup[256]; - snprintf(setup, sizeof setup, "rm -rf %s && mkdir -p %s", - j->workdir, j->workdir); + char setup[4096]; + snprintf(setup, sizeof setup, "rm -rf %s && mkdir -p %s && cp %s/%s %s/build.ww", + j->workdir, j->workdir, cwd, j->src_rel, j->workdir); if (runwait(setup) != 0) return -1; char cmd[4096]; @@ -98,15 +104,15 @@ spawn_build(const char *bin, const char *cwd, struct buildjob *j) snprintf(cmd, sizeof cmd, "cd %s && timeout 180 %s/ww_ww build -I %s/%s " "-I %s/lib/ww -I %s/lib/ww/lex -I %s/lib/ww/parse " - "-I %s/selfhost/cmd/wcc %s/%s >/dev/null 2>%s/build.err", + "-I %s/selfhost/cmd/wcc build.ww >/dev/null 2>%s/build.err", j->workdir, bin, cwd, j->inc_local, - cwd, cwd, cwd, cwd, cwd, j->src_rel, j->workdir); + cwd, cwd, cwd, cwd, j->workdir); } else { snprintf(cmd, sizeof cmd, "cd %s && timeout 180 %s/ww_ww build " "-I %s/lib/ww -I %s/lib/ww/lex -I %s/lib/ww/parse " - "-I %s/selfhost/cmd/wcc %s/%s >/dev/null 2>%s/build.err", - j->workdir, bin, cwd, cwd, cwd, cwd, cwd, j->src_rel, j->workdir); + "-I %s/selfhost/cmd/wcc build.ww >/dev/null 2>%s/build.err", + j->workdir, bin, cwd, cwd, cwd, cwd, j->workdir); } pid_t p = fork(); @@ -146,7 +152,7 @@ collect_build(const char *bin, struct buildjob *j) rc = -1; } else { char rebuilt[256], canonical[256]; - snprintf(rebuilt, sizeof rebuilt, "%s/main", j->workdir); + snprintf(rebuilt, sizeof rebuilt, "%s/build", j->workdir); snprintf(canonical, sizeof canonical, "%s/%s_ww", bin, j->tool); rc = slurp_eq(rebuilt, canonical); if (rc != 0) {