summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-07-05 20:24:43 +0200
committerJo-Philipp Wich <jo@mein.io>2021-07-11 15:49:14 +0200
commit4ae056867d96b1795fec7f4cfd0f68b124e398cd (patch)
tree1d9ae3590b83cdd9ea9c37f35f2981d61d526efa
parent2f77657ae97f84edcd665c4cfe00ef91b9cde1bc (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.c7
-rw-r--r--main.c4
-rw-r--r--types.h3
-rw-r--r--vm.c11
-rw-r--r--vm.h1
5 files changed, 23 insertions, 3 deletions
diff --git a/lib.c b/lib.c
index 750acfb..cd0f582 100644
--- a/lib.c
+++ b/lib.c
@@ -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 *
diff --git a/main.c b/main.c
index 6c763cd..b420051 100644
--- a/main.c
+++ b/main.c
@@ -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;
diff --git a/types.h b/types.h
index 710f6fc..b4c33fc 100644
--- a/types.h
+++ b/types.h
@@ -217,7 +217,8 @@ typedef enum {
EXCEPTION_RUNTIME,
EXCEPTION_TYPE,
EXCEPTION_REFERENCE,
- EXCEPTION_USER
+ EXCEPTION_USER,
+ EXCEPTION_EXIT
} uc_exception_type_t;
typedef struct {
diff --git a/vm.c b/vm.c
index 15e510d..f4c56db 100644
--- a/vm.c
+++ b/vm.c
@@ -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 */
diff --git a/vm.h b/vm.h
index 520cf62..c4952a0 100644
--- a/vm.h
+++ b/vm.h
@@ -103,6 +103,7 @@ enum insn_type {
typedef enum {
STATUS_OK,
+ STATUS_EXIT,
ERROR_COMPILE,
ERROR_RUNTIME
} uc_vm_status_t;