From 8a8da49b5212030d603000d699a8ca9ed92e24cd Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 12 Apr 2024 22:51:52 +0200 Subject: [PATCH] Re-add lazy preopen changes --- lib/libc/include/wasm-wasi-musl/wasi/libc.h | 4 + .../cloudlibc/src/libc/unistd/close.c | 0 .../sources/__wasilibc_fd_renumber.c | 3 + .../wasi/libc-bottom-half/sources/preopens.c | 111 ++++++++++++++++-- src/wasi_libc.zig | 1 - 5 files changed, 109 insertions(+), 10 deletions(-) delete mode 100644 lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/unistd/close.c diff --git a/lib/libc/include/wasm-wasi-musl/wasi/libc.h b/lib/libc/include/wasm-wasi-musl/wasi/libc.h index 18d8e9e3cb..6acb672ad0 100644 --- a/lib/libc/include/wasm-wasi-musl/wasi/libc.h +++ b/lib/libc/include/wasm-wasi-musl/wasi/libc.h @@ -17,6 +17,10 @@ struct timespec; /// afterward, you should call this before doing so. void __wasilibc_populate_preopens(void); +/// Reset the preopens table to an uninitialized state, forcing it to be +/// reinitialized next time it is needed. +void __wasilibc_reset_preopens(void); + /// Register the given pre-opened file descriptor under the given path. /// /// This function does not take ownership of `prefix` (it makes its own copy). diff --git a/lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/unistd/close.c b/lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/unistd/close.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c b/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c index d5247518c6..7690d1359e 100644 --- a/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c +++ b/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c @@ -4,6 +4,9 @@ #include int __wasilibc_fd_renumber(int fd, int newfd) { + // Scan the preopen fds before making any changes. + __wasilibc_populate_preopens(); + __wasi_errno_t error = __wasi_fd_renumber(fd, newfd); if (error != 0) { errno = error; diff --git a/lib/libc/wasi/libc-bottom-half/sources/preopens.c b/lib/libc/wasi/libc-bottom-half/sources/preopens.c index a49ca3e9ad..a7ebe646b9 100644 --- a/lib/libc/wasi/libc-bottom-half/sources/preopens.c +++ b/lib/libc/wasi/libc-bottom-half/sources/preopens.c @@ -25,6 +25,7 @@ typedef struct preopen { } preopen; /// A simple growable array of `preopen`. +static _Atomic _Bool preopens_populated = false; static preopen *preopens; static size_t num_preopens; static size_t preopen_capacity; @@ -100,12 +101,9 @@ static const char *strip_prefixes(const char *path) { return path; } -/// Register the given preopened file descriptor under the given path. -/// -/// This function takes ownership of `prefix`. -static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) { - LOCK(lock); - +/// Similar to `internal_register_preopened_fd_unlocked` but does not +/// take a lock. +static int internal_register_preopened_fd_unlocked(__wasi_fd_t fd, const char *relprefix) { // Check preconditions. assert_invariants(); assert(fd != AT_FDCWD); @@ -113,22 +111,32 @@ static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) assert(relprefix != NULL); if (num_preopens == preopen_capacity && resize() != 0) { - UNLOCK(lock); return -1; } char *prefix = strdup(strip_prefixes(relprefix)); if (prefix == NULL) { - UNLOCK(lock); return -1; } preopens[num_preopens++] = (preopen) { prefix, fd, }; assert_invariants(); - UNLOCK(lock); return 0; } +/// Register the given preopened file descriptor under the given path. +/// +/// This function takes ownership of `prefix`. +static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) { + LOCK(lock); + + int r = internal_register_preopened_fd_unlocked(fd, relprefix); + + UNLOCK(lock); + + return r; +} + /// Are the `prefix_len` bytes pointed to by `prefix` a prefix of `path`? static bool prefix_matches(const char *prefix, size_t prefix_len, const char *path) { // Allow an empty string as a prefix of any relative path. @@ -152,6 +160,8 @@ static bool prefix_matches(const char *prefix, size_t prefix_len, const char *pa // See the documentation in libc.h int __wasilibc_register_preopened_fd(int fd, const char *prefix) { + __wasilibc_populate_preopens(); + return internal_register_preopened_fd((__wasi_fd_t)fd, prefix); } @@ -172,6 +182,8 @@ int __wasilibc_find_relpath(const char *path, int __wasilibc_find_abspath(const char *path, const char **abs_prefix, const char **relative_path) { + __wasilibc_populate_preopens(); + // Strip leading `/` characters, the prefixes we're mataching won't have // them. while (*path == '/') @@ -218,3 +230,84 @@ int __wasilibc_find_abspath(const char *path, *relative_path = computed; return fd; } + +__attribute__((constructor(51))) +void __wasilibc_populate_preopens(void) { + // Fast path: If the preopens are already initialized, do nothing. + if (preopens_populated) { + return; + } + + LOCK(lock); + + // Check whether another thread initialized the preopens already. + if (preopens_populated) { + UNLOCK(lock); + return; + } + + // Skip stdin, stdout, and stderr, and count up until we reach an invalid + // file descriptor. + for (__wasi_fd_t fd = 3; fd != 0; ++fd) { + __wasi_prestat_t prestat; + __wasi_errno_t ret = __wasi_fd_prestat_get(fd, &prestat); + if (ret == __WASI_ERRNO_BADF) + break; + if (ret != __WASI_ERRNO_SUCCESS) + goto oserr; + switch (prestat.tag) { + case __WASI_PREOPENTYPE_DIR: { + char *prefix = malloc(prestat.u.dir.pr_name_len + 1); + if (prefix == NULL) + goto software; + + // TODO: Remove the cast on `prefix` once the witx is updated with + // char8 support. + ret = __wasi_fd_prestat_dir_name(fd, (uint8_t *)prefix, + prestat.u.dir.pr_name_len); + if (ret != __WASI_ERRNO_SUCCESS) + goto oserr; + prefix[prestat.u.dir.pr_name_len] = '\0'; + + if (internal_register_preopened_fd_unlocked(fd, prefix) != 0) + goto software; + free(prefix); + + break; + } + default: + break; + } + } + + // Preopens are now initialized. + preopens_populated = true; + + UNLOCK(lock); + + return; +oserr: + _Exit(EX_OSERR); +software: + _Exit(EX_SOFTWARE); +} + +void __wasilibc_reset_preopens(void) { + LOCK(lock); + + if (num_preopens) { + for (int i = 0; i < num_preopens; ++i) { + free((void*) preopens[i].prefix); + } + free(preopens); + } + + preopens_populated = false; + preopens = NULL; + num_preopens = 0; + preopen_capacity = 0; + + assert_invariants(); + + UNLOCK(lock); +} diff --git a/src/wasi_libc.zig b/src/wasi_libc.zig index bd63b1bd93..97a435c26c 100644 --- a/src/wasi_libc.zig +++ b/src/wasi_libc.zig @@ -463,7 +463,6 @@ const libc_bottom_half_src_files = [_][]const u8{ "wasi/libc-bottom-half/cloudlibc/src/libc/time/clock_nanosleep.c", "wasi/libc-bottom-half/cloudlibc/src/libc/time/nanosleep.c", "wasi/libc-bottom-half/cloudlibc/src/libc/time/time.c", - "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/close.c", "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/faccessat.c", "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/fdatasync.c", "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/fsync.c",