From 059550e00fd063f6e8138dff644701c7e811f730 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 13 Aug 2026 08:19:29 +0900 Subject: [PATCH] ww: make allocation failures stage-equivalent --- cmd/ww/main.c | 72 ++++++++++++++++++++++++++++++++--------- selfhost/cmd/ww/main.ww | 58 +++++++++++++++++++++++---------- 2 files changed, 97 insertions(+), 33 deletions(-) diff --git a/cmd/ww/main.c b/cmd/ww/main.c index acb9a946..514b3293 100644 --- a/cmd/ww/main.c +++ b/cmd/ww/main.c @@ -1728,8 +1728,14 @@ sep_scan_file(struct sepgraph *g, int pi, const char *file, break; } { + errno = 0; char *canon = realpath(ipath, NULL); if (canon == NULL) { + if (errno == ENOMEM) { + sep_fail_nomem(); + rc = -1; + break; + } errorf(u->pos, "cannot canonicalize package '%s'", name); rc = -1; break; @@ -2130,8 +2136,12 @@ sep_reverse_import_base(const struct sepgraph *g, const struct seppkg *pkg, if (root == NULL) return sep_fail_nomem(); memcpy(root, p, n); root[n] = '\0'; + errno = 0; char *canon = n == 0 ? NULL : realpath(root, NULL); + int canon_errno = n == 0 ? 0 : errno; free(root); + if (canon == NULL && canon_errno == ENOMEM) + return sep_fail_nomem(); if (canon != NULL) { size_t rn = strlen(canon); const char *rel = NULL; @@ -2149,9 +2159,16 @@ sep_reverse_import_base(const struct sepgraph *g, const struct seppkg *pkg, char located[PATH_MAX]; if (locate_import(searchpath, rel, located, sizeof located)) { + errno = 0; char *selected = realpath(located, NULL); + int selected_errno = errno; int same = selected != NULL && strcmp(selected, pkg->canon) == 0; + if (selected == NULL + && selected_errno == ENOMEM) { + free(canon); + return sep_fail_nomem(); + } free(selected); if (same) { free(canon); return 1; } } @@ -2896,7 +2913,12 @@ build_one_sep_impl(const char *src, int entry_is_dir, g->support_context = sep_context_for(g, toolsrcdir, NULL, toolsrcdir); if (g->support_context < 0) return 1; + errno = 0; char *tc = realpath(tpath, NULL); + if (tc == NULL && errno == ENOMEM) { + sep_fail_nomem(); + return 1; + } int collision = 0; for (int i = 0; i < nproducts; i++) { int root_is_support = tc != NULL @@ -2914,7 +2936,13 @@ build_one_sep_impl(const char *src, int entry_is_dir, "test", userpath, sizeof userpath)) { userdir = 1; (void)userdir; + errno = 0; char *uc = realpath(userpath, NULL); + if (uc == NULL && errno == ENOMEM) { + free(tc); + sep_fail_nomem(); + return 1; + } if (tc != NULL && uc != NULL && strcmp(tc, uc) != 0) collision = 1; @@ -3704,22 +3732,24 @@ do_build(int argc, char **argv) { const char *src = NULL; struct seplinkflags linkflags = {0}; - size_t incsz = 1; - for (int i = 0; i < argc; i++) incsz += strlen(argv[i]) + 1; - char incs[incsz]; - memset(incs, 0, sizeof incs); + size_t incsz = 0; + char *incs = NULL; + if (include_buffer_for_args(argc, argv, &incs, &incsz) < 0) return 1; char outflag[PATH_MAX] = {0}; char workdir[PATH_MAX] = {0}; int emit_asm = 0; int package_only = 0; - if (parse_build_flags("build", argc, argv, incs, sizeof incs, + if (parse_build_flags("build", argc, argv, incs, incsz, &linkflags, outflag, sizeof outflag, workdir, sizeof workdir, - &src, &emit_asm, &package_only) < 0) + &src, &emit_asm, &package_only) < 0) { + free(incs); return 2; + } if (src == NULL) src = "."; if (package_only && emit_asm) { fprintf(stderr, "ww build: -p and -S cannot be combined\n"); + free(incs); return 2; } struct stat requested; @@ -3728,10 +3758,12 @@ do_build(int argc, char **argv) int is_dir = 0; if (!resolve_module(src, incs, resolved, sizeof resolved, &is_dir)) { fprintf(stderr, "ww build: cannot find module %s\n", src); + free(incs); return 1; } if (package_only && !is_dir) { fprintf(stderr, "ww build: -p needs a package directory\n"); + free(incs); return 2; } char out[PATH_MAX]; @@ -3752,9 +3784,11 @@ do_build(int argc, char **argv) basename_no_ext(resolved, out, sizeof out); } const char *root_identity = !literal && is_dir ? src : NULL; - return build_one_sep(resolved, is_dir, root_identity, out, objstem, incs, + int rc = build_one_sep(resolved, is_dir, root_identity, out, objstem, incs, &linkflags, package_only, 0, SEP_VARIANT_PRODUCTION, NULL, emit_asm, 1, workdir); + free(incs); + return rc; } static int @@ -3762,15 +3796,14 @@ do_run(int argc, char **argv) { const char *src = NULL; struct seplinkflags linkflags = {0}; - size_t incsz = 1; - for (int i = 0; i < argc; i++) incsz += strlen(argv[i]) + 1; - char incs[incsz]; - memset(incs, 0, sizeof incs); + size_t incsz = 0; + char *incs = NULL; + if (include_buffer_for_args(argc, argv, &incs, &incsz) < 0) return 1; char outflag[PATH_MAX] = {0}; /* -o accepted+ignored: run always uses the temp */ - int next = parse_build_flags("run", argc, argv, incs, sizeof incs, + int next = parse_build_flags("run", argc, argv, incs, incsz, &linkflags, outflag, sizeof outflag, NULL, 0, &src, NULL, NULL); - if (next < 0) return 2; + if (next < 0) { free(incs); return 2; } if (src == NULL) src = "."; struct stat requested; int literal = stat(src, &requested) == 0; @@ -3778,22 +3811,29 @@ do_run(int argc, char **argv) int is_dir = 0; if (!resolve_module(src, incs, resolved, sizeof resolved, &is_dir)) { fprintf(stderr, "ww run: cannot find module %s\n", src); + free(incs); return 1; } char tmpdir[PATH_MAX], tmp[PATH_MAX]; snprintf(tmpdir, sizeof tmpdir, "/tmp/ww_run_%d", getpid()); if (mkdir(tmpdir, 0700) != 0) { fprintf(stderr, "ww: cannot create temporary directory %s\n", tmpdir); + free(incs); return 1; } int tn = snprintf(tmp, sizeof tmp, "%s/main", tmpdir); - if (tn < 0 || (size_t)tn >= sizeof tmp) return 1; + if (tn < 0 || (size_t)tn >= sizeof tmp) { + free(incs); + return 1; + } /* The freshly acquired directory owns both the executable and the * adjacent main.sepwork tree. Nothing outside it is adopted or removed. */ const char *root_identity = !literal && is_dir ? src : NULL; - if (build_one_sep(resolved, is_dir, root_identity, tmp, tmp, incs, + int buildrc = build_one_sep(resolved, is_dir, root_identity, tmp, tmp, incs, &linkflags, - 0, 0, SEP_VARIANT_PRODUCTION, NULL, 0, 0, NULL) != 0) { + 0, 0, SEP_VARIANT_PRODUCTION, NULL, 0, 0, NULL); + free(incs); + if (buildrc != 0) { if (unlink(tmp) != 0 && errno != ENOENT) fputs("ww: cannot remove temporary output\n", stderr); if (rmdir(tmpdir) != 0) diff --git a/selfhost/cmd/ww/main.ww b/selfhost/cmd/ww/main.ww index c69299ff..e5ce4c9c 100644 --- a/selfhost/cmd/ww/main.ww +++ b/selfhost/cmd/ww/main.ww @@ -1010,6 +1010,23 @@ fn sepmakeints(count: i32, out: *[]i32) bool = { return false; }; +fn sepmakeptrs(count: i32, out: *[]*u8) bool = { + if (count < 0) { + sepfailsize(); + return false; + }; + let allocation: ([]*u8 | nomem) = sepallocptrs(count); + match (allocation) { + case let value: []*u8 => { + value.len = count; + *out = value; + return true; + }; + case nomem => { sepfailnomem(); return false; }; + }; + return false; +}; + fn sepreservepackages(g: *sepgraph, need: i32) bool = { if (need <= g.pkg.len) { return true; }; let cap: i32 = sepgrowcap(g.pkg.len, need); @@ -2599,6 +2616,7 @@ fn sepreverseimportbase(g: *sepgraph, p: *seppkg, context: i32, root.ptr = searchpath + pos; root.len = (end - pos): i32; let canonroot: *u8 = canonicaldir(root); + if (canonroot == nil && sepfatalallocation) { return -1; }; if (canonroot != nil) { let rn: u64 = cstrlen(canonroot); let dn: u64 = cstrlen(p.canon); @@ -2623,6 +2641,9 @@ fn sepreverseimportbase(g: *sepgraph, p: *seppkg, context: i32, cstrlen(rel)); if (selected != nil) { let selectedcanon: *u8 = canonicaldir(pathstr(selected)); + if (selectedcanon == nil && sepfatalallocation) { + return -1; + }; if (selectedcanon != nil && cstreq(selectedcanon, p.canon)) { return 1; @@ -4485,20 +4506,21 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { let inccap: u64 = 1u64; let capi: i32 = start; for (capi < argc) { - inccap += cstrlen(argv[capi]) + 1u64; + if (!sepaddbytes(&inccap, cstrlen(argv[capi])) + || !sepaddbytes(&inccap, 1u64)) { return 1; }; capi += 1; }; - let incs: []u8 = alloc([], inccap)!; - incs.len = inccap: i32; + let incs: []u8; + if (!sepmakebytes(inccap, &incs)) { return 1; }; let incoff: u64 = 0u64; cstrseal(incs.ptr, 0u64); let maxlflags: i32 = 32; - let libdirs: []*u8 = alloc([], maxlflags: u64)!; - libdirs.len = maxlflags; + let libdirs: []*u8; + if (!sepmakeptrs(maxlflags, &libdirs)) { return 1; }; let nlibdirs: i32 = 0; - let libs: []*u8 = alloc([], maxlflags: u64)!; - libs.len = maxlflags; + let libs: []*u8; + if (!sepmakeptrs(maxlflags, &libs)) { return 1; }; let nlibs: i32 = 0; let i: i32 = start; @@ -4696,20 +4718,21 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { let inccap: u64 = 1u64; let capi: i32 = start; for (capi < argc) { - inccap += cstrlen(argv[capi]) + 1u64; + if (!sepaddbytes(&inccap, cstrlen(argv[capi])) + || !sepaddbytes(&inccap, 1u64)) { return 1; }; capi += 1; }; - let incs: []u8 = alloc([], inccap)!; - incs.len = inccap: i32; + let incs: []u8; + if (!sepmakebytes(inccap, &incs)) { return 1; }; let incoff: u64 = 0u64; cstrseal(incs.ptr, 0u64); let maxlflags: i32 = 32; - let libdirs: []*u8 = alloc([], maxlflags: u64)!; - libdirs.len = maxlflags; + let libdirs: []*u8; + if (!sepmakeptrs(maxlflags, &libdirs)) { return 1; }; let nlibdirs: i32 = 0; - let libs: []*u8 = alloc([], maxlflags: u64)!; - libs.len = maxlflags; + let libs: []*u8; + if (!sepmakeptrs(maxlflags, &libs)) { return 1; }; let nlibs: i32 = 0; let i: i32 = start; @@ -5001,11 +5024,12 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { let inccap: u64 = 1u64; let capi: i32 = start; for (capi < argc) { - inccap += cstrlen(argv[capi]) + 1u64; + if (!sepaddbytes(&inccap, cstrlen(argv[capi])) + || !sepaddbytes(&inccap, 1u64)) { return 1; }; capi += 1; }; - let incs: []u8 = alloc([], inccap)!; - incs.len = inccap: i32; + let incs: []u8; + if (!sepmakebytes(inccap, &incs)) { return 1; }; let incoff: u64 = 0u64; cstrseal(incs.ptr, 0u64);