diff options
Diffstat (limited to 'libc-bottom-half/sources/__wasilibc_initialize_environ.c')
-rw-r--r-- | libc-bottom-half/sources/__wasilibc_initialize_environ.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/libc-bottom-half/sources/__wasilibc_initialize_environ.c b/libc-bottom-half/sources/__wasilibc_initialize_environ.c new file mode 100644 index 0000000..2d31c5d --- /dev/null +++ b/libc-bottom-half/sources/__wasilibc_initialize_environ.c @@ -0,0 +1,93 @@ +#include <unistd.h> +#include <stdlib.h> +#include <sysexits.h> +#include <wasi/api.h> +#include <wasi/libc.h> +#include <wasi/libc-environ.h> + +/// If the program doesn't use `environ`, it'll get this version of +/// `__wasilibc_environ`, which isn't initialized with a constructor function. +/// `getenv` etc. call `__wasilibc_ensure_environ()` before accessing it. +/// Statically-initialize it to an invalid pointer value so that we can +/// detect if it's been explicitly initialized (we can't use `NULL` because +/// `clearenv` sets it to NULL. +weak char **__wasilibc_environ = (char **)-1; + +// See the comments in libc-environ.h. +void __wasilibc_ensure_environ(void) { + if (__wasilibc_environ == (char **)-1) { + __wasilibc_initialize_environ(); + } +} + +/// Avoid dynamic allocation for the case where there are no environment +/// variables, but we still need a non-NULL pointer to an (empty) array. +static char *empty_environ[1] = { NULL }; + +// See the comments in libc-environ.h. +void __wasilibc_initialize_environ(void) { + // Get the sizes of the arrays we'll have to create to copy in the environment. + size_t environ_count; + size_t environ_buf_size; + __wasi_errno_t err = __wasi_environ_sizes_get(&environ_count, &environ_buf_size); + if (err != __WASI_ERRNO_SUCCESS) { + goto oserr; + } + if (environ_count == 0) { + __wasilibc_environ = empty_environ; + return; + } + + // Add 1 for the NULL pointer to mark the end, and check for overflow. + size_t num_ptrs = environ_count + 1; + if (num_ptrs == 0) { + goto software; + } + + // Allocate memory for storing the environment chars. + char *environ_buf = malloc(environ_buf_size); + if (environ_buf == NULL) { + goto software; + } + + // Allocate memory for the array of pointers. This uses `calloc` both to + // handle overflow and to initialize the NULL pointer at the end. + char **environ_ptrs = calloc(num_ptrs, sizeof(char *)); + if (environ_ptrs == NULL) { + free(environ_buf); + goto software; + } + + // Fill the environment chars, and the `__wasilibc_environ` array with + // pointers into those chars. + // TODO: Remove the casts on `environ_ptrs` and `environ_buf` once the witx is updated with char8 support. + err = __wasi_environ_get((uint8_t **)environ_ptrs, (uint8_t *)environ_buf); + if (err != __WASI_ERRNO_SUCCESS) { + free(environ_buf); + free(environ_ptrs); + goto oserr; + } + + __wasilibc_environ = environ_ptrs; + return; +oserr: + _Exit(EX_OSERR); +software: + _Exit(EX_SOFTWARE); +} + +// See the comments in libc-environ.h. +void __wasilibc_deinitialize_environ(void) { + if (__wasilibc_environ != (char **)-1) { + // Let libc-top-half clear the old environment-variable strings. + clearenv(); + // Set the pointer to the special init value. + __wasilibc_environ = (char **)-1; + } +} + +// See the comments in libc-environ.h. +weak void __wasilibc_maybe_reinitialize_environ_eagerly(void) { + // This version does nothing. It may be overridden by a version which does + // something if `environ` is used. +} |