]> git.proxmox.com Git - wasi-libc.git/blob - libc-bottom-half/sources/__wasilibc_initialize_environ.c
4a8bb1a3e824eeb78936e1bd8e260205aa1ab3d2
[wasi-libc.git] / libc-bottom-half / sources / __wasilibc_initialize_environ.c
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <sysexits.h>
4 #include <wasi/api.h>
5 #include <wasi/libc.h>
6 #include <wasi/libc-environ.h>
7
8 /// If the program doesn't use `environ`, it'll get this version of
9 /// `__wasilibc_environ`, which isn't initialized with a constructor function.
10 /// `getenv` etc. call `__wasilibc_ensure_environ()` before accessing it.
11 /// Statically-initialize it to an invalid pointer value so that we can
12 /// detect if it's been explicitly initialized (we can't use `NULL` because
13 /// `clearenv` sets it to NULL.
14 char **__wasilibc_environ weak = (char **)-1;
15
16 // See the comments in libc-environ.h.
17 void __wasilibc_ensure_environ(void) {
18 if (__wasilibc_environ == (char **)-1) {
19 __wasilibc_initialize_environ();
20 }
21 }
22
23 /// Avoid dynamic allocation for the case where there are no environment
24 /// variables, but we still need a non-NULL pointer to an (empty) array.
25 static char *empty_environ[1] = { NULL };
26
27 // See the comments in libc-environ.h.
28 void __wasilibc_initialize_environ(void) {
29 // Get the sizes of the arrays we'll have to create to copy in the environment.
30 size_t environ_count;
31 size_t environ_buf_size;
32 __wasi_errno_t err = __wasi_environ_sizes_get(&environ_count, &environ_buf_size);
33 if (err != __WASI_ERRNO_SUCCESS) {
34 goto oserr;
35 }
36 if (environ_count == 0) {
37 __wasilibc_environ = empty_environ;
38 return;
39 }
40
41 // Add 1 for the NULL pointer to mark the end, and check for overflow.
42 size_t num_ptrs = environ_count + 1;
43 if (num_ptrs == 0) {
44 goto software;
45 }
46
47 // Allocate memory for storing the environment chars.
48 char *environ_buf = malloc(environ_buf_size);
49 if (environ_buf == NULL) {
50 goto software;
51 }
52
53 // Allocate memory for the array of pointers. This uses `calloc` both to
54 // handle overflow and to initialize the NULL pointer at the end.
55 char **environ_ptrs = calloc(num_ptrs, sizeof(char *));
56 if (environ_ptrs == NULL) {
57 free(environ_buf);
58 goto software;
59 }
60
61 // Fill the environment chars, and the `__wasilibc_environ` array with
62 // pointers into those chars.
63 // TODO: Remove the casts on `environ_ptrs` and `environ_buf` once the witx is updated with char8 support.
64 err = __wasi_environ_get((uint8_t **)environ_ptrs, (uint8_t *)environ_buf);
65 if (err != __WASI_ERRNO_SUCCESS) {
66 free(environ_buf);
67 free(environ_ptrs);
68 goto oserr;
69 }
70
71 __wasilibc_environ = environ_ptrs;
72 return;
73 oserr:
74 _Exit(EX_OSERR);
75 software:
76 _Exit(EX_SOFTWARE);
77 }
78
79 // See the comments in libc-environ.h.
80 void __wasilibc_deinitialize_environ(void) {
81 if (__wasilibc_environ != (char **)-1) {
82 // Let libc-top-half clear the old environment-variable strings.
83 clearenv();
84 // Set the pointer to the special init value.
85 __wasilibc_environ = (char **)-1;
86 }
87 }
88
89 // See the comments in libc-environ.h.
90 weak
91 void __wasilibc_maybe_reinitialize_environ_eagerly(void) {
92 // This version does nothing. It may be overridden by a version which does
93 // something if `environ` is used.
94 }