diff --git a/test/wcc/950_selfcheck.c b/test/wcc/950_selfcheck.c index 300166fb..f60ec55c 100644 --- a/test/wcc/950_selfcheck.c +++ b/test/wcc/950_selfcheck.c @@ -9,32 +9,48 @@ #include #include #include +#include #include #include #include "wwtestpkg.h" static int -runcap(const char *cmd, char **outerr, size_t *outlen) +runcap(const char *cmd, char **outerr, size_t *outlen, int *outrc) { char tmp[256]; snprintf(tmp, sizeof tmp, "/tmp/wwd_sc_%d", getpid()); char full[2048]; snprintf(full, sizeof full, "%s 2>%s 1>/dev/null", cmd, tmp); + int ret = -1; + FILE *f = NULL; + char *b = NULL; + long n = 0; int rc = system(full); - FILE *f = fopen(tmp, "rb"); - if (!f) { unlink(tmp); return -1; } - fseek(f, 0, SEEK_END); - long n = ftell(f); - fseek(f, 0, SEEK_SET); - char *b = malloc((size_t)n + 1); - if (!b) { fclose(f); unlink(tmp); return -1; } - if (fread(b, 1, (size_t)n, f) != (size_t)n) { - free(b); fclose(f); unlink(tmp); return -1; - } + if (rc == -1 || !WIFEXITED(rc)) goto cleanup; + f = fopen(tmp, "rb"); + if (!f) { perror(tmp); goto cleanup; } + if (fseek(f, 0, SEEK_END) != 0) { perror(tmp); goto cleanup; } + n = ftell(f); + if (n < 0) { perror(tmp); goto cleanup; } + if (fseek(f, 0, SEEK_SET) != 0) { perror(tmp); goto cleanup; } + b = malloc((size_t)n + 1); + if (!b) goto cleanup; + if (fread(b, 1, (size_t)n, f) != (size_t)n) goto cleanup; b[n] = '\0'; - fclose(f); unlink(tmp); - *outerr = b; *outlen = (size_t)n; - (void)rc; + ret = 0; + +cleanup: + /* the shell may never have created tmp (fork failure). */ + if (f) fclose(f); + if (unlink(tmp) != 0 && errno != ENOENT) { + perror(tmp); + ret = -1; + } + if (ret != 0) { + free(b); + return -1; + } + *outerr = b; *outlen = (size_t)n; *outrc = WEXITSTATUS(rc); return 0; } @@ -44,7 +60,15 @@ writefile(const char *path, const char *src) FILE *f = fopen(path, "wb"); if (!f) return -1; wwtest_fputs(src, f); - fclose(f); + /* wwtest_fputs is void; ferror + fclose's flush surface a short + * write (ENOSPC) that would otherwise compile a truncated fixture. */ + int werr = ferror(f) != 0; + if (fclose(f) != 0 || werr) { + perror(path); + if (unlink(path) != 0 && errno != ENOENT) + perror(path); + return -1; + } return 0; } @@ -168,9 +192,15 @@ main(void) if (!bin) bin = "out/bin"; char wwdump[2048]; snprintf(wwdump, sizeof wwdump, "%s/wwdump_ww", bin); + /* bootstrap gate: a missing selfhost checker must FAIL, not skip. */ + if (access(wwdump, X_OK) != 0) { + fprintf(stderr, "selfcheck: %s missing or not executable\n", + wwdump); + return 1; + } int n = sizeof rows / sizeof rows[0]; - int fail = 0; + int fail = 0, cleanfail = 0; for (int i = 0; i < n; i++) { char path[64]; snprintf(path, sizeof path, "/tmp/wwd_sc_%d_%d.ww", getpid(), i); @@ -178,7 +208,12 @@ main(void) char cmd[2048]; snprintf(cmd, sizeof cmd, "%s -r %s", wwdump, path); char *err = NULL; size_t elen = 0; - runcap(cmd, &err, &elen); + int xrc = -1; + if (runcap(cmd, &err, &elen, &xrc) != 0) { + fprintf(stderr, "row %d: capture failed\n", i); + fail++; + goto rowcleanup; + } const char *want = rows[i].expect; int got_match = (err && want && strstr(err, want) != NULL); int expected_no_err = (want == NULL); @@ -201,7 +236,9 @@ main(void) err_present = err_present || (err && strstr(err, "return: not assignable") != NULL); int ok; - if (expected_no_err) ok = !err_present; + /* a checker that dies with empty stderr must not pass a + * no-error row: require a clean exit too. */ + if (expected_no_err) ok = !err_present && xrc == 0; else ok = got_match; if (!ok) { fprintf(stderr, @@ -209,13 +246,21 @@ main(void) i, want ? want : "(no error)", err ? err : "(empty)"); fail++; } +rowcleanup: free(err); - unlink(path); + if (unlink(path) != 0 && errno != ENOENT) { + perror(path); + cleanfail = 1; + } } if (fail) { fprintf(stderr, "%d/%d selfcheck rows failed\n", fail, n); return 1; } + if (cleanfail) { + fprintf(stderr, "selfcheck: cleanup failed\n"); + return 1; + } printf("selfcheck: %d/%d ok\n", n, n); return 0; } diff --git a/test/wcc/991_w6a_ww.c b/test/wcc/991_w6a_ww.c index 0b34e0b3..09a42bd4 100644 --- a/test/wcc/991_w6a_ww.c +++ b/test/wcc/991_w6a_ww.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -63,34 +64,47 @@ static int diff_one(const char *bin, const char *src) { char co[64], wo[64], cmd[2048]; + char *bc = NULL, *bw = NULL; + size_t nc = 0, nw = 0; + int rc = -1; snprintf(co, sizeof co, "/tmp/wwa_%d_c.o", getpid()); snprintf(wo, sizeof wo, "/tmp/wwa_%d_w.o", getpid()); snprintf(cmd, sizeof cmd, "timeout 180 %s/w6a -o %s %s 2>/dev/null", bin, co, src); if (runwait(cmd) != 0) { fprintf(stderr, "w6a_ww FAIL: C w6a errored on %s\n", src); - unlink(co); - return -1; + goto cleanup; } snprintf(cmd, sizeof cmd, "timeout 180 %s/w6a_ww -o %s %s 2>/dev/null", bin, wo, src); if (runwait(cmd) != 0) { fprintf(stderr, "w6a_ww FAIL: ww w6a errored on %s\n", src); - unlink(co); unlink(wo); - return -1; + goto cleanup; } - char *bc = NULL, *bw = NULL; - size_t nc = 0, nw = 0; - int rc = 0; if (slurp(co, &bc, &nc) < 0 || slurp(wo, &bw, &nw) < 0) { fprintf(stderr, "w6a_ww FAIL: cannot read .o for %s\n", src); - rc = -1; + } else if (nc == 0) { + fprintf(stderr, "w6a_ww FAIL: empty .o for %s\n", src); } else if (nc != nw || memcmp(bc, bw, nc) != 0) { fprintf(stderr, "w6a_ww FAIL: %s — C %zu vs ww %zu bytes\n", src, nc, nw); - rc = -1; - } + } else + rc = 0; + +cleanup: free(bc); free(bw); - unlink(co); unlink(wo); + /* co/wo are reused across corpus files; a stale .o left behind + * would be slurped as a later file's output. */ + int cleanfail = 0; + if (unlink(co) != 0 && errno != ENOENT) { + perror(co); + cleanfail = 1; + } + if (unlink(wo) != 0 && errno != ENOENT) { + perror(wo); + cleanfail = 1; + } + if (cleanfail && rc == 0) + rc = -1; return rc; } @@ -112,6 +126,9 @@ main(void) * intentionally contains package main plus legacy file-import packages, * so it is not a directory-package root. */ char stem[256], cmd[4096]; + int fail = 0; + int n = 0; + int gen = 0; snprintf(stem, sizeof stem, "/tmp/wwa_%d_sh", getpid()); snprintf(cmd, sizeof cmd, "timeout 400 %s/ww build -o %s " @@ -120,7 +137,9 @@ main(void) if (runwait(cmd) != 0) { fprintf(stderr, "w6a_ww FAIL: cannot sep-build selfhost/cmd/w6a/main.ww\n"); - return 1; + /* a failed build can leave a partial stem/.sepwork tree. */ + fail = 1; + goto cleanup; } /* hand-written runtime — small, covers MOVQ/LEAQ/CALL/SYSCALL/RET; @@ -129,8 +148,6 @@ main(void) "rt/start.s", "rt/syscall.s", "rt/abort.s", "rt/alloc.s", "rt/streq.s", NULL, }; - int fail = 0; - int n = 0; for (int i = 0; rtfiles[i]; i++) { char p[2048]; snprintf(p, sizeof p, "%s/%s", cwd, rtfiles[i]); @@ -152,17 +169,32 @@ main(void) if (sz <= 0) continue; if (diff_one(bin, g.gl_pathv[i]) != 0) fail++; n++; + gen++; } globfree(&g); } + /* the PASS banner claims generated-asm coverage; an empty glob + * (or all-empty units) must not go green on the rt corpus alone. */ + if (gen == 0) { + fprintf(stderr, + "w6a_ww FAIL: no non-empty generated .s under %s.sepwork\n", + stem); + fail++; + } +cleanup: snprintf(cmd, sizeof cmd, "rm -rf %s.sepwork %s", stem, stem); - if (system(cmd)) {} + int cleanfail = runwait(cmd) != 0; + if (cleanfail) + fprintf(stderr, "w6a_ww: cleanup of %s{,.sepwork} failed\n", + stem); if (fail) { fprintf(stderr, "w6a_ww: %d/%d diff(s) failed\n", fail, n); return 1; } + if (cleanfail) + return 1; printf("w6a_ww: byte-identical to C w6a on %d corpus files " "(rt/*.s + selfhost/cmd/w6a sep-built .s)\n", n); return 0; diff --git a/test/wcc/992_w6l_ww.c b/test/wcc/992_w6l_ww.c index 59b415f0..1991825b 100644 --- a/test/wcc/992_w6l_ww.c +++ b/test/wcc/992_w6l_ww.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -68,11 +69,15 @@ slurp(const char *path, char **outbuf, size_t *outlen) * + reverse-topo .a resolution — a stronger link than the old single * main.o. */ static int -build_and_diff(const char *bin, const char *cwd, const char *tool) +build_and_diff(const char *bin, const char *cwd, const char *tool, int id) { char cstem[256], wstem[256], cmd[4096]; - snprintf(cstem, sizeof cstem, "/tmp/wwl_%d_c", getpid()); - snprintf(wstem, sizeof wstem, "/tmp/wwl_%d_w", getpid()); + snprintf(cstem, sizeof cstem, "/tmp/wwl_%d_%d_c", getpid(), id); + snprintf(wstem, sizeof wstem, "/tmp/wwl_%d_%d_w", getpid(), id); + + char *bc = NULL, *bw = NULL; + size_t nc = 0, nw = 0; + int rc = 0; snprintf(cmd, sizeof cmd, "timeout 300 %s/ww build -o %s " @@ -80,7 +85,8 @@ build_and_diff(const char *bin, const char *cwd, const char *tool) bin, cstem, cwd, tool); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww FAIL: C-link sep-build of %s\n", tool); - return -1; + rc = -1; + goto cleanup; } snprintf(cmd, sizeof cmd, "WW_W6L=%s/w6l_ww timeout 300 %s/ww build " @@ -88,25 +94,43 @@ build_and_diff(const char *bin, const char *cwd, const char *tool) bin, bin, wstem, cwd, tool); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww FAIL: ww-link sep-build of %s\n", tool); - snprintf(cmd, sizeof cmd, "rm -rf %s %s.sepwork", cstem, cstem); - if (system(cmd)) {} - return -1; + rc = -1; + goto cleanup; } - char *bc = NULL, *bw = NULL; - size_t nc = 0, nw = 0; - int rc = 0; if (slurp(cstem, &bc, &nc) < 0 || slurp(wstem, &bw, &nw) < 0) { fprintf(stderr, "w6l_ww FAIL: cannot read output for %s\n", tool); rc = -1; + } else if (nc == 0) { + fprintf(stderr, "w6l_ww FAIL: empty output for %s\n", tool); + rc = -1; } else if (nc != nw || memcmp(bc, bw, nc) != 0) { fprintf(stderr, "w6l_ww FAIL: %s — C %zu vs ww %zu bytes\n", tool, nc, nw); rc = -1; } free(bc); free(bw); - snprintf(cmd, sizeof cmd, "rm -rf %s %s %s.sepwork %s.sepwork", - cstem, wstem, cstem, wstem); - if (system(cmd)) {} + +cleanup: + /* `ww build` retains these exact caller-owned scratch trees; a + * never-created pid+id-keyed path is harmless to remove, so one + * funnel covers every exit. */ + int cleanfail = 0; + if (unlink(cstem) != 0 && errno != ENOENT) { + perror(cstem); + cleanfail = 1; + } + if (unlink(wstem) != 0 && errno != ENOENT) { + perror(wstem); + cleanfail = 1; + } + snprintf(cmd, sizeof cmd, "rm -rf %s.sepwork %s.sepwork", + cstem, wstem); + if (runwait(cmd) != 0) + cleanfail = 1; + if (cleanfail) + fprintf(stderr, "w6l_ww: cleanup failed for %s\n", tool); + if (cleanfail && rc == 0) + rc = -1; return rc; } @@ -130,7 +154,7 @@ main(void) int fail = 0; int n = 0; for (int i = 0; tools[i]; i++) { - if (build_and_diff(bin, cwd, tools[i]) != 0) fail++; + if (build_and_diff(bin, cwd, tools[i], i) != 0) fail++; n++; } if (fail) { diff --git a/test/wcc/993_ww_ww.c b/test/wcc/993_ww_ww.c index ba86a399..1b0ec1e1 100644 --- a/test/wcc/993_ww_ww.c +++ b/test/wcc/993_ww_ww.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -48,11 +49,14 @@ slurp_eq(const char *a, const char *b) FILE *fb = fopen(b, "rb"); if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } int rc = 0; + int any = 0; for (;;) { int ca = fgetc(fa); int cb = fgetc(fb); if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; + /* a produced executable can never be legitimately empty. */ + if (ca == EOF) { if (!any) rc = -1; break; } + any = 1; } fclose(fa); fclose(fb); return rc; @@ -92,29 +96,35 @@ diff_one(const char *bin, const char *cwd, const char *label, snprintf(dw, sizeof dw, "/tmp/ww_d_%d_w", getpid()); char cmd[256]; + int rc = -1; snprintf(cmd, sizeof cmd, "rm -rf %s %s && mkdir -p %s %s", dc, dw, dc, dw); - if (runwait(cmd) != 0) return -1; + if (runwait(cmd) != 0) goto cleanup; if (build_via(bin, "ww", src, dc, incs, out_basename) != 0) { fprintf(stderr, "ww_ww FAIL: C ww errored on %s\n", label); - return -1; + goto cleanup; } if (build_via(bin, "ww_ww", src, dw, incs, out_basename) != 0) { fprintf(stderr, "ww_ww FAIL: ww ww errored on %s\n", label); - return -1; + goto cleanup; } char co[1024], wo[1024]; snprintf(co, sizeof co, "%s/%s", dc, out_basename); snprintf(wo, sizeof wo, "%s/%s", dw, out_basename); - int rc = 0; - if (slurp_eq(co, wo) != 0) { + if (slurp_eq(co, wo) != 0) fprintf(stderr, "ww_ww FAIL: %s — driver outputs differ\n", label); - rc = -1; - } + else + rc = 0; + +cleanup: + /* `ww build` retains the caller-owned .sepwork tree inside the + * workdir; rm -rf of the exact pid-keyed pair covers it, and is + * safe even after a partial mkdir. */ snprintf(cmd, sizeof cmd, "rm -rf %s %s", dc, dw); - runwait(cmd); + if (runwait(cmd) != 0 && rc == 0) + rc = -1; (void)cwd; return rc; } @@ -132,12 +142,21 @@ run_exit_code(const char *bin, const char *driver, int code) if (!f) return -1; fprintf(f, "package main;\nexport fn main() i32 = {\n\treturn %d;\n};\n", code); - fclose(f); + if (fclose(f) != 0) { + perror(src); + if (unlink(src) != 0 && errno != ENOENT) + perror(src); + return -1; + } char cmd[256]; snprintf(cmd, sizeof cmd, "%s/%s run %s 2>/dev/null", bin, driver, src); int rc = runwait(cmd); - unlink(src); + if (unlink(src) != 0 && errno != ENOENT) { + perror(src); + if (rc == code) + rc = -1; + } return rc; } @@ -152,14 +171,28 @@ run_build_fail(const char *bin, const char *driver) char src[64]; snprintf(src, sizeof src, "/tmp/ww_badbuild_%d.ww", getpid()); FILE *f = fopen(src, "w"); - if (!f) return -1; + if (!f) { + perror(src); + return -1; + } wwtest_fputs("export fn main() i32 = {\n\treturn 1\n", f); /* no ; no } */ - fclose(f); + if (fclose(f) != 0) { + perror(src); + if (unlink(src) != 0 && errno != ENOENT) + perror(src); + return -1; + } char cmd[256]; snprintf(cmd, sizeof cmd, "%s/%s run %s 2>/dev/null", bin, driver, src); int rc = runwait(cmd); - unlink(src); + if (unlink(src) != 0 && errno != ENOENT) { + perror(src); + /* cleanup failure maps onto the -1 sentinel the caller rejects; + * a real rc==0 (driver failed to fail) keeps its diagnostic. */ + if (rc != 0) + rc = -1; + } return rc; } @@ -173,13 +206,21 @@ run_missing_pkg(const char *bin, const char *driver) { char tmpdir[80], src[160], errf[160], outbin[160], rmcmd[200]; snprintf(tmpdir, sizeof tmpdir, "/tmp/ww_mp_%s_%d", driver, getpid()); - mkdir(tmpdir, 0755); + if (mkdir(tmpdir, 0755) != 0) { + perror(tmpdir); + return 1; + } snprintf(src, sizeof src, "%s/mp.ww", tmpdir); snprintf(errf, sizeof errf, "%s/mp.err", tmpdir); snprintf(outbin, sizeof outbin, "%s/mp", tmpdir); snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); FILE *f = fopen(src, "w"); - if (!f) { runwait(rmcmd); return 1; } + if (!f) { + perror(src); + if (runwait(rmcmd) != 0) + fprintf(stderr, "ww_ww: cleanup of %s failed\n", tmpdir); + return 1; + } wwtest_fputs("import nosuchpkg;\nexport fn main() i32 = { return 0; };\n", f); fclose(f); @@ -200,12 +241,16 @@ run_missing_pkg(const char *bin, const char *driver) buf[n] = '\0'; found = strstr(buf, "cannot find package nosuchpkg") != NULL; } - runwait(rmcmd); + int cleanfail = runwait(rmcmd) != 0; if (rc == 0 || !found) { fprintf(stderr, "ww_ww FAIL: %s missing-pkg rc=%d found=%d " "(want nonzero + 'cannot find package')\n", driver, rc, found); return 1; } + if (cleanfail) { + fprintf(stderr, "ww_ww: cleanup of %s failed\n", tmpdir); + return 1; + } return 0; } @@ -232,7 +277,12 @@ main(void) "\tos.write(1, \"hi\\n\".ptr, 3u64);\n" "\treturn 0;\n" "};\n", f); - fclose(f); + if (fclose(f) != 0) { + perror(hello_src); + if (unlink(hello_src) != 0 && errno != ENOENT) + perror(hello_src); + return 1; + } } struct { @@ -260,13 +310,17 @@ main(void) int fail = 0; int n = 0; + int cleanfail = 0; for (int i = 0; cases[i].label; i++) { if (diff_one(bin, cwd, cases[i].label, cases[i].src, cases[i].out, cases[i].incs) != 0) fail++; n++; } - unlink(hello_src); + if (unlink(hello_src) != 0 && errno != ENOENT) { + perror(hello_src); + cleanfail = 1; + } /* #16: `ww_ww run` must propagate the child program's real exit code. * Table-driven; the non-zero rows fail under the old collapse-to-1. @@ -296,7 +350,9 @@ main(void) * failure (non-zero), and both drivers must agree. */ int cbad = run_build_fail(bin, "ww"); int wbad = run_build_fail(bin, "ww_ww"); - if (cbad == 0 || wbad == 0 || cbad != wbad) { + /* <= 0 rejects the -1 staging/cleanup sentinel: equal sentinels must + * not pass as build-fail parity when neither driver ever ran. */ + if (cbad <= 0 || wbad <= 0 || cbad != wbad) { fprintf(stderr, "ww_ww FAIL: build-fail exit C ww=%d ww_ww=%d " "(want equal and non-zero)\n", cbad, wbad); rcfail++; @@ -307,7 +363,7 @@ main(void) rcfail += run_missing_pkg(bin, "ww"); rcfail += run_missing_pkg(bin, "ww_ww"); - if (fail || rcfail) { + if (fail || rcfail || cleanfail) { fprintf(stderr, "ww_ww: %d/%d diff(s) failed, %d exit-code " "row(s) failed\n", fail, n, rcfail); return 1; diff --git a/test/wcc/994_w6c_ww.c b/test/wcc/994_w6c_ww.c index dd6598c1..ed4b9d3f 100644 --- a/test/wcc/994_w6c_ww.c +++ b/test/wcc/994_w6c_ww.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,9 @@ static int diff_one(const char *bin, const char *label, const char *src) { char ws[64], cs[64], cmd[2048]; + char *bw = NULL, *bc = NULL; + size_t nw = 0, nc = 0; + int rc = -1; snprintf(ws, sizeof ws, "/tmp/wwc6_%d_w.s", getpid()); snprintf(cs, sizeof cs, "/tmp/wwc6_%d_c.s", getpid()); @@ -72,28 +76,37 @@ diff_one(const char *bin, const char *label, const char *src) bin, src, ws); if (runwait(cmd) != 0) { fprintf(stderr, "w6c_ww FAIL: wwdump_ww -c errored on %s\n", label); - unlink(ws); - return -1; + goto cleanup; } snprintf(cmd, sizeof cmd, "timeout 180 %s/w6c_ww -o %s %s 2>/dev/null", bin, cs, src); if (runwait(cmd) != 0) { fprintf(stderr, "w6c_ww FAIL: w6c_ww errored on %s\n", label); - unlink(ws); unlink(cs); - return -1; + goto cleanup; } - char *bw = NULL, *bc = NULL; - size_t nw = 0, nc = 0; - int rc = 0; if (slurp(ws, &bw, &nw) < 0 || slurp(cs, &bc, &nc) < 0) { fprintf(stderr, "w6c_ww FAIL: cannot read .s for %s\n", label); - rc = -1; + } else if (nw == 0) { + fprintf(stderr, "w6c_ww FAIL: empty .s for %s\n", label); } else if (nw != nc || memcmp(bw, bc, nw) != 0) { fprintf(stderr, "w6c_ww FAIL: %s — wwdump_ww %zu vs w6c_ww %zu bytes\n", label, nw, nc); - rc = -1; - } + } else + rc = 0; + +cleanup: free(bw); free(bc); - unlink(ws); unlink(cs); + /* cs may not exist when w6c_ww never ran or died before -o. */ + int cleanfail = 0; + if (unlink(ws) != 0 && errno != ENOENT) { + perror(ws); + cleanfail = 1; + } + if (unlink(cs) != 0 && errno != ENOENT) { + perror(cs); + cleanfail = 1; + } + if (cleanfail && rc == 0) + rc = -1; return rc; } @@ -103,7 +116,15 @@ write_file(const char *path, const char *content) FILE *f = fopen(path, "wb"); if (!f) return -1; wwtest_fputs(content, f); - fclose(f); + /* wwtest_fputs is void; ferror is the only short-write witness. */ + int bad = ferror(f); + if (fclose(f) != 0) bad = 1; + if (bad) { + perror(path); + if (unlink(path) != 0 && errno != ENOENT) + perror(path); + return -1; + } return 0; } @@ -282,7 +303,10 @@ main(void) snprintf(src, sizeof src, "/tmp/wwc6_%d_%d.ww", getpid(), i); if (write_file(src, progs[i].src) != 0) { fail++; n++; continue; } if (diff_one(bin, progs[i].label, src) != 0) fail++; - unlink(src); + if (unlink(src) != 0 && errno != ENOENT) { + perror(src); + fail++; + } n++; } @@ -321,7 +345,14 @@ main(void) bad[i].label); fail++; } - unlink(src); unlink(s); + if (unlink(src) != 0 && errno != ENOENT) { + perror(src); + fail++; + } + if (unlink(s) != 0 && errno != ENOENT) { + perror(s); + fail++; + } n++; } @@ -371,7 +402,11 @@ main(void) for (int s = 0; s < 2; s++) { snprintf(cmd, sizeof cmd, "rm -rf %s %s.sepwork %s.cache", stg[s].prog, stg[s].prog, stg[s].prog); - runwait(cmd); + if (runwait(cmd) != 0) { + fprintf(stderr, "Tier-C: cleanup %s failed\n", + stg[s].prog); + fail++; + } } } diff --git a/test/wcc/995_self_rebuild.c b/test/wcc/995_self_rebuild.c index 2e072c8b..d1a81f22 100644 --- a/test/wcc/995_self_rebuild.c +++ b/test/wcc/995_self_rebuild.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static int @@ -53,12 +54,16 @@ slurp_eq(const char *a, const char *b) return -1; } int rc = 0; + size_t nb = 0; for (;;) { int ca = fgetc(fa); int cb = fgetc(fb); if (ca != cb) { rc = -1; break; } if (ca == EOF) break; + nb++; } + /* two 0-byte artifacts must not compare green (pkgcache 0-byte poison). */ + if (rc == 0 && nb == 0) rc = -1; fclose(fa); fclose(fb); return rc; } @@ -93,10 +98,10 @@ 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); - if (runwait(setup) != 0) return -1; + if (mkdir(j->workdir, 0755) != 0) { + perror(j->workdir); + return -1; + } char cmd[4096]; if (j->inc_local && j->inc_local[0]) { @@ -115,7 +120,14 @@ spawn_build(const char *bin, const char *cwd, struct buildjob *j) } pid_t p = fork(); - if (p < 0) return -1; + if (p < 0) { + char clean[128]; + snprintf(clean, sizeof clean, "rm -rf %s", j->workdir); + if (runwait(clean) != 0) + fprintf(stderr, "self-rebuild: cleanup %s failed\n", + j->workdir); + return -1; + } if (p == 0) { int rc = system(cmd); if (rc == -1) _exit(1); @@ -162,7 +174,11 @@ collect_build(const char *bin, struct buildjob *j) char cleanup[128]; snprintf(cleanup, sizeof cleanup, "rm -rf %s", j->workdir); - runwait(cleanup); + int cleanfail = runwait(cleanup) != 0; + if (cleanfail) + fprintf(stderr, "self-rebuild: cleanup %s failed\n", j->workdir); + if (cleanfail && rc == 0) + rc = -1; return rc; } diff --git a/test/wcc/996_dyn_ww.c b/test/wcc/996_dyn_ww.c index 87e07ad3..af7245fc 100644 --- a/test/wcc/996_dyn_ww.c +++ b/test/wcc/996_dyn_ww.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -67,22 +68,23 @@ main(void) * private /tmp stem (NOT next to the tracked example source), then * link .sepwork/__root.o — the self-contained single-package * object the flip emits in place of the old next-to-source .o. */ - char cmd[4096], mbstem[256], mbobj[320]; + char cmd[4096], mbstem[256], mbobj[320], co[64], wo[64]; snprintf(mbstem, sizeof mbstem, "/tmp/wwld_%d_mb", getpid()); snprintf(mbobj, sizeof mbobj, "%s.sepwork/__root.o", mbstem); + snprintf(co, sizeof co, "/tmp/wwld_%d_c", getpid()); + snprintf(wo, sizeof wo, "/tmp/wwld_%d_w", getpid()); + + int rc = 0; snprintf(cmd, sizeof cmd, "cd %s/examples/mandelbrot && %s/ww build " "-o %s mandelbrot.ww -L /usr/lib -l c >/dev/null 2>&1", cwd, bin, mbstem); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww-dyn FAIL: cannot build mandelbrot.o via C driver\n"); - return 1; + rc = 1; + goto cleanup; } - char co[64], wo[64]; - snprintf(co, sizeof co, "/tmp/wwld_%d_c", getpid()); - snprintf(wo, sizeof wo, "/tmp/wwld_%d_w", getpid()); - /* C-side w6l with the dynamic flags. */ snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s -L /usr/lib " @@ -90,8 +92,8 @@ main(void) bin, co, mbobj, cwd); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww-dyn FAIL: C w6l errored\n"); - unlink(co); - return 1; + rc = 1; + goto cleanup; } /* ww-side w6l with the same flags. */ @@ -101,16 +103,18 @@ main(void) bin, wo, mbobj, cwd); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww-dyn FAIL: ww w6l errored\n"); - unlink(co); unlink(wo); - return 1; + rc = 1; + goto cleanup; } char *bc = NULL, *bw = NULL; size_t nc = 0, nw = 0; - int rc = 0; if (slurp(co, &bc, &nc) < 0 || slurp(wo, &bw, &nw) < 0) { fprintf(stderr, "w6l_ww-dyn FAIL: cannot read outputs\n"); rc = 1; + } else if (nc == 0) { + fprintf(stderr, "w6l_ww-dyn FAIL: empty outputs\n"); + rc = 1; } else if (nc != nw || memcmp(bc, bw, nc) != 0) { fprintf(stderr, "w6l_ww-dyn FAIL: C %zu vs ww %zu bytes\n", nc, nw); @@ -121,9 +125,24 @@ main(void) "%zu bytes)\n", nc); } free(bc); free(bw); - unlink(co); unlink(wo); - /* #93: the sep scratch + tmpdir-owned outputs. */ - snprintf(cmd, sizeof cmd, "rm -rf %s.sepwork %s", mbstem, mbstem); - if (system(cmd)) {} + +cleanup: + /* #93: `ww build` retains this exact caller-owned scratch tree. */ + snprintf(cmd, sizeof cmd, "rm -rf %s.sepwork", mbstem); + int cleanfail = runwait(cmd) != 0; + if (unlink(co) != 0 && errno != ENOENT) { + perror(co); + cleanfail = 1; + } + if (unlink(wo) != 0 && errno != ENOENT) { + perror(wo); + cleanfail = 1; + } + if (unlink(mbstem) != 0 && errno != ENOENT) { + perror(mbstem); + cleanfail = 1; + } + if (cleanfail && rc == 0) + rc = 1; return rc; }