diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-07-05 20:24:43 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-07-11 15:49:14 +0200 |
commit | 4ae056867d96b1795fec7f4cfd0f68b124e398cd (patch) | |
tree | 1d9ae3590b83cdd9ea9c37f35f2981d61d526efa | |
parent | 2f77657ae97f84edcd665c4cfe00ef91b9cde1bc (diff) |
lib, vm: reimplement exit() as exception type
Instead of invoking exit(3) from uc_exit(), use a new EXCEPTION_EXIT
exception type to instruct the VM to shutdown cleanly.
This is required to not terminate the host program in case libucode
is embedded and loaded scripts invoke the exit() function.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | lib.c | 7 | ||||
-rw-r--r-- | main.c | 4 | ||||
-rw-r--r-- | types.h | 3 | ||||
-rw-r--r-- | vm.c | 11 | ||||
-rw-r--r-- | vm.h | 1 |
5 files changed, 23 insertions, 3 deletions
@@ -502,12 +502,15 @@ uc_exists(uc_vm *vm, size_t nargs) return ucv_boolean_new(found); } -__attribute__((noreturn)) static uc_value_t * +static uc_value_t * uc_exit(uc_vm *vm, size_t nargs) { int64_t n = uc_cast_int64(uc_get_arg(0)); - exit(n); + vm->arg.s32 = (int32_t)n; + uc_vm_raise_exception(vm, EXCEPTION_EXIT, "Terminated"); + + return NULL; } static uc_value_t * @@ -132,6 +132,10 @@ parse(uc_parse_config *config, uc_source *src, rc = 0; break; + case STATUS_EXIT: + rc = (int)ucv_int64_get(res); + break; + case ERROR_COMPILE: rc = -1; break; @@ -217,7 +217,8 @@ typedef enum { EXCEPTION_RUNTIME, EXCEPTION_TYPE, EXCEPTION_REFERENCE, - EXCEPTION_USER + EXCEPTION_USER, + EXCEPTION_EXIT } uc_exception_type_t; typedef struct { @@ -77,6 +77,7 @@ static const char *exception_type_strings[] = { [EXCEPTION_TYPE] = "Type error", [EXCEPTION_REFERENCE] = "Reference error", [EXCEPTION_USER] = "Error", + [EXCEPTION_EXIT] = "Exit" }; @@ -2256,6 +2257,16 @@ uc_vm_execute_chunk(uc_vm *vm, uc_value_t **retvalp) /* previous instruction raised exception */ if (vm->exception.type != EXCEPTION_NONE) { + /* VM termination was requested */ + if (vm->exception.type == EXCEPTION_EXIT) { + uc_vm_reset_callframes(vm); + + if (retvalp) + *retvalp = ucv_int64_new(vm->arg.s32); + + return STATUS_EXIT; + } + /* walk up callframes until something handles the exception or the root is reached */ while (!uc_vm_handle_exception(vm)) { /* no further callframe to pop, report unhandled exception and terminate */ @@ -103,6 +103,7 @@ enum insn_type { typedef enum { STATUS_OK, + STATUS_EXIT, ERROR_COMPILE, ERROR_RUNTIME } uc_vm_status_t; |