/* * 989_wwdumpgate_run (#52, F15 c4) — wwdump_ww's `-c` and `-r` arms must gate * on parse-stage errors instead of silently emitting on a broken AST. * * THE BUG (wwstage wwdump_ww only, cat-A silent wrong output under rc=0): the * `-c` codegen arm ran checkfile+cgfile with NO parse-error gate — ps.errs * was never read — so a parse-errored decl was silently dropped from the AST * and the rest of the file compiled to asm with exit 0 (and `-c` IS the 994 * byte-identity probe, so the gate tool itself could ship wrong asm silently). * The `-r` resolve report arm was likewise ungated. THE FIX: add the * `l.errs>0 || ps.errs>0` gate after parsefile in both arms, mirroring the * w6c compiler gate (selfhost/cmd/w6c/main.ww:162 / cmd/w6c/main.c). * * WWSTAGE-ONLY: the C wwdump (cstage) implements only -t/-a, not -c/-r — the * codegen/resolve dump arms are a wwstage-wwdump_ww feature, so there is no * cstage -c/-r twin to diff against; the gate reference is the w6c compiler. * * row | mode | input | result * -------+------+---------------+---------------------------------- * bad_c | -c | parse error | rc != 0, zero asm bytes * bad_r | -r | parse error | rc != 0 * ok_c | -c | valid file | rc == 0, asm emitted (control) * * bad_c / bad_r were RED pre-c4 (rc=0 with truncated asm / a resolve report). * ok_c pins the healthy emission path unperturbed. */ #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 *BAD = "package main;\n\n" "export fn main(argc: i32, argv: **u8) i32 = {\n\treturn 0;\n};\n\n" "fn broken( {\n"; static const char *OK = "package main;\nexport fn main() i32 = { return 0; };\n"; /* Run ` ` capturing asm on stdout; returns rc, sets * *asmbytes to the stdout byte count when non-NULL. */ static int run_dump(const char *tool, const char *mode, const char *src, long *asmbytes) { char outp[128], cmd[1024]; snprintf(outp, sizeof outp, "/tmp/wwdg_%d_out", getpid()); snprintf(cmd, sizeof cmd, "%s %s %s > %s 2>/dev/null", tool, mode, src, outp); int rc = runwait(cmd); if (asmbytes) { FILE *f = fopen(outp, "rb"); long n = 0; if (f) { fseek(f, 0, SEEK_END); n = ftell(f); fclose(f); } *asmbytes = n; } unlink(outp); return rc; } 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 = getenv("BIN"); if (!bin) bin = "out/bin"; char absbin[1024]; if (bin[0] != '/') { char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); bin = absbin; } char wtool[1024]; snprintf(wtool, sizeof wtool, "%s/wwdump_ww", bin); if (access(wtool, X_OK) != 0) { /* wwdump_ww is the unit under test; absence is a wiring fault. */ fprintf(stderr, "wwdumpgate: missing %s\n", wtool); return 1; } char badp[64], okp[64]; snprintf(badp, sizeof badp, "/tmp/wwdg_bad_%d.ww", getpid()); snprintf(okp, sizeof okp, "/tmp/wwdg_ok_%d.ww", getpid()); if (write_file(badp, BAD) || write_file(okp, OK)) return 1; int fail = 0, total = 0; long ab; /* bad_c: loud, zero asm */ total++; if (run_dump(wtool, "-c", badp, &ab) == 0 || ab != 0) { fprintf(stderr, "wwdumpgate[bad_c]: emitted asm with rc=0 on " "parse-errored input (#52); asm=%ld\n", ab); fail++; } /* bad_r: loud */ total++; if (run_dump(wtool, "-r", badp, NULL) == 0) { fprintf(stderr, "wwdumpgate[bad_r]: resolve report with rc=0 on " "parse-errored input (#52)\n"); fail++; } /* ok_c control: rc=0 with asm */ total++; if (run_dump(wtool, "-c", okp, &ab) != 0 || ab <= 0) { fprintf(stderr, "wwdumpgate[ok_c]: healthy file rejected/no asm " "(asm=%ld)\n", ab); fail++; } unlink(badp); unlink(okp); if (fail) { fprintf(stderr, "wwdumpgate_run: %d/%d check(s) failed\n", fail, total); return 1; } printf("wwdumpgate_run: %d/%d ok\n", total, total); return 0; }