diff --git a/LibOS/shim/include/shim_internal.h b/LibOS/shim/include/shim_internal.h index 99e0896c..014511d1 100644 --- a/LibOS/shim/include/shim_internal.h +++ b/LibOS/shim/include/shim_internal.h @@ -145,7 +145,7 @@ static inline PAL_HANDLE __open_shim_stdio (void) return shim_stdio; } -int shim_terminate (void); +int shim_terminate (int err); /* assertions */ #define USE_PAUSE 0 @@ -163,7 +163,7 @@ static inline void do_pause (void); do { \ __sys_printf("bug() " __FILE__ ":%d\n", __LINE__); \ pause(); \ - shim_terminate(); \ + shim_terminate(-ENOTRECOVERABLE); \ } while (0) #if USE_ASSERT == 1 @@ -749,7 +749,8 @@ static inline bool memory_migrated(void * mem) extern void * __load_address, * __load_address_end; extern void * __code_address, * __code_address_end; -int shim_clean (void); +/* cleanup and terminate process, preserve exit code if err == 0 */ +int shim_clean (int err); unsigned long parse_int (const char * str); diff --git a/LibOS/shim/src/ipc/shim_ipc_helper.c b/LibOS/shim/src/ipc/shim_ipc_helper.c index 2610cdc0..cc6f8aed 100644 --- a/LibOS/shim/src/ipc/shim_ipc_helper.c +++ b/LibOS/shim/src/ipc/shim_ipc_helper.c @@ -1034,7 +1034,7 @@ end: barrier(); if (ipc_helper_state == HELPER_HANDEDOVER) { debug("ipc helper thread is the last thread, process exiting\n"); - shim_terminate(); // Same as shim_clean(), but this is the official termination function + shim_terminate(0); // Same as shim_clean(), but this is the official termination function } lock(ipc_helper_lock); diff --git a/LibOS/shim/src/shim_init.c b/LibOS/shim/src/shim_init.c index 2607afaa..5a9ae414 100644 --- a/LibOS/shim/src/shim_init.c +++ b/LibOS/shim/src/shim_init.c @@ -59,7 +59,7 @@ static void handle_failure (PAL_PTR event, PAL_NUM arg, PAL_CONTEXT * context) void __abort(void) { pause(); - shim_terminate(); + shim_terminate(-ENOTRECOVERABLE); } void warn (const char *format, ...) @@ -671,7 +671,7 @@ DEFINE_PROFILE_INTERVAL(init_signal, init); int _err = CALL_INIT(func, ##__VA_ARGS__); \ if (_err < 0) { \ sys_printf("shim_init() in " #func " (%d)\n", _err); \ - shim_terminate(); \ + shim_terminate(_err); \ } \ SAVE_PROFILE_INTERVAL(func); \ } while (0) @@ -1121,18 +1121,19 @@ static void print_profile_result (PAL_HANDLE hdl, struct shim_profile * root, static struct atomic_int in_terminate = { .counter = 0, }; -int shim_terminate (void) +int shim_terminate (int err) { - debug("teminating the whole process\n"); + debug("teminating the whole process (%d)\n", err); /* do last clean-up of the process */ - shim_clean(); + shim_clean(err); - DkProcessExit(0); + DkProcessExit(err); return 0; } -int shim_clean (void) +/* cleanup and terminate process, preserve exit code if err == 0 */ +int shim_clean (int err) { /* preventing multiple cleanup, this is mostly caused by assertion in shim_clean */ @@ -1140,6 +1141,8 @@ int shim_clean (void) if (atomic_read(&in_terminate) > 1) return 0; + if (err != 0) + cur_process.exit_code = err; store_all_msg_persist(); #ifdef PROFILE diff --git a/LibOS/shim/src/sys/shim_exec.c b/LibOS/shim/src/sys/shim_exec.c index fd8f0076..f1361052 100644 --- a/LibOS/shim/src/sys/shim_exec.c +++ b/LibOS/shim/src/sys/shim_exec.c @@ -182,7 +182,7 @@ retry_dump_vmas: SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec); if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0) - shim_terminate(); + shim_terminate(ret); init_brk_from_executable(cur_thread->exec); load_elf_interp(cur_thread->exec); diff --git a/LibOS/shim/src/sys/shim_exit.c b/LibOS/shim/src/sys/shim_exit.c index 58a4e2c1..5a622cf1 100644 --- a/LibOS/shim/src/sys/shim_exit.c +++ b/LibOS/shim/src/sys/shim_exit.c @@ -159,7 +159,7 @@ int try_process_exit (int error_code, int term_signal) */ put_thread(ipc_thread); /* free resources of the thread */ if (!ret) - shim_clean(); + shim_clean(ret); else DkThreadExit(); diff --git a/LibOS/shim/test/regression/00_bootstrap.py b/LibOS/shim/test/regression/00_bootstrap.py index 9b805176..08f7fe67 100644 --- a/LibOS/shim/test/regression/00_bootstrap.py +++ b/LibOS/shim/test/regression/00_bootstrap.py @@ -41,6 +41,7 @@ regression.add_check(name="Shared Object", rv = regression.run_checks() if rv: sys.exit(rv) +# Exit test regression = Regression(loader, "exit") regression.add_check(name="Exit Code Propagation", @@ -48,3 +49,12 @@ regression.add_check(name="Exit Code Propagation", rv = regression.run_checks() if rv: sys.exit(rv) + +# Early abort test +regression = Regression(loader, "init_fail") + +regression.add_check(name="Early abort", + check=lambda res: res[0].code != 42 and res[0].code != 0) + +rv = regression.run_checks() +if rv: sys.exit(rv) diff --git a/LibOS/shim/test/regression/init_fail.c b/LibOS/shim/test/regression/init_fail.c new file mode 100644 index 00000000..5bc4b7ef --- /dev/null +++ b/LibOS/shim/test/regression/init_fail.c @@ -0,0 +1,7 @@ +#include + +int main() +{ + printf("Hello world\n"); + return 42; +} diff --git a/LibOS/shim/test/regression/init_fail.manifest.template b/LibOS/shim/test/regression/init_fail.manifest.template new file mode 100644 index 00000000..5d75a522 --- /dev/null +++ b/LibOS/shim/test/regression/init_fail.manifest.template @@ -0,0 +1,16 @@ +loader.preload = file:$(SHIMPATH) +loader.env.LD_LIBRARY_PATH = /lib +loader.debug_type = none + +fs.mount.lib.type = chroot +fs.mount.lib.path = /lib +fs.mount.lib.uri = file:$(LIBCDIR) + +# purposefully force mount failure to cause early shim abort +fs.mount.test.type = chroot +fs.mount.test.path = /test +fs.mount.test.uri = file:I_DONT_EXIST + +sgx.trusted_files.ld = file:$(LIBCDIR)/ld-linux-x86-64.so.2 +sgx.trusted_files.libc = file:$(LIBCDIR)/libc.so.6 +