Commit 8a8da49b52

Frank Denis <github@pureftpd.org>
2024-04-12 22:51:52
Re-add lazy preopen changes
1 parent 3f4c43b
Changed files (5)
lib
libc
include
wasm-wasi-musl
wasi
wasi
libc-bottom-half
cloudlibc
src
libc
unistd
sources
src
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).
lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/unistd/close.c
lib/libc/wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c
@@ -4,6 +4,9 @@
 #include <unistd.h>
 
 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;
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);
+}
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",