1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 02:59:54 +00:00

Fix some stack overflow bugs.

This commit is contained in:
Calvin Rose 2019-08-19 01:19:51 -04:00
parent 0360942942
commit 292be33b9d
6 changed files with 25 additions and 10 deletions

View File

@ -2,6 +2,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## Unreleased ## Unreleased
- Change default fiber stack limit to the maximum value of a 32 bit signed integer.
- Some bug fixes with `jpm` - Some bug fixes with `jpm`
- Add `os/arch` to get ISA that janet was compiled for - Add `os/arch` to get ISA that janet was compiled for
- Add color to stacktraces via `(dyn :err-color)` - Add color to stacktraces via `(dyn :err-color)`

View File

@ -14,7 +14,7 @@ option('int_types', type : 'boolean', value : true)
option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024) option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024)
option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200) option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200)
option('max_macro_expand', type : 'integer', min : 1, max : 8000, value : 200) option('max_macro_expand', type : 'integer', min : 1, max : 8000, value : 200)
option('stack_max', type : 'integer', min : 8096, max : 1000000000, value : 16384) option('stack_max', type : 'integer', min : 8096, max : 0x7fffffff, value : 0x7fffffff)
option('arch_name', type : 'string', value: '') option('arch_name', type : 'string', value: '')
option('os_name', type : 'string', value: '') option('os_name', type : 'string', value: '')

View File

@ -64,7 +64,9 @@ void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth) {
Janet *newData; Janet *newData;
Janet *old = array->data; Janet *old = array->data;
if (capacity <= array->capacity) return; if (capacity <= array->capacity) return;
capacity *= growth; int64_t new_capacity = capacity * growth;
if (new_capacity > INT32_MAX) new_capacity = INT32_MAX;
capacity = (int32_t) new_capacity;
newData = realloc(old, capacity * sizeof(Janet)); newData = realloc(old, capacity * sizeof(Janet));
if (NULL == newData) { if (NULL == newData) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;

View File

@ -87,19 +87,27 @@ void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) {
fiber->capacity = n; fiber->capacity = n;
} }
/* Grow fiber if needed */
static void janet_fiber_grow(JanetFiber *fiber, int32_t needed) {
int32_t cap = needed > (INT32_MAX / 2) ? INT32_MAX : 2 * needed;
janet_fiber_setcapacity(fiber, cap);
}
/* Push a value on the next stack frame */ /* Push a value on the next stack frame */
void janet_fiber_push(JanetFiber *fiber, Janet x) { void janet_fiber_push(JanetFiber *fiber, Janet x) {
if (fiber->stacktop == INT32_MAX) janet_panic("stack overflow");
if (fiber->stacktop >= fiber->capacity) { if (fiber->stacktop >= fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * fiber->stacktop); janet_fiber_grow(fiber, fiber->stacktop);
} }
fiber->data[fiber->stacktop++] = x; fiber->data[fiber->stacktop++] = x;
} }
/* Push 2 values on the next stack frame */ /* Push 2 values on the next stack frame */
void janet_fiber_push2(JanetFiber *fiber, Janet x, Janet y) { void janet_fiber_push2(JanetFiber *fiber, Janet x, Janet y) {
if (fiber->stacktop >= INT32_MAX - 1) janet_panic("stack overflow");
int32_t newtop = fiber->stacktop + 2; int32_t newtop = fiber->stacktop + 2;
if (newtop > fiber->capacity) { if (newtop > fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * newtop); janet_fiber_grow(fiber, newtop);
} }
fiber->data[fiber->stacktop] = x; fiber->data[fiber->stacktop] = x;
fiber->data[fiber->stacktop + 1] = y; fiber->data[fiber->stacktop + 1] = y;
@ -108,9 +116,10 @@ void janet_fiber_push2(JanetFiber *fiber, Janet x, Janet y) {
/* Push 3 values on the next stack frame */ /* Push 3 values on the next stack frame */
void janet_fiber_push3(JanetFiber *fiber, Janet x, Janet y, Janet z) { void janet_fiber_push3(JanetFiber *fiber, Janet x, Janet y, Janet z) {
if (fiber->stacktop >= INT32_MAX - 2) janet_panic("stack overflow");
int32_t newtop = fiber->stacktop + 3; int32_t newtop = fiber->stacktop + 3;
if (newtop > fiber->capacity) { if (newtop > fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * newtop); janet_fiber_grow(fiber, newtop);
} }
fiber->data[fiber->stacktop] = x; fiber->data[fiber->stacktop] = x;
fiber->data[fiber->stacktop + 1] = y; fiber->data[fiber->stacktop + 1] = y;
@ -120,9 +129,10 @@ void janet_fiber_push3(JanetFiber *fiber, Janet x, Janet y, Janet z) {
/* Push an array on the next stack frame */ /* Push an array on the next stack frame */
void janet_fiber_pushn(JanetFiber *fiber, const Janet *arr, int32_t n) { void janet_fiber_pushn(JanetFiber *fiber, const Janet *arr, int32_t n) {
if (fiber->stacktop > INT32_MAX - n) janet_panic("stack overflow");
int32_t newtop = fiber->stacktop + n; int32_t newtop = fiber->stacktop + n;
if (newtop > fiber->capacity) { if (newtop > fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * newtop); janet_fiber_grow(fiber, newtop);
} }
memcpy(fiber->data + fiber->stacktop, arr, n * sizeof(Janet)); memcpy(fiber->data + fiber->stacktop, arr, n * sizeof(Janet));
fiber->stacktop = newtop; fiber->stacktop = newtop;

View File

@ -628,6 +628,9 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
VM_OP(JOP_TAILCALL) { VM_OP(JOP_TAILCALL) {
Janet callee = stack[D]; Janet callee = stack[D];
if (fiber->stacktop > fiber->maxstack) {
vm_throw("stack overflow");
}
if (janet_checktype(callee, JANET_KEYWORD)) { if (janet_checktype(callee, JANET_KEYWORD)) {
vm_commit(); vm_commit();
callee = resolve_method(callee, fiber); callee = resolve_method(callee, fiber);

View File

@ -171,11 +171,10 @@ extern "C" {
/* Maximum depth to follow table prototypes before giving up and returning nil. */ /* Maximum depth to follow table prototypes before giving up and returning nil. */
#define JANET_MAX_MACRO_EXPAND 200 #define JANET_MAX_MACRO_EXPAND 200
/* Define max stack size for stacks before raising a stack overflow error. /* Define default max stack size for stacks before raising a stack overflow error.
* If this is not defined, fiber stacks can grow without limit (until memory * This can also be set on a per fiber basis. */
* runs out) */
#ifndef JANET_STACK_MAX #ifndef JANET_STACK_MAX
#define JANET_STACK_MAX 16384 #define JANET_STACK_MAX 0x7fffffff
#endif #endif
/* Use nanboxed values - uses 8 bytes per value instead of 12 or 16. /* Use nanboxed values - uses 8 bytes per value instead of 12 or 16.