From 50e93747008584d29627b8cdfd3f634b3d94ec1a Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 8 Aug 2025 15:18:43 -0700 Subject: [PATCH 1/2] Port environment variables to use wasip2 methods --- .../sources/__wasilibc_initialize_environ.c | 54 +++++++++++++++++++ test/Makefile | 4 +- test/scripts/run-test.sh | 4 +- test/src/misc/external_env.c | 20 +++++++ 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 test/src/misc/external_env.c diff --git a/libc-bottom-half/sources/__wasilibc_initialize_environ.c b/libc-bottom-half/sources/__wasilibc_initialize_environ.c index 2d31c5d03..9eddb4b5f 100644 --- a/libc-bottom-half/sources/__wasilibc_initialize_environ.c +++ b/libc-bottom-half/sources/__wasilibc_initialize_environ.c @@ -1,7 +1,11 @@ #include #include #include +#ifdef __wasilibc_use_wasip2 +#include +#else #include +#endif #include #include @@ -26,6 +30,55 @@ static char *empty_environ[1] = { NULL }; // See the comments in libc-environ.h. void __wasilibc_initialize_environ(void) { +#ifdef __wasilibc_use_wasip2 + // Get the environment + wasip2_list_tuple2_string_string_t wasi_environment; + environment_get_environment(&wasi_environment); + + size_t environ_count = wasi_environment.len; + 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 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 *)); + + // Copy the environment variables + for (size_t i = 0; i < environ_count; i++) { + wasip2_tuple2_string_string_t pair = wasi_environment.ptr[i]; + // 1 extra character for the null terminator, 1 for the '=' character + environ_ptrs[i] = malloc(pair.f0.len + pair.f1.len + 2); + if (!environ_ptrs[i]) { + for (size_t j = 0; j < i; j++) + free(environ_ptrs[j]); + free(environ_ptrs); + goto software; + } + memcpy(environ_ptrs[i], pair.f0.ptr, pair.f0.len); + environ_ptrs[i][pair.f0.len] = '='; + memcpy(environ_ptrs[i] + pair.f0.len + 1, pair.f1.ptr, pair.f1.len); + environ_ptrs[i][pair.f0.len + pair.f1.len + 1] = '\0'; + } + + // Free the WASI environment list + wasip2_list_tuple2_string_string_free(&wasi_environment); + + // Initialize the environment from the created array + __wasilibc_environ = environ_ptrs; + return; +software: + wasip2_list_tuple2_string_string_free(&wasi_environment); + _Exit(EX_SOFTWARE); + +#else // 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; @@ -74,6 +127,7 @@ void __wasilibc_initialize_environ(void) { _Exit(EX_OSERR); software: _Exit(EX_SOFTWARE); +#endif } // See the comments in libc-environ.h. diff --git a/test/Makefile b/test/Makefile index d1dc3ff9b..bc35da774 100644 --- a/test/Makefile +++ b/test/Makefile @@ -210,8 +210,10 @@ wasm_to_c = $(patsubst $(OBJPAT),$(SRCDIR)/%.c,$1) $(RUNDIR)/%/success: $(OBJPAT) @mkdir -p $(@D) @DIR="$(abspath $(@D))" \ + ENV="$(shell scripts/add-flags.py ENV $(call wasm_to_c,$<))" \ WASM="$(abspath $<)" \ - ENGINE="$(ENGINE) $(shell scripts/add-flags.py RUN $(call wasm_to_c,$<))" \ + ENGINE="$(ENGINE)" \ + RUN="$(shell scripts/add-flags.py RUN $(call wasm_to_c,$<))" \ ARGS="$(shell scripts/add-flags.py ARGS $(call wasm_to_c,$<))" \ scripts/run-test.sh diff --git a/test/scripts/run-test.sh b/test/scripts/run-test.sh index 21d529ae5..87961418e 100755 --- a/test/scripts/run-test.sh +++ b/test/scripts/run-test.sh @@ -6,7 +6,7 @@ # - a `fs` directory which the test may have used for file IO # - an `output.log` file containing the output of the test # -# Usage: DIR=... WASM=... ENGINE=... ARGS="..." ./run-test.sh +# Usage: ENV="..." DIR=... WASM=... ENGINE=... RUN="..." ARGS="..." ./run-test.sh ENGINE="${ENGINE:-wasmtime}" [ -n "$WASM" ] || (echo "missing WASM variable" && exit 1) @@ -14,7 +14,7 @@ ENGINE="${ENGINE:-wasmtime}" cd $DIR mkdir -p fs -echo "$ENGINE $WASM $ARGS" > cmd.sh +echo "$ENV $ENGINE $RUN $WASM $ARGS" > cmd.sh chmod +x cmd.sh ./cmd.sh &> output.log [ $? -eq 0 ] || echo "Test failed" >> output.log diff --git a/test/src/misc/external_env.c b/test/src/misc/external_env.c new file mode 100644 index 000000000..85b4ee84b --- /dev/null +++ b/test/src/misc/external_env.c @@ -0,0 +1,20 @@ +//! add-flags.py(CFLAGS): -I. +//! add-flags.py(RUN): --wasi=inherit-env=y +//! add-flags.py(ENV): VAR1=foo VAR2=bar +#include +#include +#include +#include "test.h" + +#define TEST(c, ...) \ + ( (c) || (t_error(#c " failed: " __VA_ARGS__),0) ) + +int main(int argc, char **argv) +{ + char* s = getenv("VAR1"); + TEST(strcmp(s, "foo")==0); + s = getenv("VAR2"); + TEST(strcmp(s, "bar")==0); + + return t_status; +} From 253c5250f72041c7ad23ceff7e7f2553f05a8e88 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 8 Aug 2025 16:36:30 -0700 Subject: [PATCH 2/2] Skip environment variables test when testing in browser --- test/scripts/browser-test/harness.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/scripts/browser-test/harness.mjs b/test/scripts/browser-test/harness.mjs index f7c1e66d3..87806ceec 100755 --- a/test/scripts/browser-test/harness.mjs +++ b/test/scripts/browser-test/harness.mjs @@ -26,6 +26,8 @@ const SKIP_TESTS = [ "libc-test/functional/pthread_tsd", // Skip test that uses command-line arguments "misc/argv_two_args", + // Skip test that uses environment variables + "misc/external_env", // XFAIL: @bjorn3/browser_wasi_shim doesn't support symlinks for now "misc/fts", ];