lang: Check stack depth before accessing elements
I tested this code by hand, make sure to do the same if changing.
This commit is contained in:
parent
183df4494b
commit
75c2a5e8fb
1 changed files with 21 additions and 4 deletions
25
lang/vm.c
25
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 <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -10,14 +11,16 @@ struct vm_state {
|
|||
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_destroy(VmState *state) {
|
|||
|
||||
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 @@ void vm_stack_set(VmState state, int index, Object obj) {
|
|||
|
||||
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 @@ Object vm_stack_get(VmState state, int index) {
|
|||
|
||||
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;
|
||||
|
|
Loading…
Add table
Reference in a new issue