]>
Commit | Line | Data |
---|---|---|
bdfbb545 DG |
1 | #include <unistd.h> |
2 | #include <stdlib.h> | |
410c6607 | 3 | #include <sysexits.h> |
446cb3f1 | 4 | #include <wasi/api.h> |
bdfbb545 | 5 | #include <wasi/libc.h> |
9efc2f42 | 6 | #include <wasi/libc-environ.h> |
bdfbb545 | 7 | |
9efc2f42 DG |
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 __attribute__((weak)) = (char **)-1; | |
bdfbb545 | 15 | |
9efc2f42 DG |
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 }; | |
bdfbb545 | 26 | |
9efc2f42 DG |
27 | // See the comments in libc-environ.h. |
28 | void __wasilibc_initialize_environ(void) { | |
bdfbb545 DG |
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; | |
9efc2f42 | 32 | __wasi_errno_t err = __wasi_environ_sizes_get(&environ_count, &environ_buf_size); |
446cb3f1 | 33 | if (err != __WASI_ERRNO_SUCCESS) { |
410c6607 | 34 | goto oserr; |
bdfbb545 DG |
35 | } |
36 | if (environ_count == 0) { | |
9efc2f42 | 37 | __wasilibc_environ = empty_environ; |
410c6607 | 38 | return; |
bdfbb545 DG |
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) { | |
410c6607 | 44 | goto software; |
bdfbb545 DG |
45 | } |
46 | ||
47 | // Allocate memory for storing the environment chars. | |
48 | char *environ_buf = malloc(environ_buf_size); | |
49 | if (environ_buf == NULL) { | |
410c6607 | 50 | goto software; |
bdfbb545 DG |
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); | |
410c6607 | 58 | goto software; |
bdfbb545 DG |
59 | } |
60 | ||
9efc2f42 DG |
61 | // Fill the environment chars, and the `__wasilibc_environ` array with |
62 | // pointers into those chars. | |
446cb3f1 DG |
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); | |
410c6607 | 65 | if (err != __WASI_ERRNO_SUCCESS) { |
bdfbb545 DG |
66 | free(environ_buf); |
67 | free(environ_ptrs); | |
410c6607 | 68 | goto oserr; |
bdfbb545 | 69 | } |
410c6607 | 70 | |
9efc2f42 | 71 | __wasilibc_environ = environ_ptrs; |
1fad3389 | 72 | return; |
410c6607 DG |
73 | oserr: |
74 | _Exit(EX_OSERR); | |
75 | software: | |
76 | _Exit(EX_SOFTWARE); | |
bdfbb545 | 77 | } |
82fc2c4f DG |
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 | __attribute__((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 | } |