w6a/ww: DATAR naming an undefined slot is a loud reject
A DATAR relocation against an undefined data slot was silently dropped — the relocation vanished from the object. Reject loudly, matching the cstage single-pass resolution behavior.
This commit is contained in:
9
Makefile
9
Makefile
@@ -264,6 +264,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
|
||||
$(BIN)/test_loopcap_run \
|
||||
$(BIN)/test_enumcap_run \
|
||||
$(BIN)/test_wwdumpgate_run \
|
||||
$(BIN)/test_datargate_run \
|
||||
$(BIN)/test_ampfncollide_run \
|
||||
$(BIN)/test_trycallcollide_run \
|
||||
$(BIN)/test_gunsigned_run \
|
||||
@@ -837,6 +838,14 @@ $(BIN)/test_wwdumpgate_run: test/wcc/989_wwdumpgate_run.c \
|
||||
$(BIN)/wwdump $(BIN)/wwdump_ww | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
# 989_datargate_run (#59, F15 c5): w6a loud-rejects a DATAR relocation whose
|
||||
# slot was never defined by a prior DATAW instead of silently dropping the
|
||||
# reloc (zero-filled pointer slot in the .o). Runs w6a + w6a_ww directly and
|
||||
# asserts a byte-identical .o on the healthy path (rule-10). See the header.
|
||||
$(BIN)/test_datargate_run: test/wcc/989_datargate_run.c \
|
||||
$(BIN)/w6a $(BIN)/w6a_ww | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
# 989_ampfncollide_run (#4, c2): `&fn` synthesis (unoptype TK_AMP +
|
||||
# assignableaddrfn) prefers the current module's fn when a same-leaf fn is
|
||||
# declared in a later module. Builds/rejects on BOTH driver twins (rule-10).
|
||||
|
||||
@@ -300,10 +300,17 @@ export fn encode(a: *asm_) i32 = {
|
||||
// pointing at target. Slot must already be defined
|
||||
// by a prior DATAW.
|
||||
let holder: *asym = intern(a, p.from.asym);
|
||||
if (holder.defined == 0) {
|
||||
p = p.link; continue;
|
||||
};
|
||||
if (holder.isdata == 0) {
|
||||
// #59: a DATAR slot with no prior DATAW definition must be
|
||||
// a loud error, not a silently dropped relocation (the .o
|
||||
// would ship a zero-filled pointer slot — a null pointer at
|
||||
// link/runtime). Mirrors cmd/w6a/asm.c:363 (errs++ → main
|
||||
// returns 1 before opening the output, so no .o is written).
|
||||
if (holder.defined == 0 || holder.isdata == 0) {
|
||||
let msg: str = "w6a: DATAR slot not yet defined as DATAW: ";
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.write(2, p.from.asym.ptr, p.from.asym.len: u64);
|
||||
os.write(2, "\n".ptr, 1u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
let target: *asym = intern(a, p.to.asym);
|
||||
|
||||
@@ -4023,10 +4023,17 @@ export fn encode(a: *asm_) i32 = {
|
||||
// pointing at target. Slot must already be defined
|
||||
// by a prior DATAW.
|
||||
let holder: *asym = intern(a, p.from.asym);
|
||||
if (holder.defined == 0) {
|
||||
p = p.link; continue;
|
||||
};
|
||||
if (holder.isdata == 0) {
|
||||
// #59: a DATAR slot with no prior DATAW definition must be
|
||||
// a loud error, not a silently dropped relocation (the .o
|
||||
// would ship a zero-filled pointer slot — a null pointer at
|
||||
// link/runtime). Mirrors cmd/w6a/asm.c:363 (errs++ → main
|
||||
// returns 1 before opening the output, so no .o is written).
|
||||
if (holder.defined == 0 || holder.isdata == 0) {
|
||||
let msg: str = "w6a: DATAR slot not yet defined as DATAW: ";
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.write(2, p.from.asym.ptr, p.from.asym.len: u64);
|
||||
os.write(2, "\n".ptr, 1u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
let target: *asym = intern(a, p.to.asym);
|
||||
|
||||
139
test/wcc/989_datargate_run.c
Normal file
139
test/wcc/989_datargate_run.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 989_datargate_run (#59, F15 c5) — w6a must loud-reject a DATAR relocation
|
||||
* whose slot was never defined by a prior DATAW, not silently drop the reloc.
|
||||
*
|
||||
* THE BUG (wwstage w6a only, cat-A silent wrong output under rc=0): asm.ww's
|
||||
* A_DATAR arm, when holder.defined==0 or holder.isdata==0, did `p = p.link;
|
||||
* continue;` with no diagnostic and no errs++ — so the R_X86_64_64 .data
|
||||
* relocation was silently dropped and a rc=0 .o was emitted with a zero-filled
|
||||
* pointer slot (a null pointer at link/runtime). The cstage twin (cmd/w6a/
|
||||
* asm.c:363) printed a diagnostic + a->errs++, and main returns 1 before
|
||||
* opening the output, so no .o is written. THE FIX: emit a diagnostic and bump
|
||||
* a.errs (encode returns a.errs → main returns 1 before writing the .o).
|
||||
*
|
||||
* row | shape | result (cs & ww agree)
|
||||
* ----+-------------------------------+--------------------------------
|
||||
* bad | DATAR on a slot with no DATAW | rc != 0, no .o written
|
||||
* ok | DATAW then DATAR on that slot | rc == 0, .o byte-identical (cs==ww)
|
||||
*
|
||||
* bad was RED pre-c5 on wwstage (rc=0, .o with the reloc silently dropped).
|
||||
* ok pins the defined-slot path: both stages rc=0 and a byte-identical .o.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
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 =
|
||||
"TEXT f,$0\n\tRET\n\tDATAR x+0(SB), f(SB)\n";
|
||||
static const char *OK =
|
||||
"TEXT f,$0\n\tRET\n"
|
||||
"DATAW x(SB),\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n"
|
||||
"\tDATAR x+0(SB), f(SB)\n";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Assemble `src` with `tool` into `obj` (removed first). Returns rc; sets
|
||||
* *exists to whether the .o was created. */
|
||||
static int
|
||||
assemble(const char *tool, const char *src, const char *obj, int *exists)
|
||||
{
|
||||
char cmd[1024];
|
||||
unlink(obj);
|
||||
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", tool, obj, src);
|
||||
int rc = runwait(cmd);
|
||||
if (exists) *exists = (access(obj, F_OK) == 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
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 ctool[1024], wtool[1024];
|
||||
snprintf(ctool, sizeof ctool, "%s/w6a", bin);
|
||||
snprintf(wtool, sizeof wtool, "%s/w6a_ww", bin);
|
||||
int have_ww = (access(wtool, X_OK) == 0);
|
||||
if (!have_ww)
|
||||
fprintf(stderr, "datargate: skip wwstage (no %s)\n", wtool);
|
||||
|
||||
char bads[64], oks[64], co[64], wo[64];
|
||||
snprintf(bads, sizeof bads, "/tmp/datarg_bad_%d.s", getpid());
|
||||
snprintf(oks, sizeof oks, "/tmp/datarg_ok_%d.s", getpid());
|
||||
snprintf(co, sizeof co, "/tmp/datarg_c_%d.o", getpid());
|
||||
snprintf(wo, sizeof wo, "/tmp/datarg_w_%d.o", getpid());
|
||||
if (write_file(bads, BAD) || write_file(oks, OK)) return 1;
|
||||
|
||||
int fail = 0, total = 0, ex;
|
||||
|
||||
/* bad: both stages loud, no .o */
|
||||
total++;
|
||||
if (assemble(ctool, bads, co, &ex) == 0 || ex) {
|
||||
fprintf(stderr, "datargate[cstage][bad]: rc=0/.o written on "
|
||||
"undefined DATAR slot\n");
|
||||
fail++;
|
||||
}
|
||||
if (have_ww) {
|
||||
if (assemble(wtool, bads, wo, &ex) == 0 || ex) {
|
||||
fprintf(stderr, "datargate[wwstage][bad]: rc=0/.o written on "
|
||||
"undefined DATAR slot — reloc silently dropped (#59)\n");
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ok: both stages rc=0, byte-identical .o */
|
||||
total++;
|
||||
int crc = assemble(ctool, oks, co, &ex);
|
||||
if (crc != 0 || !ex) {
|
||||
fprintf(stderr, "datargate[cstage][ok]: rc=%d .o=%d\n", crc, ex);
|
||||
fail++;
|
||||
}
|
||||
if (have_ww) {
|
||||
int wrc = assemble(wtool, oks, wo, &ex);
|
||||
if (wrc != 0 || !ex) {
|
||||
fprintf(stderr, "datargate[wwstage][ok]: rc=%d .o=%d\n", wrc, ex);
|
||||
fail++;
|
||||
}
|
||||
char cmp[1024];
|
||||
snprintf(cmp, sizeof cmp, "cmp -s %s %s", co, wo);
|
||||
if (runwait(cmp) != 0) {
|
||||
fprintf(stderr, "datargate[ok]: cs/ww .o differ (#59)\n");
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
unlink(bads); unlink(oks); unlink(co); unlink(wo);
|
||||
|
||||
if (fail) {
|
||||
fprintf(stderr, "datargate_run: %d check(s) failed\n", fail);
|
||||
return 1;
|
||||
}
|
||||
printf("datargate_run: %d/%d ok\n", total, total);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user