diff --git a/lang/vm.c b/lang/vm.c index abb4152..f9a38ec 100644 --- a/lang/vm.c +++ b/lang/vm.c @@ -2,6 +2,7 @@ // Copyright (c) 2023 John Watts and the LuminaSensum contributors #include "vm.h" +#include "error.h" #include "object.h" #include #include @@ -10,14 +11,16 @@ Object *stack; int stack_base; int stack_next; + int stack_size; }; VmState vm_create(void) { struct vm_state *state = malloc(sizeof(struct vm_state)); - Object *stack = malloc(sizeof(Object) * 16); - state->stack = stack; + state->stack_size = 16; state->stack_base = 0; state->stack_next = 0; + Object *stack = malloc(sizeof(Object) * state->stack_size); + state->stack = stack; return (VmState)state; } @@ -30,7 +33,10 @@ void vm_stack_set(VmState state, int index, Object obj) { struct vm_state *priv = (struct vm_state *)state; - Object *stack_pos = &priv->stack[priv->stack_base + index]; + int offset = priv->stack_base + index; + abort_if(index < 0, "vm_stack_set: negative value"); + abort_if(offset >= priv->stack_next, "vm_stack_set: stack overflow"); + Object *stack_pos = &priv->stack[offset]; Object old = *stack_pos; if (old != NULL) { object_drop(stack_pos); @@ -40,7 +46,10 @@ Object vm_stack_get(VmState state, int index) { struct vm_state *priv = (struct vm_state *)state; - Object obj = priv->stack[priv->stack_base + index]; + int offset = priv->stack_base + index; + abort_if(index < 0, "vm_stack_get: negative value"); + abort_if(offset >= priv->stack_next, "vm_stack_get: stack overflow"); + Object obj = priv->stack[offset]; if (obj != NULL) { object_hold(obj); } @@ -49,11 +58,19 @@ void vm_stack_push(VmState state, Object obj) { struct vm_state *priv = (struct vm_state *)state; + // stack_next starts at 0, stack_size starts at 1 + // Convert stack_size to a max stack offset to compensate + int max_stack = priv->stack_size - 1; + // Check if stack_next is outside the stack before + // writing to it + abort_if(priv->stack_next > max_stack, "vm_stack_push: stack overflow"); priv->stack[priv->stack_next++] = obj; } Object vm_stack_pop(VmState state) { struct vm_state *priv = (struct vm_state *)state; + abort_if(priv->stack_next <= priv->stack_base, + "vm_stack_pop: stack base underflow"); Object obj = priv->stack[--priv->stack_next]; priv->stack[priv->stack_next] = NULL; return obj;