mirror of
https://git.proxmox.com/git/wasi-libc
synced 2025-10-18 17:19:33 +00:00

* Fixes for the THREAD_MODEL=posix build * Fix expected symbols from previous commit * Enable `lock` in `random.c` when threads are enabled This uses the `_REENTRANT` definition to indicate when the `lock` should be available. * Disable `aio.h` when compiling for threads In talking to @sunfishcode about `aio.h`, this functionality is not yet a primary concern (it was already disabled in the default, single-threaded mode). Additionally, this change adds expectation lines for the new symbols/includes added and removed by `pthread.h`. This change was reached by running: ```console $ git diff --no-index expected/wasm32-wasi sysroot/share/wasm32-wasi > patch.diff # replace "sysroot/share" with "expected" in `patch.diff` $ git apply patch.diff --reject # manually fix any rejections ``` * Specify the TLS model until LLVM 15 is released The `-ftls-model` configuration can be removed once https://reviews.llvm.org/D130053 makes its way into an upstream release. * Rename `__wasi_libc_pthread_self` to `__wasilibc_pthread_self` The symbol is still undefined, though. * Add different sets of expected output based on THREAD_MODEL * Re-add trailing whitespace to `predefined-macros.txt` @sbc100 wanted to retain the whitespace trailing after certain predefined macro lines. This change restores that whitespace from upstream and re-generates the POSIX version using the following command: ```console $ git diff --no-index expected/wasm32-wasi/posix/predefined-macros.txt sysroot/share/wasm32-wasi/predefined-macros.txt | sed 's/sysroot\/share\/wasm32-wasi/expected\/wasm32-wasi\/posix/' | git apply ``` * Protect `preopens.c` against concurrent access * Only build thread-capable wasi-libc on latest version of Clang * Use `thrd_sleep` from MUSL instead of aliasing `nanosleep` * Define `pthread_setcancelstate` in `THREAD_MODEL=posix` builds There are other options here (e.g., always define the `pthread_*` symbols with stubs) but until we discuss that this is an intermediate working step. * Define a Wasm global to store `pthread_self` * Remove `g_needs_dynamic_alloc` global * Document the state of pthread support * review: de-duplicate symbols based on #314 * review: only define `__wasilibc_cwd_{un}lock` when needed * review: add #ifdefs to `__pthread_setcancelstate` * review: add additional #ifdefs to `pthread_self.c` * review: put lock definition behind #ifdef _REENTRANT * review: remove pthread_setcancelstate.c * review: re-fix indentation * review: alias __clock_nanosleep in bottom half * review: remove extra line Co-authored-by: Sam Clegg <sbc@chromium.org>
172 lines
5.1 KiB
C
172 lines
5.1 KiB
C
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <wasi/libc-find-relpath.h>
|
|
#include <wasi/libc.h>
|
|
|
|
#ifdef _REENTRANT
|
|
void __wasilibc_cwd_lock(void);
|
|
void __wasilibc_cwd_unlock(void);
|
|
#else
|
|
#define __wasilibc_cwd_lock() (void)0
|
|
#define __wasilibc_cwd_unlock() (void)0
|
|
#endif
|
|
extern char *__wasilibc_cwd;
|
|
static int __wasilibc_cwd_mallocd = 0;
|
|
|
|
int chdir(const char *path)
|
|
{
|
|
static char *relative_buf = NULL;
|
|
static size_t relative_buf_len = 0;
|
|
|
|
// Find a preopen'd directory as well as a relative path we're anchored
|
|
// from which we're changing directories to.
|
|
const char *abs;
|
|
int parent_fd = __wasilibc_find_relpath_alloc(path, &abs, &relative_buf, &relative_buf_len, 1);
|
|
if (parent_fd == -1)
|
|
return -1;
|
|
|
|
// Make sure that this directory we're accessing is indeed a directory.
|
|
struct stat dirinfo;
|
|
int ret = fstatat(parent_fd, relative_buf, &dirinfo, 0);
|
|
if (ret == -1)
|
|
return -1;
|
|
if (!S_ISDIR(dirinfo.st_mode)) {
|
|
errno = ENOTDIR;
|
|
return -1;
|
|
}
|
|
|
|
// Create a string that looks like:
|
|
//
|
|
// __wasilibc_cwd = "/" + abs + "/" + relative_buf
|
|
//
|
|
// If `relative_buf` is equal to "." or `abs` is equal to the empty string,
|
|
// however, we skip that part and the middle slash.
|
|
size_t abs_len = strlen(abs);
|
|
int copy_relative = strcmp(relative_buf, ".") != 0;
|
|
int mid = copy_relative && abs[0] != 0;
|
|
char *new_cwd = malloc(1 + abs_len + mid + (copy_relative ? strlen(relative_buf) : 0) + 1);
|
|
if (new_cwd == NULL) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
new_cwd[0] = '/';
|
|
strcpy(new_cwd + 1, abs);
|
|
if (mid)
|
|
new_cwd[1 + abs_len] = '/';
|
|
if (copy_relative)
|
|
strcpy(new_cwd + 1 + abs_len + mid, relative_buf);
|
|
|
|
// And set our new malloc'd buffer into the global cwd, freeing the
|
|
// previous one if necessary.
|
|
__wasilibc_cwd_lock();
|
|
char *prev_cwd = __wasilibc_cwd;
|
|
__wasilibc_cwd = new_cwd;
|
|
__wasilibc_cwd_unlock();
|
|
if (__wasilibc_cwd_mallocd)
|
|
free(prev_cwd);
|
|
__wasilibc_cwd_mallocd = 1;
|
|
return 0;
|
|
}
|
|
|
|
static const char *make_absolute(const char *path) {
|
|
static char *make_absolute_buf = NULL;
|
|
static size_t make_absolute_len = 0;
|
|
|
|
// If this path is absolute, then we return it as-is.
|
|
if (path[0] == '/') {
|
|
return path;
|
|
}
|
|
|
|
#ifndef _REENTRANT
|
|
// If the path is empty, or points to the current directory, then return
|
|
// the current directory.
|
|
if (path[0] == 0 || !strcmp(path, ".") || !strcmp(path, "./")) {
|
|
return __wasilibc_cwd;
|
|
}
|
|
#endif
|
|
|
|
// If the path starts with `./` then we won't be appending that to the cwd.
|
|
if (path[0] == '.' && path[1] == '/')
|
|
path += 2;
|
|
|
|
// Otherwise we'll take the current directory, add a `/`, and then add the
|
|
// input `path`. Note that this doesn't do any normalization (like removing
|
|
// `/./`).
|
|
__wasilibc_cwd_lock();
|
|
size_t cwd_len = strlen(__wasilibc_cwd);
|
|
size_t path_len = path ? strlen(path) : 0;
|
|
__wasilibc_cwd_unlock();
|
|
int need_slash = __wasilibc_cwd[cwd_len - 1] == '/' ? 0 : 1;
|
|
size_t alloc_len = cwd_len + path_len + 1 + need_slash;
|
|
if (alloc_len > make_absolute_len) {
|
|
char *tmp = realloc(make_absolute_buf, alloc_len);
|
|
if (tmp == NULL) {
|
|
__wasilibc_cwd_unlock();
|
|
return NULL;
|
|
}
|
|
make_absolute_buf = tmp;
|
|
make_absolute_len = alloc_len;
|
|
}
|
|
strcpy(make_absolute_buf, __wasilibc_cwd);
|
|
__wasilibc_cwd_unlock();
|
|
|
|
#ifdef _REENTRANT
|
|
if (path[0] == 0 || !strcmp(path, ".") || !strcmp(path, "./")) {
|
|
return make_absolute_buf;
|
|
}
|
|
#endif
|
|
|
|
if (need_slash)
|
|
strcpy(make_absolute_buf + cwd_len, "/");
|
|
strcpy(make_absolute_buf + cwd_len + need_slash, path);
|
|
return make_absolute_buf;
|
|
}
|
|
|
|
// Helper function defined only in this object file and weakly referenced from
|
|
// `preopens.c` and `posix.c` This function isn't necessary unless `chdir` is
|
|
// pulled in because all paths are otherwise absolute or relative to the root.
|
|
int __wasilibc_find_relpath_alloc(
|
|
const char *path,
|
|
const char **abs_prefix,
|
|
char **relative_buf,
|
|
size_t *relative_buf_len,
|
|
int can_realloc
|
|
) {
|
|
// First, make our path absolute taking the cwd into account.
|
|
const char *abspath = make_absolute(path);
|
|
if (abspath == NULL) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
// Next use our absolute path and split it. Find the preopened `fd` parent
|
|
// directory and set `abs_prefix`. Next up we'll be trying to fit `rel`
|
|
// into `relative_buf`.
|
|
const char *rel;
|
|
int fd = __wasilibc_find_abspath(abspath, abs_prefix, &rel);
|
|
if (fd == -1)
|
|
return -1;
|
|
|
|
size_t rel_len = strlen(rel);
|
|
if (*relative_buf_len < rel_len + 1) {
|
|
if (!can_realloc) {
|
|
errno = ERANGE;
|
|
return -1;
|
|
}
|
|
char *tmp = realloc(*relative_buf, rel_len + 1);
|
|
if (tmp == NULL) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
*relative_buf = tmp;
|
|
*relative_buf_len = rel_len + 1;
|
|
}
|
|
strcpy(*relative_buf, rel);
|
|
return fd;
|
|
}
|