From ad189c2ee2d2971f31c58b564d2a2743125940b6 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 8 Aug 2026 14:07:57 +0900 Subject: [PATCH] test: port the sep archive/link observers to ww; retire 989_{separchive,sepcycle_dup} seplink_test.ww carries the .a substrate legs (root-as-.o layout, .a byte-id + 3x determinism, the #31 masked-dup PASS-3 reject with its non-vacuity flip), the loud dependency-cycle reject with byte-equal cs/ww stderr, and the w6l/w6l_ww bare-main duplicate-symbol reject (achievable substring parity per the filed message divergence). --- Makefile | 3 +- test/sep/seplink_test.ww | 361 +++++++++++++++++++++++++++++ test/wcc/989_separchive_run.c | 416 ---------------------------------- test/wcc/989_sepcycle_dup.c | 409 --------------------------------- 4 files changed, 363 insertions(+), 826 deletions(-) create mode 100644 test/sep/seplink_test.ww delete mode 100644 test/wcc/989_separchive_run.c delete mode 100644 test/wcc/989_sepcycle_dup.c diff --git a/Makefile b/Makefile index 74d1a17c..bca6cae8 100644 --- a/Makefile +++ b/Makefile @@ -362,7 +362,8 @@ BYTEID_WW_TARGETS = $(BYTEID_WW_TESTS:%=wwtest/%) # gates (module trees, sepwork artifact layout, composed //ww:module # units, link rejects), NOT byteid suites: they run under # test-compiler beside the surviving residual carriers. -SEP_WW_TESTS = test/sep/sepbuild_test.ww test/sep/sepimport_test.ww +SEP_WW_TESTS = test/sep/sepbuild_test.ww test/sep/sepimport_test.ww \ + test/sep/seplink_test.ww SEP_WW_TARGETS = $(SEP_WW_TESTS:%=wwtest/%) BOOTSTRAP_WRAPPER_SOURCES = test/wcc/950_selfcheck.c \ test/wcc/991_w6a_ww.c \ diff --git a/test/sep/seplink_test.ww b/test/sep/seplink_test.ww new file mode 100644 index 00000000..f68e5ead --- /dev/null +++ b/test/sep/seplink_test.ww @@ -0,0 +1,361 @@ +package seplink_test; + +// Archive-substrate + link-reject observers, both stages. Ports of the +// retired native carriers test/wcc/989_separchive_run.c and +// 989_sepcycle_dup.c; every assertion preserved. +// +// archive (#46 commit-5a) — `ww build` wraps each DEP package's .o in +// a deterministic single-member .a and links the ROOT as a positional +// .o (force-loaded): build+run exit 7 both stages; __root.a absent, +// __root.o + helper.a present; cs helper.a == ww helper.a (rule 10, +// the .a byte-id substrate); 3 cold cstage rebuilds emit +// byte-identical helper.a (zeroed mtime/uid/gid, fixed mode/member — +// a floating byte would poison the content cache key). +// +// archivedup (#31 PASS 3) — two dep packages force the same link +// symbol via @symbol("dup_sym"); one member is pulled, the other +// lands UNPULLED defining an already-defined name — exactly what +// selective pull skips and the post-pull PASS 3 catches: both stages +// exit non-zero, name "duplicate symbol", and leave no partial +// binary. Non-vacuity flip: a distinct symbol builds + runs (exit 3). +// +// cycle (#46 commit-4) — a 3-package import cycle +// root->pkga->pkgb->pkgc->pkga is LOUD-rejected: non-zero exit, the +// `dependency cycle: pkga -> pkgb -> pkgc -> pkga` chain named, no +// partial binary, and cs stderr == ww stderr BYTE-IDENTICAL (the +// message is pure driver code, rule 10). Non-vacuity flip: the +// acyclic tree builds + runs (exit 7). +// +// linkdup (#31) — two hand-assembled .o each defining bare `main` fed +// to w6l AND w6l_ww: non-zero, "duplicate symbol", no partial binary. +// ACHIEVABLE parity only — substring, NOT byte-equal stderr: cstage +// prints `: duplicate symbol `, wwstage the bare form (a +// pre-existing divergence filed with the carrier, not reconciled +// here). Non-vacuity: a single .o + libwwrt.a links and runs clean. +// +// Dropped C machinery, not assertions: per-path unlink/rmdir +// accounting (testenv.clean asserts the removal). + +import os; +import os.exec; +import strings; +import testenv; +import time; + +fn fail(label: str, why: str) void = { + let m: str = strings.concat("seplink FAIL: ", label, " -- ", why, + "\n"); + os.write(2, m.ptr, m.len: u64); + assert(false); +}; + +fn tmo() time.duration = { + return (240i64 * (time.second: i64)): time.duration; +}; + +fn run(dir: str, name: str, argv: []str, out: *testenv.commandout) void = { + testenv.runcommand(dir, dir, name, argv, tmo(), out); +}; + +// -1 encodes an abnormal (non-EXIT) termination, never a valid code. +fn runcode(dir: str, name: str, argv: []str) i32 = { + let co: testenv.commandout; + run(dir, name, argv, &co); + if (co.termination != exec.termination.EXIT) { return -1; }; + return co.code; +}; + +// ---- archive (#46 commit-5a) ------------------------------------------- + +@test fn archive() void = { + let td: str = testenv.fresh(); + assert(os.mkdir(strings.concat(td, "/helper"), 493) == 0); + testenv.writefile(strings.concat(td, "/helper/h.ww"), strings.concat( + "package helper;\n", + "export fn val() i32 = { return 7; };\n")); + let rootww: str = strings.concat(td, "/root.ww"); + testenv.writefile(rootww, strings.concat( + "package main;\n", + "import helper;\n", + "fn main() i32 = { return helper.val(); };\n")); + + let drvs: []str = ["ww", "ww_ww"]; + let tags: []str = ["cs", "ww"]; + let s: i32 = 0; + for (s < 2) { + let prog: str = strings.concat(td, "/prog.", tags[s]); + let av: []str = [testenv.driver(drvs[s]), "build", "-I", td, + "-o", prog, rootww]; + if (runcode(td, strings.concat("build_", tags[s]), av) != 0) { + fail("archive", strings.concat(drvs[s], " build failed")); + }; + let rav: []str = [prog]; + if (runcode(td, strings.concat("runbin_", tags[s]), rav) != 7) { + fail("archive", strings.concat(drvs[s], " prog exit != 7")); + }; + s += 1; + }; + + // layout: root stays a positional force-loaded .o, deps become .a + if (testenv.exists(strings.concat(td, "/prog.cs.sepwork/__root.a"))) { + fail("archive", "root wrapped in .a (should stay positional .o)"); + }; + if (!testenv.exists(strings.concat(td, "/prog.cs.sepwork/__root.o"))) { + fail("archive", "missing root .o"); + }; + if (!testenv.exists(strings.concat(td, "/prog.cs.sepwork/helper.a"))) { + fail("archive", "missing dep helper.a"); + }; + + // rule 10: the .a byte-id substrate + if (!testenv.same( + testenv.readfile(strings.concat(td, "/prog.cs.sepwork/helper.a")), + testenv.readfile(strings.concat(td, "/prog.ww.sepwork/helper.a")))) { + fail("archive", "cs helper.a != ww helper.a (rule 10 .a byte-id)"); + }; + + // determinism: 3 cold cstage rebuilds -> byte-identical .a + let det0: str = strings.concat(td, "/det0"); + let det1: str = strings.concat(td, "/det1"); + let det2: str = strings.concat(td, "/det2"); + let av0: []str = [testenv.driver("ww"), "build", "-I", td, "-o", det0, + rootww]; + if (runcode(td, "det0", av0) != 0) { fail("archive", "det0 build"); }; + let av1: []str = [testenv.driver("ww"), "build", "-I", td, "-o", det1, + rootww]; + if (runcode(td, "det1", av1) != 0) { fail("archive", "det1 build"); }; + let av2: []str = [testenv.driver("ww"), "build", "-I", td, "-o", det2, + rootww]; + if (runcode(td, "det2", av2) != 0) { fail("archive", "det2 build"); }; + let a0: str = testenv.readfile(strings.concat(det0, + ".sepwork/helper.a")); + let a1: str = testenv.readfile(strings.concat(det1, + ".sepwork/helper.a")); + let a2: str = testenv.readfile(strings.concat(det2, + ".sepwork/helper.a")); + if (!testenv.same(a0, a1) || !testenv.same(a1, a2)) { + fail("archive", strings.concat(".a not deterministic across 3 ", + "builds (floating bytes poison the cache key)")); + }; + testenv.clean(td); +}; + +// ---- archivedup (#31 through .a, PASS 3) ------------------------------- + +@test fn archivedup() void = { + let td: str = testenv.fresh(); + assert(os.mkdir(strings.concat(td, "/pkga"), 493) == 0); + assert(os.mkdir(strings.concat(td, "/pkgb"), 493) == 0); + testenv.writefile(strings.concat(td, "/pkga/a.ww"), strings.concat( + "package pkga;\n", + "@symbol(\"dup_sym\") export fn afn() i32 = { return 1; };\n")); + let pbww: str = strings.concat(td, "/pkgb/b.ww"); + testenv.writefile(pbww, strings.concat( + "package pkgb;\n", + "@symbol(\"dup_sym\") export fn bfn() i32 = { return 2; };\n")); + let droot: str = strings.concat(td, "/droot.ww"); + testenv.writefile(droot, strings.concat( + "package main;\n", + "import pkga;\n", + "import pkgb;\n", + "fn main() i32 = { return pkga.afn() + pkgb.bfn(); };\n")); + + let drvs: []str = ["ww", "ww_ww"]; + let tags: []str = ["cs", "ww"]; + let s: i32 = 0; + for (s < 2) { + let prog: str = strings.concat(td, "/dup.", tags[s]); + let av: []str = [testenv.driver(drvs[s]), "build", "-I", td, + "-o", prog, droot]; + let co: testenv.commandout; + run(td, strings.concat("dup_", tags[s]), av, &co); + if (co.termination == exec.termination.EXIT && co.code == 0) { + fail("archivedup", strings.concat(drvs[s], " accepted a masked ", + "cross-pkg dup through .a (PASS 3 missing?)")); + }; + if (!testenv.has(co.stderr, "duplicate symbol")) { + fail("archivedup", strings.concat(drvs[s], + " missing 'duplicate symbol' on the .a dup path")); + }; + if (testenv.exists(prog)) { + fail("archivedup", strings.concat(drvs[s], + " produced a partial binary on the dup reject")); + }; + s += 1; + }; + + // non-vacuity flip: a distinct symbol builds + runs (1 + 2) + assert(os.remove(pbww) == 0); + testenv.writefile(pbww, strings.concat( + "package pkgb;\n", + "@symbol(\"uniq_sym\") export fn bfn() i32 = { return 2; };\n")); + let s2: i32 = 0; + for (s2 < 2) { + let prog: str = strings.concat(td, "/ok.", tags[s2]); + let av: []str = [testenv.driver(drvs[s2]), "build", "-I", td, + "-o", prog, droot]; + if (runcode(td, strings.concat("ok_", tags[s2]), av) != 0) { + fail("archivedup", strings.concat(drvs[s2], " could not build ", + "the distinct-symbol graph (non-vacuity)")); + }; + let rav: []str = [prog]; + if (runcode(td, strings.concat("okrun_", tags[s2]), rav) != 3) { + fail("archivedup", strings.concat(drvs[s2], + " flip prog exit != 3 (non-vacuity)")); + }; + s2 += 1; + }; + testenv.clean(td); +}; + +// ---- cycle (#46 commit-4 A) -------------------------------------------- + +@test fn cycle() void = { + let td: str = testenv.fresh(); + assert(os.mkdir(strings.concat(td, "/pkga"), 493) == 0); + assert(os.mkdir(strings.concat(td, "/pkgb"), 493) == 0); + assert(os.mkdir(strings.concat(td, "/pkgc"), 493) == 0); + let rootww: str = strings.concat(td, "/root.ww"); + testenv.writefile(rootww, strings.concat( + "package main;\n", + "import pkga;\n", + "fn main() i32 = { return pkga.av(); };\n")); + testenv.writefile(strings.concat(td, "/pkga/a.ww"), strings.concat( + "package pkga;\n", + "import pkgb;\n", + "export fn av() i32 = { return pkgb.bv(); };\n")); + testenv.writefile(strings.concat(td, "/pkgb/b.ww"), strings.concat( + "package pkgb;\n", + "import pkgc;\n", + "export fn bv() i32 = { return pkgc.cv(); };\n")); + let fc: str = strings.concat(td, "/pkgc/c.ww"); + testenv.writefile(fc, strings.concat( + "package pkgc;\n", + "import pkga;\n", + "export fn cv() i32 = { return pkga.av(); };\n")); + + let drvs: []str = ["ww", "ww_ww"]; + let tags: []str = ["cs", "ww"]; + let errs: []str = ["", ""]; + let s: i32 = 0; + for (s < 2) { + let prog: str = strings.concat(td, "/prog.", tags[s]); + let av: []str = [testenv.driver(drvs[s]), "build", "-o", prog, + rootww]; + let co: testenv.commandout; + run(td, strings.concat("cyc_", tags[s]), av, &co); + if (co.termination == exec.termination.EXIT && co.code == 0) { + fail("cycle", strings.concat(drvs[s], + " build returned 0 (no-op reject)")); + }; + if (!testenv.has(co.stderr, + "dependency cycle: pkga -> pkgb -> pkgc -> pkga")) { + fail("cycle", strings.concat(drvs[s], + " missing the cycle-chain message")); + }; + if (testenv.exists(prog)) { + fail("cycle", strings.concat(drvs[s], + " produced a partial binary")); + }; + errs[s] = co.stderr; + s += 1; + }; + // the cycle message is pure driver code -> byte-identical stderr + if (!testenv.same(errs[0], errs[1])) { + fail("cycle", "cs stderr != ww stderr (rule 10)"); + }; + + // non-vacuity flip: break the cycle -> both stages build + run + assert(os.remove(fc) == 0); + testenv.writefile(fc, strings.concat( + "package pkgc;\n", + "export fn cv() i32 = { return 7; };\n")); + let s2: i32 = 0; + for (s2 < 2) { + let prog: str = strings.concat(td, "/ok.", tags[s2]); + let av: []str = [testenv.driver(drvs[s2]), "build", "-o", prog, + rootww]; + if (runcode(td, strings.concat("cycok_", tags[s2]), av) != 0) { + fail("cycle", strings.concat(drvs[s2], " could not build the ", + "acyclic graph (non-vacuity)")); + }; + let rav: []str = [prog]; + if (runcode(td, strings.concat("cycokrun_", tags[s2]), rav) != 7) { + fail("cycle", strings.concat(drvs[s2], + " flip prog exit != 7 (non-vacuity)")); + }; + s2 += 1; + }; + testenv.clean(td); +}; + +// ---- linkdup (#31 at the linker) --------------------------------------- + +@test fn linkdup() void = { + let td: str = testenv.fresh(); + let u1: str = strings.concat(td, "/u1.ww"); + let u2: str = strings.concat(td, "/u2.ww"); + testenv.writefile(u1, strings.concat("package main;\n", + "fn main() i32 = { return 0; };\n")); + testenv.writefile(u2, strings.concat("package main;\n", + "fn main() i32 = { return 1; };\n")); + let o1: str = strings.concat(td, "/u1.o"); + let o2: str = strings.concat(td, "/u2.o"); + let names: []str = ["u1", "u2"]; + let n: i32 = 0; + for (n < 2) { + let sf: str = strings.concat(td, "/", names[n], ".s"); + let cav: []str = [testenv.driver("w6c"), "-c", "-o", sf, + strings.concat(td, "/", names[n], ".ww")]; + if (runcode(td, strings.concat("c_", names[n]), cav) != 0) { + fail("linkdup", strings.concat("w6c -c ", names[n], " failed")); + }; + let aav: []str = [testenv.driver("w6a"), "-o", + strings.concat(td, "/", names[n], ".o"), sf]; + if (runcode(td, strings.concat("a_", names[n]), aav) != 0) { + fail("linkdup", strings.concat("w6a ", names[n], " failed")); + }; + n += 1; + }; + + let lnks: []str = ["w6l", "w6l_ww"]; + let l: i32 = 0; + for (l < 2) { + let prog: str = strings.concat(td, "/dupprog.", lnks[l]); + let av: []str = [testenv.driver(lnks[l]), "-o", prog, o1, o2]; + let co: testenv.commandout; + run(td, strings.concat("dup_", lnks[l]), av, &co); + if (co.termination == exec.termination.EXIT && co.code == 0) { + fail("linkdup", strings.concat(lnks[l], + " accepted a duplicate symbol (exit 0)")); + }; + if (!testenv.has(co.stderr, "duplicate symbol")) { + fail("linkdup", strings.concat(lnks[l], + " missing 'duplicate symbol' message")); + }; + if (testenv.exists(prog)) { + fail("linkdup", strings.concat(lnks[l], + " produced a partial binary on the reject path")); + }; + l += 1; + }; + + // non-vacuity: a single .o + libwwrt.a links clean and runs + let rt: str = strings.concat(testenv.repo(), "/out/lib/libwwrt.a"); + let l2: i32 = 0; + for (l2 < 2) { + let prog: str = strings.concat(td, "/single.", lnks[l2]); + let av: []str = [testenv.driver(lnks[l2]), "-o", prog, o1, rt]; + if (runcode(td, strings.concat("single_", lnks[l2]), av) != 0) { + fail("linkdup", strings.concat(lnks[l2], + " could not link a single .o (non-vacuity)")); + }; + let rav: []str = [prog]; + if (runcode(td, strings.concat("singlerun_", lnks[l2]), rav) != 0) { + fail("linkdup", strings.concat(lnks[l2], + " single prog did not run clean (non-vacuity)")); + }; + l2 += 1; + }; + testenv.clean(td); +}; diff --git a/test/wcc/989_separchive_run.c b/test/wcc/989_separchive_run.c deleted file mode 100644 index 557c2817..00000000 --- a/test/wcc/989_separchive_run.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * 989_separchive_run — M3-tail commit-5a gate (#46, task #62): the - * per-package `.a` substrate + its archive-path #31 dup-detect, both - * stages, COLD. Commit 5a makes `ww build` wrap each DEP package's - * `.o` in a deterministic single-member `.a` (cstage archive_o / - * wwstage archiveo) and link the ROOT as a positional `.o` (force-loaded) - * + dep `.a` reverse-topo + libwwrt.a. The #31 dup the selective pull - * would mask is caught by a post-pull PASS 3 in w6l/w6l_ww load_archive. - * - * Legs (fresh output stems under an invocation-owned root; retained - * `.sepwork` is inspected, then removed by final carrier cleanup): - * 1. POSITIVE: root→helper builds + runs exit 7, BOTH stages, through - * the `.a` link path (root `.o` + helper `.a`). - * 2. ★ DETERMINISM (ken, load-bearing): re-archive the same package 3× - * → byte-identical `.a` (proves zeroed mtime/uid/gid + fixed mode + - * fixed member name; a floating md5 would poison the 5b cache key). - * 3. ★ cs `.a` == ww `.a` (rule 10, the NEW byte-id substrate ken binds): - * the dep `.a` from `ww` is byte-identical to the one from - * `ww_ww`. - * 4. ★ #31 dup THROUGH the `.a` path (ken #263 + D3, the leg that proves - * PASS 3 closed the selective-pull hole): two DEP packages each export - * the same link symbol via `@symbol("dup_sym")`, referenced by root. - * One dep's member is pulled; the OTHER lands UNPULLED and defines an - * already-`defined` name — exactly what selective-pull skips. BOTH - * stages must (exit≠0) ∧ (stderr contains "duplicate symbol") ∧ (no - * partial binary). NON-VACUITY flip: give the second dep a DISTINCT - * symbol → both stages build + run (exit 3), proving the leg actually - * discriminates (without PASS 3 the dup leg would WRONGLY pass green). - * 5. ACHIEVABLE-parity posture (same as c4's 989_sepcycle_dup, because - * #61 is a separate commit): cs vs ww is `both exit≠0 ∧ both stderrs - * contain "duplicate symbol"` — NOT exact-stderr-equal (cstage names - * `: duplicate symbol `, wwstage the bare form). - * - * Light wwstage-driver test (CLAUDE.md rule 14): all fixtures + scratch - * live under /tmp, COLD each run. Models 989_sepbuild_run.c conventions. - */ -#include -#include -#include -#include -#include -#include -#include - -#define EXPECT_EXIT 7 - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return 1; -} - -static const char * -absbin(void) -{ - const char *b = getenv("BIN"); - if (!b) b = "out/bin"; - if (b[0] == '/') return b; - static char buf[2048]; - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return NULL; - snprintf(buf, sizeof buf, "%s/%s", cwd, b); - return buf; -} - -static int -slurp(const char *path, char **outbuf, size_t *outlen) -{ - FILE *f = fopen(path, "rb"); - if (!f) return -1; - fseek(f, 0, SEEK_END); - long n = ftell(f); - fseek(f, 0, SEEK_SET); - if (n < 0) { fclose(f); return -1; } - char *b = malloc((size_t)n + 1); - if (!b) { fclose(f); return -1; } - if (fread(b, 1, (size_t)n, f) != (size_t)n) { free(b); fclose(f); return -1; } - b[n] = '\0'; - fclose(f); - *outbuf = b; - *outlen = (size_t)n; - return 0; -} - -static int -files_eq(const char *a, const char *b) -{ - char *ba = NULL, *bb = NULL; - size_t na = 0, nb = 0; - if (slurp(a, &ba, &na) < 0 || slurp(b, &bb, &nb) < 0) { - free(ba); free(bb); - return -1; - } - int eq = (na == nb && memcmp(ba, bb, na) == 0); - free(ba); free(bb); - return eq ? 0 : 1; -} - -static int -file_has(const char *path, const char *needle) -{ - char *b = NULL; - size_t n = 0; - if (slurp(path, &b, &n) < 0) return 0; - int found = (strstr(b, needle) != NULL); - free(b); - return found; -} - -static int -write_file(const char *path, const char *body) -{ - FILE *f = fopen(path, "wb"); - if (!f) return -1; - fputs(body, f); - fclose(f); - return 0; -} - -int -main(void) -{ - const char *bin = absbin(); - if (!bin) return 1; - char td[64], cmd[8192]; - int fail = 0, have_helpdir = 0, have_pkgad = 0, have_pkgbd = 0; - - snprintf(td, sizeof td, "/tmp/wwar_%d", getpid()); - if (mkdir(td, 0755) != 0) { - fprintf(stderr, "separchive FAIL: cannot acquire %s\n", td); - return 1; - } - - /* ---- root → helper fixture (one dep `.a`) ------------------------ */ - char helpdir[1024], helpww[1100], rootww[1100]; - snprintf(helpdir, sizeof helpdir, "%s/helper", td); - if (mkdir(helpdir, 0755) != 0) { - fprintf(stderr, "separchive FAIL: cannot create %s\n", helpdir); - fail++; goto out; - } - have_helpdir = 1; - snprintf(helpww, sizeof helpww, "%s/h.ww", helpdir); - snprintf(rootww, sizeof rootww, "%s/root.ww", td); - if (write_file(helpww, - "package helper;\n" - "export fn val() i32 = { return 7; };\n") || - write_file(rootww, - "package main;\n" - "import helper;\n" - "fn main() i32 = { return helper.val(); };\n")) { - fail++; goto out; - } - - struct { const char *drv, *tag; char prog[1024]; } - stg[] = { { "ww", "cs", {0} }, { "ww_ww", "ww", {0} } }; - - /* Leg 1: POSITIVE build + run through the `.a` path, both stages. */ - for (int s = 0; s < 2; s++) { - snprintf(stg[s].prog, sizeof stg[s].prog, "%s/prog.%s", td, stg[s].tag); - snprintf(cmd, sizeof cmd, - "timeout 240 %s/%s build -I %s -o %s %s >/dev/null 2>&1", - bin, stg[s].drv, td, stg[s].prog, rootww); - if (runwait(cmd) != 0) { - fprintf(stderr, "separchive FAIL: %s build\n", stg[s].drv); - fail++; - continue; - } - int rc = runwait(stg[s].prog); - if (rc != EXPECT_EXIT) { - fprintf(stderr, "separchive FAIL: %s prog exit=%d expected %d\n", - stg[s].drv, rc, EXPECT_EXIT); - fail++; - } - } - - /* Root is a positional `.o` (force-loaded), so NO __root.a exists; - * the dep is the only `.a`. Assert the layout the driver produced. */ - { - char roota[1100], rooto[1100], helpa[1100]; - snprintf(roota, sizeof roota, "%s/prog.cs.sepwork/__root.a", td); - snprintf(rooto, sizeof rooto, "%s/prog.cs.sepwork/__root.o", td); - snprintf(helpa, sizeof helpa, "%s/prog.cs.sepwork/helper.a", td); - if (access(roota, 0) == 0) { - fprintf(stderr, "separchive FAIL: root wrapped in .a " - "(should stay positional .o)\n"); - fail++; - } - if (access(rooto, 0) != 0) { - fprintf(stderr, "separchive FAIL: missing root .o\n"); - fail++; - } - if (access(helpa, 0) != 0) { - fprintf(stderr, "separchive FAIL: missing dep helper.a\n"); - fail++; - } - } - - /* Leg 3: cs `.a` == ww `.a` (rule 10, the new byte-id substrate). */ - { - char a[1100], b[1100]; - snprintf(a, sizeof a, "%s/prog.cs.sepwork/helper.a", td); - snprintf(b, sizeof b, "%s/prog.ww.sepwork/helper.a", td); - if (files_eq(a, b) != 0) { - fprintf(stderr, "separchive FAIL: cs helper.a != ww helper.a " - "(rule 10 .a byte-id)\n"); - fail++; - } - } - - /* Leg 2: DETERMINISM — re-archive the same package 3× (cold each), - * the `.a` must be byte-identical (zeroed mtime/uid/gid, fixed mode, - * fixed member name). Copy each build's helper.a aside, compare. */ - { - char det[3][1100]; - int ok = 1; - for (int i = 0; i < 3; i++) { - char prog[1100]; - snprintf(prog, sizeof prog, "%s/det%d", td, i); - snprintf(cmd, sizeof cmd, - "timeout 240 %s/ww build -I %s -o %s %s >/dev/null 2>&1", - bin, td, prog, rootww); - if (runwait(cmd) != 0) { ok = 0; break; } - snprintf(det[i], sizeof det[i], "%s/det%d.sepwork/helper.a", td, i); - } - if (!ok) { - fprintf(stderr, "separchive FAIL: determinism build\n"); - fail++; - } else if (files_eq(det[0], det[1]) != 0 || - files_eq(det[1], det[2]) != 0) { - fprintf(stderr, "separchive FAIL: .a not deterministic across " - "3 builds (floating md5 → poisons 5b cache)\n"); - fail++; - } - } - - /* ---- Leg 4: #31 dup THROUGH the `.a` path (PASS 3) --------------- */ - /* Two DEP packages each export the SAME link symbol via @symbol; - * root references both. One member is pulled, the other lands - * UNPULLED defining an already-`defined` name → the masked dup PASS 3 - * catches (#53 path-qualifies normal exports, so @symbol is the - * cleanest forced cross-package clash). */ - char pkgad[1024], pkgbd[1024], paww[1100], pbww[1100], droot[1100]; - snprintf(pkgad, sizeof pkgad, "%s/pkga", td); - snprintf(pkgbd, sizeof pkgbd, "%s/pkgb", td); - if (mkdir(pkgad, 0755) != 0) { - fprintf(stderr, "separchive FAIL: cannot create %s\n", pkgad); - fail++; goto out; - } - have_pkgad = 1; - if (mkdir(pkgbd, 0755) != 0) { - fprintf(stderr, "separchive FAIL: cannot create %s\n", pkgbd); - fail++; goto out; - } - have_pkgbd = 1; - snprintf(paww, sizeof paww, "%s/a.ww", pkgad); - snprintf(pbww, sizeof pbww, "%s/b.ww", pkgbd); - snprintf(droot, sizeof droot, "%s/droot.ww", td); - if (write_file(paww, - "package pkga;\n" - "@symbol(\"dup_sym\") export fn afn() i32 = { return 1; };\n") || - write_file(pbww, - "package pkgb;\n" - "@symbol(\"dup_sym\") export fn bfn() i32 = { return 2; };\n") || - write_file(droot, - "package main;\n" - "import pkga;\n" - "import pkgb;\n" - "fn main() i32 = { return pkga.afn() + pkgb.bfn(); };\n")) { - fail++; goto out; - } - - for (int s = 0; s < 2; s++) { - char prog[1100], errf[1100]; - snprintf(prog, sizeof prog, "%s/dup.%s", td, stg[s].tag); - snprintf(errf, sizeof errf, "%s/dup.%s.err", td, stg[s].tag); - snprintf(cmd, sizeof cmd, - "timeout 240 %s/%s build -I %s -o %s %s >/dev/null 2>%s", - bin, stg[s].drv, td, prog, droot, errf); - int rc = runwait(cmd); - if (rc == 0) { - fprintf(stderr, "separchive FAIL: %s accepted a masked " - "cross-pkg dup through .a (exit 0 — PASS 3 missing?)\n", - stg[s].drv); - fail++; - } - if (!file_has(errf, "duplicate symbol")) { - fprintf(stderr, "separchive FAIL: %s missing 'duplicate " - "symbol' on the .a dup path\n", stg[s].drv); - fail++; - } - if (access(prog, 0) == 0) { - fprintf(stderr, "separchive FAIL: %s produced a partial " - "binary on the dup reject\n", stg[s].drv); - fail++; - } - } - - /* Leg 4 NON-VACUITY: give pkgb a DISTINCT symbol → no collision → - * both stages build + run (exit 3 = 1 + 2). Proves the dup leg - * actually discriminates (not a vacuous always-fail). */ - if (write_file(pbww, - "package pkgb;\n" - "@symbol(\"uniq_sym\") export fn bfn() i32 = { return 2; };\n")) { - fail++; goto out; - } - for (int s = 0; s < 2; s++) { - char prog[1100]; - snprintf(prog, sizeof prog, "%s/ok.%s", td, stg[s].tag); - snprintf(cmd, sizeof cmd, - "timeout 240 %s/%s build -I %s -o %s %s >/dev/null 2>&1", - bin, stg[s].drv, td, prog, droot); - if (runwait(cmd) != 0) { - fprintf(stderr, "separchive FAIL(non-vacuity): %s could not " - "build the distinct-symbol graph\n", stg[s].drv); - fail++; - continue; - } - int rc = runwait(prog); - if (rc != 3) { - fprintf(stderr, "separchive FAIL(non-vacuity): %s prog " - "exit=%d expected 3\n", stg[s].drv, rc); - fail++; - } - } - -out: - snprintf(cmd, sizeof cmd, - "rm -rf -- '%s/prog.cs.sepwork' '%s/prog.ww.sepwork' " - "'%s/det0.sepwork' '%s/det1.sepwork' '%s/det2.sepwork' " - "'%s/dup.cs.sepwork' '%s/dup.ww.sepwork' " - "'%s/ok.cs.sepwork' '%s/ok.ww.sepwork'", - td, td, td, td, td, td, td, td, td); - if (runwait(cmd) != 0) { - fprintf(stderr, "separchive FAIL: cannot clean .sepwork trees\n"); - fail++; - } - { - char path[1200]; - snprintf(path, sizeof path, "%s/root.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/droot.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/prog.cs", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/prog.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/det0", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/det1", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/det2", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/dup.cs", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/dup.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/dup.cs.err", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/dup.ww.err", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/ok.cs", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/ok.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); fail++; } - } - if (have_helpdir) { - if (unlink(helpww) != 0 && errno != ENOENT) { - fprintf(stderr, "separchive FAIL: cannot remove %s\n", helpww); - fail++; - } - } - if (have_pkgad) { - char path[1200]; - snprintf(path, sizeof path, "%s/a.ww", pkgad); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); - fail++; - } - } - if (have_pkgbd) { - char path[1200]; - snprintf(path, sizeof path, "%s/b.ww", pkgbd); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "separchive FAIL: cannot remove %s\n", path); - fail++; - } - } - if (have_helpdir && rmdir(helpdir) != 0 && errno != ENOENT) { - fprintf(stderr, "separchive FAIL: cannot remove %s\n", helpdir); - fail++; - } - if (have_pkgad && rmdir(pkgad) != 0 && errno != ENOENT) { - fprintf(stderr, "separchive FAIL: cannot remove %s\n", pkgad); - fail++; - } - if (have_pkgbd && rmdir(pkgbd) != 0 && errno != ENOENT) { - fprintf(stderr, "separchive FAIL: cannot remove %s\n", pkgbd); - fail++; - } - if (rmdir(td) != 0 && errno != ENOENT) { - fprintf(stderr, "separchive FAIL: cannot remove %s\n", td); - fail++; - } - if (fail) { - fprintf(stderr, "separchive: %d check(s) failed\n", fail); - return 1; - } - printf("separchive: per-pkg .a (root=.o force-load, deps=.a) build+run " - "(exit %d) + .a determinism (3x identical) + cs.a==ww.a (rule 10) + " - "#31 masked-dup reject THROUGH .a (PASS 3, both stages loud+non-zero, " - "non-vacuity flip exit 3)\n", EXPECT_EXIT); - return 0; -} diff --git a/test/wcc/989_sepcycle_dup.c b/test/wcc/989_sepcycle_dup.c deleted file mode 100644 index efb9861c..00000000 --- a/test/wcc/989_sepcycle_dup.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * 989_sepcycle_dup — M3-tail commit-4 negative gates (#46, #31). - * - * Two error PATHS the commit-4 link-hardening relies on, each asserted to - * ACTUALLY FIRE (ken #263: a happy-path-green run does not prove a reject - * works — a no-op reject ships green). Every negative leg asserts - * (exit != 0) AND (the expected stderr message) AND a non-vacuity flip - * (remove the defect → green), so the gate cannot pass for the wrong - * reason. - * - * A. LOUD dep-cycle reject (spec §2, Hare deps.ha:243). A 3-package - * import cycle root->A->B->C->A fed to `ww build` must exit - * non-zero, print the `dependency cycle: A -> B -> C -> A` chain, and - * produce NO output binary. cs==ww (rule 10): the cycle message is - * pure driver code, so cstage `ww` and wwstage `ww_ww` emit - * BYTE-IDENTICAL stderr — asserted here. Non-vacuity: break the cycle - * (C stops importing A) → both stages build green and the program - * runs (exit 7). - * - * B. #31 duplicate-symbol reject (spec §3; w6l ALREADY detects it, this - * gate only proves it fires). Two trivial root units each define a - * bare `main` (the #31 bare-collision class — #53 path-qualifies - * normal exports, so `main` is the cleanest bare clash); both `.o` - * fed directly to `w6l` AND `w6l_ww` must exit non-zero with a - * `duplicate symbol` message. Non-vacuity: link a single `.o` - * (+ libwwrt.a) → clean link, runs. - * NOTE on parity: w6l and w6l_ww BOTH reject loud + non-zero and both - * name "duplicate symbol", but the EXACT text differs — cstage adds - * the path+symbol (`w6l: u2.o: duplicate symbol main`), wwstage prints - * the bare `w6l: duplicate symbol`. That is a PRE-EXISTING w6l_ww vs - * w6l message divergence on the reject path (byte-id-blind); commit 4 - * adds NO linker code and must hold w6l_ww byte-identical, so it is - * NOT reconciled here. The gate asserts the achievable reject parity: - * both exit != 0 AND both stderr contain "duplicate symbol". The - * text-divergence is filed (see report) for a sibling linker task. - * - * Light wwstage-driver test (CLAUDE.md rule 14): all fixtures + scratch - * live under /tmp, COLD each run. Models 989_sepbuild_run.c conventions. - */ -#include -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return 1; -} - -static const char * -absbin(void) -{ - const char *b = getenv("BIN"); - if (!b) b = "out/bin"; - if (b[0] == '/') return b; - static char buf[2048]; - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return NULL; - snprintf(buf, sizeof buf, "%s/%s", cwd, b); - return buf; -} - -static int -slurp(const char *path, char **outbuf, size_t *outlen) -{ - FILE *f = fopen(path, "rb"); - if (!f) return -1; - fseek(f, 0, SEEK_END); - long n = ftell(f); - fseek(f, 0, SEEK_SET); - if (n < 0) { fclose(f); return -1; } - char *b = malloc((size_t)n + 1); - if (!b) { fclose(f); return -1; } - if (fread(b, 1, (size_t)n, f) != (size_t)n) { free(b); fclose(f); return -1; } - b[n] = '\0'; - fclose(f); - *outbuf = b; - *outlen = (size_t)n; - return 0; -} - -static int -files_eq(const char *a, const char *b) -{ - char *ba = NULL, *bb = NULL; - size_t na = 0, nb = 0; - if (slurp(a, &ba, &na) < 0 || slurp(b, &bb, &nb) < 0) { - free(ba); free(bb); - return -1; - } - int eq = (na == nb && memcmp(ba, bb, na) == 0); - free(ba); free(bb); - return eq ? 0 : 1; -} - -/* True iff file `path` contains the literal substring `needle`. */ -static int -file_has(const char *path, const char *needle) -{ - char *b = NULL; - size_t n = 0; - if (slurp(path, &b, &n) < 0) return 0; - int found = (strstr(b, needle) != NULL); - free(b); - return found; -} - -static int -write_file(const char *path, const char *body) -{ - FILE *f = fopen(path, "wb"); - if (!f) return -1; - fputs(body, f); - fclose(f); - return 0; -} - -int -main(void) -{ - const char *bin = absbin(); - if (!bin) return 1; - char td[64], cmd[8192]; - int fail = 0, have_dira = 0, have_dirb = 0, have_dirc = 0; - - snprintf(td, sizeof td, "/tmp/wwcd_%d", getpid()); - if (mkdir(td, 0755) != 0) { - fprintf(stderr, "sepcycle_dup FAIL: cannot acquire %s\n", td); - return 1; - } - - /* ---- A. dep-cycle reject ----------------------------------------- */ - char rootww[1024], dira[1024], dirb[1024], dirc[1024], fa[1100], - fb[1100], fc[1100]; - snprintf(rootww, sizeof rootww, "%s/root.ww", td); - snprintf(dira, sizeof dira, "%s/pkga", td); - snprintf(dirb, sizeof dirb, "%s/pkgb", td); - snprintf(dirc, sizeof dirc, "%s/pkgc", td); - if (mkdir(dira, 0755) != 0) { - fprintf(stderr, "sepcycle_dup FAIL: cannot create %s\n", dira); - fail++; goto out; - } - have_dira = 1; - if (mkdir(dirb, 0755) != 0) { - fprintf(stderr, "sepcycle_dup FAIL: cannot create %s\n", dirb); - fail++; goto out; - } - have_dirb = 1; - if (mkdir(dirc, 0755) != 0) { - fprintf(stderr, "sepcycle_dup FAIL: cannot create %s\n", dirc); - fail++; goto out; - } - have_dirc = 1; - snprintf(fa, sizeof fa, "%s/a.ww", dira); - snprintf(fb, sizeof fb, "%s/b.ww", dirb); - snprintf(fc, sizeof fc, "%s/c.ww", dirc); - if (write_file(rootww, - "package main;\n" - "import pkga;\n" - "fn main() i32 = { return pkga.av(); };\n") || - write_file(fa, - "package pkga;\n" - "import pkgb;\n" - "export fn av() i32 = { return pkgb.bv(); };\n") || - write_file(fb, - "package pkgb;\n" - "import pkgc;\n" - "export fn bv() i32 = { return pkgc.cv(); };\n") || - write_file(fc, - "package pkgc;\n" - "import pkga;\n" - "export fn cv() i32 = { return pkga.av(); };\n")) { - fail++; goto out; - } - - struct { const char *drv, *tag; } stg[] = { - { "ww", "cs" }, { "ww_ww", "ww" } - }; - char cerr_path[2][1100]; - for (int s = 0; s < 2; s++) { - char prog[1100], errf[1100]; - snprintf(prog, sizeof prog, "%s/prog.%s", td, stg[s].tag); - snprintf(errf, sizeof errf, "%s/cyc.%s.err", td, stg[s].tag); - snprintf(cerr_path[s], sizeof cerr_path[s], "%s", errf); - snprintf(cmd, sizeof cmd, - "%s/%s build -o %s %s >/dev/null 2>%s", - bin, stg[s].drv, prog, rootww, errf); - int rc = runwait(cmd); - if (rc == 0) { - fprintf(stderr, "cycle FAIL: %s build returned 0 " - "(no-op reject)\n", stg[s].drv); - fail++; - } - if (!file_has(errf, "dependency cycle: pkga -> pkgb -> pkgc -> pkga")) { - fprintf(stderr, "cycle FAIL: %s missing cycle-chain " - "message\n", stg[s].drv); - fail++; - } - if (access(prog, 0) == 0) { - fprintf(stderr, "cycle FAIL: %s produced a partial " - "binary %s\n", stg[s].drv, prog); - fail++; - } - } - /* cs==ww (rule 10): the cycle message is pure driver code → stderr - * byte-identical between the two stages. */ - if (files_eq(cerr_path[0], cerr_path[1]) != 0) { - fprintf(stderr, "cycle FAIL: cs stderr != ww stderr (rule 10)\n"); - fail++; - } - - /* Non-vacuity: break the cycle → both stages build + run (exit 7). */ - if (write_file(fc, - "package pkgc;\n" - "export fn cv() i32 = { return 7; };\n")) { - fail++; goto out; - } - for (int s = 0; s < 2; s++) { - char prog[1100]; - snprintf(prog, sizeof prog, "%s/ok.%s", td, stg[s].tag); - snprintf(cmd, sizeof cmd, - "%s/%s build -o %s %s >/dev/null 2>&1", - bin, stg[s].drv, prog, rootww); - if (runwait(cmd) != 0) { - fprintf(stderr, "cycle FAIL(non-vacuity): %s could not " - "build the acyclic graph\n", stg[s].drv); - fail++; - continue; - } - int rc = runwait(prog); - if (rc != 7) { - fprintf(stderr, "cycle FAIL(non-vacuity): %s prog exit=%d " - "expected 7\n", stg[s].drv, rc); - fail++; - } - } - - /* ---- B. #31 duplicate-symbol reject ------------------------------ */ - char u1[1100], u2[1100], s1[1100], s2[1100], o1[1100], o2[1100]; - snprintf(u1, sizeof u1, "%s/u1.ww", td); - snprintf(u2, sizeof u2, "%s/u2.ww", td); - snprintf(s1, sizeof s1, "%s/u1.s", td); - snprintf(s2, sizeof s2, "%s/u2.s", td); - snprintf(o1, sizeof o1, "%s/u1.o", td); - snprintf(o2, sizeof o2, "%s/u2.o", td); - if (write_file(u1, "package main;\nfn main() i32 = { return 0; };\n") || - write_file(u2, "package main;\nfn main() i32 = { return 1; };\n")) { - fail++; goto out; - } - snprintf(cmd, sizeof cmd, "%s/w6c -c -o %s %s && %s/w6a -o %s %s", - bin, s1, u1, bin, o1, s1); - if (runwait(cmd) != 0) { fprintf(stderr, "dup FAIL: build u1.o\n"); fail++; goto out; } - snprintf(cmd, sizeof cmd, "%s/w6c -c -o %s %s && %s/w6a -o %s %s", - bin, s2, u2, bin, o2, s2); - if (runwait(cmd) != 0) { fprintf(stderr, "dup FAIL: build u2.o\n"); fail++; goto out; } - - /* Both linkers must reject the dup loud + non-zero. */ - const char *lnk[] = { "w6l", "w6l_ww" }; - for (int i = 0; i < 2; i++) { - char errf[1100], prog[1100]; - snprintf(errf, sizeof errf, "%s/dup.%s.err", td, lnk[i]); - snprintf(prog, sizeof prog, "%s/dupprog.%s", td, lnk[i]); - snprintf(cmd, sizeof cmd, "%s/%s -o %s %s %s >/dev/null 2>%s", - bin, lnk[i], prog, o1, o2, errf); - int rc = runwait(cmd); - if (rc == 0) { - fprintf(stderr, "dup FAIL: %s accepted a duplicate " - "symbol (exit 0)\n", lnk[i]); - fail++; - } - if (!file_has(errf, "duplicate symbol")) { - fprintf(stderr, "dup FAIL: %s missing 'duplicate symbol' " - "message\n", lnk[i]); - fail++; - } - if (access(prog, 0) == 0) { - fprintf(stderr, "dup FAIL: %s produced a partial binary " - "%s on the reject path\n", lnk[i], prog); - fail++; - } - } - - /* Non-vacuity: a single .o + libwwrt.a links clean and runs. */ - { - char rt[1100], prog[1100]; - snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin); - for (int i = 0; i < 2; i++) { - snprintf(prog, sizeof prog, "%s/single.%s", td, lnk[i]); - snprintf(cmd, sizeof cmd, "%s/%s -o %s %s %s >/dev/null 2>&1", - bin, lnk[i], prog, o1, rt); - if (runwait(cmd) != 0) { - fprintf(stderr, "dup FAIL(non-vacuity): %s could " - "not link a single .o\n", lnk[i]); - fail++; - continue; - } - if (runwait(prog) != 0) { - fprintf(stderr, "dup FAIL(non-vacuity): %s single " - "prog did not run clean\n", lnk[i]); - fail++; - } - } - } - -out: - snprintf(cmd, sizeof cmd, - "rm -rf -- '%s/prog.cs.sepwork' '%s/prog.ww.sepwork' " - "'%s/ok.cs.sepwork' '%s/ok.ww.sepwork'", td, td, td, td); - if (runwait(cmd) != 0) { - fprintf(stderr, "sepcycle_dup FAIL: cannot clean .sepwork trees\n"); - fail++; - } - { - char path[1200]; - snprintf(path, sizeof path, "%s/root.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/prog.cs", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/prog.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/cyc.cs.err", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/cyc.ww.err", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/ok.cs", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/ok.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/u1.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/u2.ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/u1.s", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/u2.s", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/u1.o", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/u2.o", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/dup.w6l.err", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/dup.w6l_ww.err", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/dupprog.w6l", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/dupprog.w6l_ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/single.w6l", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - snprintf(path, sizeof path, "%s/single.w6l_ww", td); - if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); fail++; } - } - if (have_dira) { - char path[1200]; - snprintf(path, sizeof path, "%s/a.ww", dira); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); - fail++; - } - } - if (have_dirb) { - char path[1200]; - snprintf(path, sizeof path, "%s/b.ww", dirb); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); - fail++; - } - } - if (have_dirc) { - char path[1200]; - snprintf(path, sizeof path, "%s/c.ww", dirc); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", path); - fail++; - } - } - if (have_dira && rmdir(dira) != 0 && errno != ENOENT) { - fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", dira); - fail++; - } - if (have_dirb && rmdir(dirb) != 0 && errno != ENOENT) { - fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", dirb); - fail++; - } - if (have_dirc && rmdir(dirc) != 0 && errno != ENOENT) { - fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", dirc); - fail++; - } - if (rmdir(td) != 0 && errno != ENOENT) { - fprintf(stderr, "sepcycle_dup FAIL: cannot remove %s\n", td); - fail++; - } - if (fail) { - fprintf(stderr, "sepcycle_dup: %d check(s) failed\n", fail); - return 1; - } - printf("sepcycle_dup: dep-cycle reject (chain named, cs==ww stderr, no " - "partial binary, non-vacuity flip) + #31 dup-symbol reject (w6l & " - "w6l_ww loud+non-zero, non-vacuity single-.o link)\n"); - return 0; -}