test/wcc: carrier ownership repair and driver-contract adaptation

Every surviving carrier now owns its artifacts: checked mkdir/mkdtemp/
fopen acquisition, one all-exit cleanup funnel per carrier, ENOENT-
tolerant checked unlinks, exact-path deletion (rm -rf only for an
owned pid-keyed dir or a .sepwork beneath one), and cleanup failure
fails a passing carrier without overwriting its diagnostic. In the
same pass the carriers adapt to the driver contract this branch lands:
--sep and WW_PKGCACHE are gone, -S and the /tmp/ww_run_<pid> scratch
contract are asserted, and rows whose runtime or reject coverage moved
to test/wcc/data fixtures or test/lang @test owners are trimmed to the
byte/artifact/diagnostic observations only they can make.

Repair and adaptation ride together because most files interleave both
in the same hunks; splitting would manufacture intermediate carrier
states that never existed and cannot run against either driver.
This commit is contained in:
2026-08-07 23:02:47 +09:00
parent b2899dd8d3
commit a95a7a316b
132 changed files with 7573 additions and 6172 deletions

View File

@@ -87,6 +87,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
@@ -189,25 +190,27 @@ write_source(const char *path, const char *src)
{
FILE *f = fopen(path, "wb");
if (!f) return -1;
fputs(src, f);
fclose(f);
return 0;
int bad = fputs(src, f) == EOF || ferror(f);
if (fclose(f) != 0) bad = 1;
return bad ? -1 : 0;
}
/* Per-row tmpdir cleanup. ww_ww writes intermediates next to the
* source (filed task #15), so each row's build leaves
* <src>.{combined.ww,s,o} + bare exe alongside. Sweep all then
* rmdir. Mirror of 778's cleanup_tmp. */
static void
/* Per-row tmpdir cleanup. `ww build` retains its exact
* <base>.sepwork tree; remove that tree, the source, and the bare
* executable before removing the invocation-owned directory. */
static int
cleanup_tmp(const char *tmpdir, const char *base)
{
char p[640];
snprintf(p, sizeof p, "%s/%s.ww", tmpdir, base); unlink(p);
snprintf(p, sizeof p, "%s/%s.s", tmpdir, base); unlink(p);
snprintf(p, sizeof p, "%s/%s.o", tmpdir, base); unlink(p);
snprintf(p, sizeof p, "%s/%s.combined.ww", tmpdir, base); unlink(p);
snprintf(p, sizeof p, "%s/%s", tmpdir, base); unlink(p);
rmdir(tmpdir);
int rc = 0;
snprintf(p, sizeof p, "%s/%s.ww", tmpdir, base);
if (unlink(p) != 0 && errno != ENOENT) rc = -1;
snprintf(p, sizeof p, "rm -rf -- %s/%s.sepwork", tmpdir, base);
if (runwait(p) != 0) rc = -1;
snprintf(p, sizeof p, "%s/%s", tmpdir, base);
if (unlink(p) != 0 && errno != ENOENT) rc = -1;
if (rmdir(tmpdir) != 0) rc = -1;
return rc;
}
static int
@@ -228,8 +231,12 @@ run_row(const char *driver, const char *cwd, const struct row *r, int seq)
snprintf(tmpdir, sizeof tmpdir, "/tmp/lvs_%d_d_%d", getpid(), seq);
snprintf(base, sizeof base, "main779");
snprintf(src, sizeof src, "%s/%s.ww", tmpdir, base);
mkdir(tmpdir, 0755);
if (write_source(src, r->src) != 0) { cleanup_tmp(tmpdir, base); return -1; }
if (mkdir(tmpdir, 0755) != 0) return -1;
if (write_source(src, r->src) != 0) {
if (cleanup_tmp(tmpdir, base) != 0)
fprintf(stderr, "row[%s]: setup cleanup failed\n", r->label);
return -1;
}
int rc;
int br = build_via_driver(driver, tmpdir, cwd, src);
if (br == 0) {
@@ -243,13 +250,12 @@ run_row(const char *driver, const char *cwd, const struct row *r, int seq)
} else {
rc = -1;
}
cleanup_tmp(tmpdir, base);
if (cleanup_tmp(tmpdir, base) != 0) return -1;
return rc;
}
/* asm_byte_identical — diff cstage vs wwstage .s. Parallel trees so
* ww_ww writing intermediates next to the source doesn't clobber the
* cstage .s (CLAUDE.md rule 14 phase split). Mirror of 778's. Unused
/* asm_byte_identical — diff cstage vs wwstage .s. Parallel trees keep
* each driver's retained .sepwork output separate. Unused
* for fold-e5 — every row is STAGE_CS-only per #226/#227 (#209, the
* checker bail, is closed) — but kept scaffolded for when those cgen
* folds land and byte-id graduates. */
@@ -261,18 +267,28 @@ asm_byte_identical(const char *cdrv, const char *wdrv, const char *cwd,
snprintf(tdc, sizeof tdc, "/tmp/lvs_%d_c_%d", getpid(), seq);
snprintf(tdw, sizeof tdw, "/tmp/lvs_%d_w_%d", getpid(), seq);
snprintf(base, sizeof base, "main779");
mkdir(tdc, 0755);
mkdir(tdw, 0755);
if (mkdir(tdc, 0755) != 0) return -1;
if (mkdir(tdw, 0755) != 0) {
if (cleanup_tmp(tdc, base) != 0)
fprintf(stderr, "row[%s]: setup cleanup failed\n", r->label);
return -1;
}
snprintf(src, sizeof src, "%s/%s.ww", tdc, base);
if (write_source(src, r->src) != 0) { cleanup_tmp(tdc, base); cleanup_tmp(tdw, base); return -1; }
if (write_source(src, r->src) != 0) {
int clean_c = cleanup_tmp(tdc, base);
int clean_w = cleanup_tmp(tdw, base);
if (clean_c != 0 || clean_w != 0)
fprintf(stderr, "row[%s]: setup cleanup failed\n", r->label);
return -1;
}
int rc = -1;
if (build_via_driver(cdrv, tdc, cwd, src) != 0) goto out;
snprintf(cs, sizeof cs, "%s/%s.s", tdc, base);
snprintf(cs, sizeof cs, "%s/%s.sepwork/__root.s", tdc, base);
snprintf(src, sizeof src, "%s/%s.ww", tdw, base);
if (write_source(src, r->src) != 0) goto out;
if (build_via_driver(wdrv, tdw, cwd, src) != 0) goto out;
snprintf(ws, sizeof ws, "%s/%s.s", tdw, base);
snprintf(ws, sizeof ws, "%s/%s.sepwork/__root.s", tdw, base);
FILE *fc = fopen(cs, "rb");
FILE *fw = fopen(ws, "rb");
@@ -288,8 +304,8 @@ asm_byte_identical(const char *cdrv, const char *wdrv, const char *cwd,
if (fc) fclose(fc);
if (fw) fclose(fw);
out:
cleanup_tmp(tdc, base);
cleanup_tmp(tdw, base);
if (cleanup_tmp(tdc, base) != 0) rc = -1;
if (cleanup_tmp(tdw, base) != 0) rc = -1;
return rc;
}