Skip to content

Call populate_args only if we actually need command-line arguments #112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions expected/wasm32-wasi/defined-symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ __ofl_lock
__ofl_unlock
__optpos
__optreset
__original_main
__overflow
__p1evll
__pio2_hi
Expand Down
4 changes: 3 additions & 1 deletion libc-bottom-half/cloudlibc/src/include/stdlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,11 @@ typedef __wchar_t wchar_t;
#define MB_CUR_MAX_L MB_CUR_MAX_L

#define alloca(size) __builtin_alloca(size)
#endif

__BEGIN_DECLS
_Noreturn void _Exit(int);
#ifdef __wasilibc_unmodified_upstream
size_t MB_CUR_MAX_L(__locale_t);
long a64l(const char *);
#endif
Expand Down Expand Up @@ -196,8 +198,8 @@ size_t wcstombs_l(char *__restrict, const wchar_t *__restrict, size_t,
__locale_t);
int wctomb(char *, wchar_t);
int wctomb_l(char *, wchar_t, __locale_t);
__END_DECLS
#endif
__END_DECLS

#if _CLOUDLIBC_INLINE_FUNCTIONS
#ifdef __wasilibc_unmodified_upstream
Expand Down
61 changes: 5 additions & 56 deletions libc-bottom-half/crt/crt1.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,10 @@

__wasi_errno_t __wasilibc_populate_environ(void) __attribute__((weak));
extern void __wasm_call_ctors(void);
extern int main(int, char *[]);
extern int __original_main(void);
extern void __prepare_for_exit(void);
void _Exit(int) __attribute__((noreturn));

static __wasi_errno_t populate_args(size_t *argc, char ***argv) {
__wasi_errno_t err;

// Get the sizes of the arrays we'll have to create to copy in the args.
size_t argv_buf_size;
size_t new_argc;
err = __wasi_args_sizes_get(&new_argc, &argv_buf_size);
if (err != __WASI_ESUCCESS) {
return err;
}
if (new_argc == 0) {
return __WASI_ESUCCESS;
}

// Add 1 for the NULL pointer to mark the end, and check for overflow.
size_t num_ptrs = new_argc + 1;
if (num_ptrs == 0) {
return __WASI_ENOMEM;
}

// Allocate memory for storing the argument chars.
char *argv_buf = malloc(argv_buf_size);
if (argv_buf == NULL) {
return __WASI_ENOMEM;
}

// Allocate memory for the array of pointers. This uses `calloc` both to
// handle overflow and to initialize the NULL pointer at the end.
char **argv_ptrs = calloc(num_ptrs, sizeof(char *));
if (argv_ptrs == NULL) {
free(argv_buf);
return __WASI_ENOMEM;
}

// Fill the argument chars, and the argv array with pointers into those chars.
err = __wasi_args_get(argv_ptrs, argv_buf);
if (err == __WASI_ESUCCESS) {
*argc = new_argc;
*argv = argv_ptrs;
} else {
free(argv_buf);
free(argv_ptrs);
}
return err;
}

static __wasi_errno_t populate_libpreopen(void) {
__wasilibc_init_preopen();

Expand Down Expand Up @@ -110,18 +64,13 @@ void _start(void) {
}
}

// Fill in the arguments from WASI syscalls.
size_t argc;
char **argv;
if (populate_args(&argc, &argv) != __WASI_ESUCCESS) {
_Exit(EX_OSERR);
}

// The linker synthesizes this to call constructors.
__wasm_call_ctors();

// Call main with the arguments.
int r = main(argc, argv);
// Call `__original_main` which will either be a compiler-synthesized
// function which calls `main` with no arguemnts, or a libc routine
// which populates `argv` and `argc` and calls `main` with them.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment accurate?

Is this more like.. ".. will either be the application's zero-argument main function (renamed by the compiler) or a libc routine which populates argv and argc and calls the application's two-argument main."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I guess I was trying to keep it abstract here, but it isn't essential. I've now updated the comment to your suggested wording.

int r = __original_main();

// Call atexit functions, destructors, stdio cleanup, etc.
__prepare_for_exit();
Expand Down
53 changes: 53 additions & 0 deletions libc-bottom-half/sources/__original_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <wasi/core.h>
#include <wasi/libc.h>
#include <stdlib.h>
#include <sysexits.h>

// The user's `main` function, expecting arguments.
int main(int argc, char *argv[]);

// If the user's `main` function expects arguments, the compiler won't emit
// an `__original_main` function so this version will get linked in, which
// initializes the argument data and calls `main`.
int __original_main(void) {
__wasi_errno_t err;

// Get the sizes of the arrays we'll have to create to copy in the args.
size_t argv_buf_size;
size_t argc;
err = __wasi_args_sizes_get(&argc, &argv_buf_size);
if (err != __WASI_ESUCCESS) {
_Exit(EX_OSERR);
}

// Add 1 for the NULL pointer to mark the end, and check for overflow.
size_t num_ptrs = argc + 1;
if (num_ptrs == 0) {
_Exit(EX_SOFTWARE);
}

// Allocate memory for storing the argument chars.
char *argv_buf = malloc(argv_buf_size);
if (argv_buf == NULL) {
_Exit(EX_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 **argv = calloc(num_ptrs, sizeof(char *));
if (argv == NULL) {
free(argv_buf);
_Exit(EX_SOFTWARE);
}

// Fill the argument chars, and the argv array with pointers into those chars.
err = __wasi_args_get(argv, argv_buf);
if (err != __WASI_ESUCCESS) {
free(argv_buf);
free(argv);
_Exit(EX_OSERR);
}

// Call main with the arguments!
return main(argc, argv);
}