From af0f56dfe5d0e2c3f163b99a4819c20965b9bfd1 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 13 Aug 2026 13:36:20 +0900 Subject: [PATCH] test: make dynamic linker parity observer self-contained --- test/wcc/996_dyn_ww.c | 101 +++++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 25 deletions(-) diff --git a/test/wcc/996_dyn_ww.c b/test/wcc/996_dyn_ww.c index cd6858e7..076379d8 100644 --- a/test/wcc/996_dyn_ww.c +++ b/test/wcc/996_dyn_ww.c @@ -2,7 +2,8 @@ * Phase-8 marker for ET_DYN linking on the ww side: a green run means * the ww-side linker emits PT_INTERP/PT_DYNAMIC binaries byte-for-byte * identical to the C linker on the same inputs — i.e. the dynamic - * linking story is fully ported. + * linking story is fully ported. The input is generated privately so the + * platform gate owns its complete source and artifact lifecycle. */ #include #include @@ -61,31 +62,70 @@ main(void) char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; - /* #93 sep layout: build the example via `ww build` into a - * 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], 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()); + const char *libdir = NULL; + if (access("/usr/lib/libc.so.6", 0) == 0) + libdir = "/usr/lib"; + else if (access("/lib/x86_64-linux-gnu/libc.so.6", 0) == 0) + libdir = "/lib/x86_64-linux-gnu"; + else if (access("/lib64/libc.so.6", 0) == 0) + libdir = "/lib64"; + if (libdir == NULL) { + puts("w6l_ww-dyn: no libc.so.6 on this system — skipping"); + return 77; + } + + char td[] = "/tmp/wwld_XXXXXX"; + if (mkdtemp(td) == NULL) { + perror("w6l_ww-dyn mkdtemp"); + return 1; + } + + /* #93 sep layout: build an explicit command source via `ww build`, + * then independently link .sepwork/__root.o with both linkers. + * The direct getpid call guarantees one dynamic libc relocation. */ + char cmd[4096], src[256], stem[256], scratch[320]; + char obj[384], co[256], wo[256]; + snprintf(src, sizeof src, "%s/dyn.ww", td); + snprintf(stem, sizeof stem, "%s/built", td); + snprintf(scratch, sizeof scratch, "%s.sepwork", stem); + snprintf(obj, sizeof obj, "%s/__root.o", scratch); + snprintf(co, sizeof co, "%s/c", td); + snprintf(wo, sizeof wo, "%s/w", td); 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"); + FILE *f = fopen(src, "wb"); + if (f == NULL) { + fprintf(stderr, "w6l_ww-dyn FAIL: cannot create generated source\n"); + rc = 1; + goto cleanup; + } + fputs("package main;\n" + "@symbol(\"getpid\") fn cgetpid() i32;\n" + "export fn main() i32 = {\n" + "\tif (cgetpid() < 0) { return 1; };\n" + "\treturn 0;\n" + "};\n", f); + int writebad = ferror(f); + if (fclose(f) != 0) writebad = 1; + if (writebad) { + fprintf(stderr, "w6l_ww-dyn FAIL: cannot write generated source\n"); rc = 1; goto cleanup; } snprintf(cmd, sizeof cmd, - "%s/w6l -o %s %s -L /usr/lib " + "%s/ww build -o %s %s -L %s -l c >/dev/null 2>&1", + bin, stem, src, libdir); + if (runwait(cmd) != 0) { + fprintf(stderr, "w6l_ww-dyn FAIL: cannot build generated command\n"); + rc = 1; + goto cleanup; + } + + snprintf(cmd, sizeof cmd, + "%s/w6l -o %s %s -L %s " "-l c %s/out/lib/libwwrt.a 2>/dev/null", - bin, co, mbobj, cwd); + bin, co, obj, libdir, cwd); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww-dyn FAIL: C w6l errored\n"); rc = 1; @@ -93,9 +133,9 @@ main(void) } snprintf(cmd, sizeof cmd, - "%s/w6l_ww -o %s %s -L /usr/lib " + "%s/w6l_ww -o %s %s -L %s " "-l c %s/out/lib/libwwrt.a 2>/dev/null", - bin, wo, mbobj, cwd); + bin, wo, obj, libdir, cwd); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww-dyn FAIL: ww w6l errored\n"); rc = 1; @@ -114,17 +154,28 @@ main(void) fprintf(stderr, "w6l_ww-dyn FAIL: C %zu vs ww %zu bytes\n", nc, nw); rc = 1; + } else if (runwait(co) != 0 || runwait(wo) != 0) { + fprintf(stderr, "w6l_ww-dyn FAIL: linked command did not run\n"); + rc = 1; } else { - printf("w6l_ww-dyn: byte-identical to C w6l on mandelbrot " + printf("w6l_ww-dyn: byte-identical to C w6l on generated command " "(PT_INTERP + PT_DYNAMIC + .rela.plt + .gnu.version_r, " "%zu bytes)\n", nc); } free(bc); free(bw); cleanup: - /* #93: `ww build` retains this exact caller-owned scratch tree. */ - snprintf(cmd, sizeof cmd, "rm -rf %s.sepwork", mbstem); + /* `ww build` retains this exact mkdtemp-owned scratch child. */ + snprintf(cmd, sizeof cmd, "rm -rf -- %s", scratch); int cleanfail = runwait(cmd) != 0; + if (unlink(src) != 0 && errno != ENOENT) { + perror(src); + cleanfail = 1; + } + if (unlink(stem) != 0 && errno != ENOENT) { + perror(stem); + cleanfail = 1; + } if (unlink(co) != 0 && errno != ENOENT) { perror(co); cleanfail = 1; @@ -133,8 +184,8 @@ cleanup: perror(wo); cleanfail = 1; } - if (unlink(mbstem) != 0 && errno != ENOENT) { - perror(mbstem); + if (rmdir(td) != 0) { + perror(td); cleanfail = 1; } if (cleanfail && rc == 0)