From 5377e10532bc91e37dacf017f5ace16c22291f7d Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 17 Aug 2020 07:01:58 -0500 Subject: [PATCH] Address #466? Do not restore pc when returning from top most fiber frame. Also add JANET_DEBUG config define for various debugging related configurations. In fiber.c, when debug is enabled we reallocate the entire stack everytime we push a frame to help uncover use after free errors. --- src/conf/janetconf.h | 1 + src/core/fiber.c | 28 ++++++++++++++++++++++++++++ src/core/vm.c | 13 +++++++++---- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/conf/janetconf.h b/src/conf/janetconf.h index dc964c30..33ae4ab4 100644 --- a/src/conf/janetconf.h +++ b/src/conf/janetconf.h @@ -57,6 +57,7 @@ /* #define JANET_NO_UMASK */ /* Other settings */ +/* #define JANET_DEBUG */ /* #define JANET_PRF */ /* #define JANET_NO_UTC_MKTIME */ /* #define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0) */ diff --git a/src/core/fiber.c b/src/core/fiber.c index 80e8e5e3..1d6e5783 100644 --- a/src/core/fiber.c +++ b/src/core/fiber.c @@ -85,6 +85,22 @@ JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity, int32_t argc, c return janet_fiber_reset(fiber_alloc(capacity), callee, argc, argv); } +#ifdef JANET_DEBUG +/* Test for memory issues by reallocating fiber every time we push a stack frame */ +static void janet_fiber_refresh_memory(JanetFiber *fiber) { + int32_t n = fiber->capacity; + if (n) { + Janet *newData = malloc(sizeof(Janet) * n); + if (NULL == newData) { + JANET_OUT_OF_MEMORY; + } + memcpy(newData, fiber->data, fiber->capacity * sizeof(Janet)); + free(fiber->data); + fiber->data = newData; + } +} +#endif + /* Ensure that the fiber has enough extra capacity */ void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) { Janet *newData = realloc(fiber->data, sizeof(Janet) * n); @@ -173,6 +189,10 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) { if (fiber->capacity < nextstacktop) { janet_fiber_setcapacity(fiber, 2 * nextstacktop); +#ifdef JANET_DEBUG + } else { + janet_fiber_refresh_memory(fiber); +#endif } /* Nil unset stack arguments (Needed for gc correctness) */ @@ -305,6 +325,10 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) { if (fiber->capacity < nextstacktop) { janet_fiber_setcapacity(fiber, 2 * nextstacktop); +#ifdef JANET_DEBUG + } else { + janet_fiber_refresh_memory(fiber); +#endif } Janet *stack = fiber->data + fiber->frame; @@ -367,6 +391,10 @@ void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun) { if (fiber->capacity < nextstacktop) { janet_fiber_setcapacity(fiber, 2 * nextstacktop); +#ifdef JANET_DEBUG + } else { + janet_fiber_refresh_memory(fiber); +#endif } /* Set the next frame */ diff --git a/src/core/vm.c b/src/core/vm.c index 4e5c6b06..a6c75b02 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -95,6 +95,10 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL; vm_commit(); \ return (sig); \ } while (0) +#define vm_return_no_restore(sig, val) do { \ + janet_vm_return_reg[0] = (val); \ + return (sig); \ +} while (0) /* Next instruction variations */ #define maybe_collect() do {\ @@ -623,7 +627,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { Janet retval = stack[D]; int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE; janet_fiber_popframe(fiber); - if (entrance_frame) vm_return(JANET_SIGNAL_OK, retval); + if (entrance_frame) vm_return_no_restore(JANET_SIGNAL_OK, retval); vm_restore(); stack[A] = retval; vm_checkgc_pcnext(); @@ -633,7 +637,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { Janet retval = janet_wrap_nil(); int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE; janet_fiber_popframe(fiber); - if (entrance_frame) vm_return(JANET_SIGNAL_OK, retval); + if (entrance_frame) vm_return_no_restore(JANET_SIGNAL_OK, retval); vm_restore(); stack[A] = retval; vm_checkgc_pcnext(); @@ -1011,8 +1015,9 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { retreg = call_nonfn(fiber, callee); } janet_fiber_popframe(fiber); - if (entrance_frame) - vm_return(JANET_SIGNAL_OK, retreg); + if (entrance_frame) { + vm_return_no_restore(JANET_SIGNAL_OK, retreg); + } vm_restore(); stack[A] = retreg; vm_checkgc_pcnext();