Skip to content

Commit bdfbb54

Browse files
authored
Call populate_environ only if we actually need environment variables. (#109)
* Link `populate_environ` only if we actually need environment variables. This avoids linking in the environment variable initialization code, and the __wasi_environ_sizes_get and __wasi_environ_get imports, in programs that don't use environment variables. This also removes the "___environ" (three underscores) alias symbol, which is only in musl for backwards compatibility. * Switch to //-style comments. * If malloc fails, don't leave `__environ` pointing to an uninitialized buffer. * Fix a memory leak if one malloc succeeds and the other fails. * Use calloc to handle multiplication overflow. This also handles the NULL terminator. * Don't initialize __environ until everything has succeeded. * Avoid leaking in case __wasi_environ_get fails. * Handle overflow in the add too. * Add #include <stdlib.h> for malloc etc. * If the environment is empty, don't allocate any memory.
1 parent d253aa3 commit bdfbb54

6 files changed

Lines changed: 83 additions & 34 deletions

File tree

Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ LIBC_TOP_HALF_MUSL_SOURCES = \
120120
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/fcntl/creat.c \
121121
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/dirent/alphasort.c \
122122
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/dirent/versionsort.c \
123-
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/__environ.c \
124123
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/clearenv.c \
125124
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/getenv.c \
126125
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/putenv.c \
@@ -359,7 +358,7 @@ $(OBJDIR)/%.o: $(CURDIR)/%.c include_dirs
359358
$(DLMALLOC_OBJS): override WASM_CFLAGS += \
360359
-I$(DLMALLOC_INC)
361360

362-
$(LIBC_BOTTOM_HALF_ALL_OBJS): override WASM_CFLAGS += \
361+
startup_files $(LIBC_BOTTOM_HALF_ALL_OBJS): override WASM_CFLAGS += \
363362
-I$(LIBC_BOTTOM_HALF_HEADERS_PRIVATE) \
364363
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC) \
365364
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) \

expected/wasm32-wasi/defined-symbols.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ _IO_putc
1111
_IO_putc_unlocked
1212
__EINVAL
1313
__ENOMEM
14-
___environ
1514
__asctime_r
1615
__assert_fail
1716
__c_dot_utf8
@@ -252,6 +251,7 @@ __utc
252251
__wasilibc_fd_renumber
253252
__wasilibc_find_relpath
254253
__wasilibc_init_preopen
254+
__wasilibc_populate_environ
255255
__wasilibc_register_preopened_fd
256256
__wasilibc_rmdirat
257257
__wasilibc_tell

libc-bottom-half/crt/crt1.c

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
#include <sysexits.h>
33
#include <wasi/core.h>
44
#include <wasi/libc.h>
5+
#include <wasi/libc-internal.h>
56

6-
extern char **__environ;
7+
__wasi_errno_t __wasilibc_populate_environ(void) __attribute__((weak));
78
extern void __wasm_call_ctors(void);
89
extern int main(int, char *[]);
910
extern void __prepare_for_exit(void);
@@ -37,32 +38,6 @@ static __wasi_errno_t populate_args(size_t *argc, char ***argv) {
3738
return __wasi_args_get(*argv, argv_buf);
3839
}
3940

40-
static __wasi_errno_t populate_environ(void) {
41-
__wasi_errno_t err;
42-
43-
/* Get the sizes of the arrays we'll have to create to copy in the environment. */
44-
size_t environ_count;
45-
size_t environ_buf_size;
46-
err = __wasi_environ_sizes_get(&environ_count, &environ_buf_size);
47-
if (err != __WASI_ESUCCESS) {
48-
return err;
49-
}
50-
51-
/* Allocate memory for the array of pointers, adding null terminator. */
52-
__environ = malloc(sizeof(char *) * (environ_count + 1));
53-
/* Allocate memory for storing the environment chars. */
54-
char *environ_buf = malloc(sizeof(char) * environ_buf_size);
55-
if (__environ == NULL || environ_buf == NULL) {
56-
return __WASI_ENOMEM;
57-
}
58-
59-
/* Make sure the last pointer in the array is NULL. */
60-
__environ[environ_count] = NULL;
61-
62-
/* Fill the environment chars, and the __environ array with pointers into those chars. */
63-
return __wasi_environ_get(__environ, environ_buf);
64-
}
65-
6641
static __wasi_errno_t populate_libpreopen(void) {
6742
__wasilibc_init_preopen();
6843

@@ -110,9 +85,11 @@ void _start(void) {
11085
_Exit(EX_OSERR);
11186
}
11287

113-
/* Fill in the environment from WASI syscalls. */
114-
if (populate_environ() != __WASI_ESUCCESS) {
115-
_Exit(EX_OSERR);
88+
/* Fill in the environment from WASI syscalls, if needed. */
89+
if (&__wasilibc_populate_environ != NULL) {
90+
if (__wasilibc_populate_environ() != __WASI_ESUCCESS) {
91+
_Exit(EX_OSERR);
92+
}
11693
}
11794

11895
/* Fill in the arguments from WASI syscalls. */
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef __wasi_libc_internal_h
2+
#define __wasi_libc_internal_h
3+
4+
#include <wasi/core.h>
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
void __wasilibc_init_preopen(void);
11+
__wasi_errno_t __wasilibc_populate_environ(void);
12+
13+
#ifdef __cplusplus
14+
}
15+
#endif
16+
17+
#endif

libc-bottom-half/headers/public/wasi/libc.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
extern "C" {
88
#endif
99

10-
void __wasilibc_init_preopen(void);
1110
int __wasilibc_register_preopened_fd(int fd, const char *path);
1211
int __wasilibc_fd_renumber(int fd, int newfd);
1312
int __wasilibc_unlinkat(int fd, const char *path);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <unistd.h>
2+
#include <stdlib.h>
3+
#include <wasi/core.h>
4+
#include <wasi/libc.h>
5+
#include <wasi/libc-internal.h>
6+
7+
char **__environ = NULL;
8+
extern __typeof(__environ) _environ __attribute__((weak, alias("__environ")));
9+
extern __typeof(__environ) environ __attribute__((weak, alias("__environ")));
10+
11+
// This function is referenced by a weak symbol in crt1.c, and we define
12+
// it here in the same source file as __environ, so that this function is
13+
// linked in iff environment variable support is used.
14+
__wasi_errno_t __wasilibc_populate_environ(void) {
15+
__wasi_errno_t err;
16+
17+
// Get the sizes of the arrays we'll have to create to copy in the environment.
18+
size_t environ_count;
19+
size_t environ_buf_size;
20+
err = __wasi_environ_sizes_get(&environ_count, &environ_buf_size);
21+
if (err != __WASI_ESUCCESS) {
22+
return err;
23+
}
24+
if (environ_count == 0) {
25+
return __WASI_ESUCCESS;
26+
}
27+
28+
// Add 1 for the NULL pointer to mark the end, and check for overflow.
29+
size_t num_ptrs = environ_count + 1;
30+
if (num_ptrs == 0) {
31+
return __WASI_ENOMEM;
32+
}
33+
34+
// Allocate memory for storing the environment chars.
35+
char *environ_buf = malloc(environ_buf_size);
36+
if (environ_buf == NULL) {
37+
return __WASI_ENOMEM;
38+
}
39+
40+
// Allocate memory for the array of pointers. This uses `calloc` both to
41+
// handle overflow and to initialize the NULL pointer at the end.
42+
char **environ_ptrs = calloc(num_ptrs, sizeof(char *));
43+
if (environ_ptrs == NULL) {
44+
free(environ_buf);
45+
return __WASI_ENOMEM;
46+
}
47+
48+
// Fill the environment chars, and the __environ array with pointers into those chars.
49+
err = __wasi_environ_get(environ_ptrs, environ_buf);
50+
if (err == __WASI_ESUCCESS) {
51+
__environ = environ_ptrs;
52+
} else {
53+
free(environ_buf);
54+
free(environ_ptrs);
55+
}
56+
return err;
57+
}

0 commit comments

Comments
 (0)