Skip to content

Commit 2e476c9

Browse files
bounds-check call stack
1 parent 052ae26 commit 2e476c9

5 files changed

Lines changed: 61 additions & 20 deletions

File tree

include/basic/flow_control.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,6 @@ void error_statement(struct basic_ctx* ctx);
215215

216216
void continue_statement(struct basic_ctx* ctx);
217217

218+
bool new_stack_frame(struct basic_ctx* ctx);
219+
220+
void pop_stack_frame(struct basic_ctx* ctx);

src/basic/flow_control.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@
77

88
extern bool debug;
99

10+
bool new_stack_frame(struct basic_ctx* ctx) {
11+
if (ctx->call_stack_ptr >= MAX_CALL_STACK_DEPTH) {
12+
tokenizer_error_print(ctx, "Call stack depth exceeded");
13+
return false;
14+
}
15+
++ctx->call_stack_ptr;
16+
return true;
17+
}
18+
19+
void pop_stack_frame(struct basic_ctx* ctx) {
20+
if (ctx->call_stack_ptr > 0) {
21+
--ctx->call_stack_ptr;
22+
}
23+
}
24+
1025
bool conditional(struct basic_ctx* ctx) {
1126
basic_debug("line %ld conditional\n", ctx->current_linenum);
1227

@@ -184,7 +199,9 @@ void gosub_statement(struct basic_ctx* ctx)
184199

185200
if (ctx->call_stack_ptr < MAX_CALL_STACK_DEPTH) {
186201
ctx->call_stack[ctx->call_stack_ptr] = tokenizer_num(ctx, NUMBER);
187-
ctx->call_stack_ptr++;
202+
if (!new_stack_frame(ctx)) {
203+
return;
204+
}
188205
init_local_heap(ctx);
189206
jump_linenum(linenum, ctx);
190207
} else {
@@ -197,7 +214,7 @@ void return_statement(struct basic_ctx* ctx)
197214
accept_or_return(RETURN, ctx);
198215
if (ctx->call_stack_ptr > 0) {
199216
free_local_heap(ctx);
200-
ctx->call_stack_ptr--;
217+
pop_stack_frame(ctx);
201218
jump_linenum(ctx->call_stack[ctx->call_stack_ptr], ctx);
202219
} else {
203220
tokenizer_error_print(ctx, "RETURN without GOSUB");

src/basic/function.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,9 @@ const char* basic_eval_str_fn(const char* fn_name, struct basic_ctx* ctx)
221221
struct ub_proc_fn_def* def = basic_find_fn(fn_name + 2, ctx);
222222
const char* rv = "";
223223
if (def) {
224-
ctx->call_stack_ptr++;
224+
if (!new_stack_frame(ctx)) {
225+
return "";
226+
}
225227
init_local_heap(ctx);
226228

227229
int bracket_depth = 0;
@@ -265,7 +267,7 @@ const char* basic_eval_str_fn(const char* fn_name, struct basic_ctx* ctx)
265267
buddy_free(ctx->allocator, atomic);
266268

267269
free_local_heap(ctx);
268-
ctx->call_stack_ptr--;
270+
pop_stack_frame(ctx);
269271

270272
return rv;
271273
}
@@ -330,7 +332,9 @@ int64_t basic_eval_int_fn(const char* fn_name, struct basic_ctx* ctx)
330332
struct ub_proc_fn_def* def = basic_find_fn(fn_name + 2, ctx);
331333
int64_t rv = 0;
332334
if (def) {
333-
ctx->call_stack_ptr++;
335+
if (!new_stack_frame(ctx)) {
336+
return 0;
337+
}
334338
init_local_heap(ctx);
335339

336340
int bracket_depth = 0;
@@ -370,7 +374,7 @@ int64_t basic_eval_int_fn(const char* fn_name, struct basic_ctx* ctx)
370374
buddy_free(ctx->allocator, atomic);
371375

372376
free_local_heap(ctx);
373-
ctx->call_stack_ptr--;
377+
pop_stack_frame(ctx);
374378

375379
return rv;
376380
}
@@ -382,7 +386,10 @@ void basic_eval_double_fn(const char* fn_name, struct basic_ctx* ctx, double* re
382386
{
383387
struct ub_proc_fn_def* def = basic_find_fn(fn_name + 2, ctx);
384388
if (def) {
385-
ctx->call_stack_ptr++;
389+
if (!new_stack_frame(ctx)) {
390+
*res = 0;
391+
return;
392+
}
386393
init_local_heap(ctx);
387394

388395
int bracket_depth = 0;
@@ -427,7 +434,7 @@ void basic_eval_double_fn(const char* fn_name, struct basic_ctx* ctx, double* re
427434
buddy_free(ctx->allocator, atomic);
428435

429436
free_local_heap(ctx);
430-
ctx->call_stack_ptr--;
437+
pop_stack_frame(ctx);
431438

432439
return;
433440
}
@@ -612,19 +619,23 @@ void proc_statement(struct basic_ctx* ctx)
612619
struct ub_proc_fn_def* def = basic_find_fn(procname, ctx);
613620
if (def) {
614621
if (*ctx->ptr == '(' && *(ctx->ptr + 1) != ')') {
615-
ctx->call_stack_ptr++;
622+
if (!new_stack_frame(ctx)) {
623+
return;
624+
}
616625
init_local_heap(ctx);
617626

618627
int bracket_depth = 0;
619628
const char* item_begin = ctx->ptr;
620629
struct ub_param* param = def->params;
621630
while (extract_comma_list(def, ctx, &bracket_depth, &item_begin, &param));
622631

623-
ctx->call_stack_ptr--;
632+
pop_stack_frame(ctx);
624633
} else {
625-
ctx->call_stack_ptr++;
634+
if (!new_stack_frame(ctx)) {
635+
return;
636+
}
626637
init_local_heap(ctx);
627-
ctx->call_stack_ptr--;
638+
pop_stack_frame(ctx);
628639
}
629640

630641
ctx->fn_type_stack[ctx->call_stack_ptr] = ctx->fn_type; // save caller’s type
@@ -638,7 +649,9 @@ void proc_statement(struct basic_ctx* ctx)
638649
if (ctx->call_stack_ptr < MAX_CALL_STACK_DEPTH) {
639650
ctx->call_stack[ctx->call_stack_ptr] = tokenizer_num(ctx, NUMBER);
640651
basic_debug("PROC from %lu returning line %lu, PROC %s on line %lu\n", ctx->current_linenum, ctx->call_stack[ctx->call_stack_ptr], procname, def->line);
641-
ctx->call_stack_ptr++;
652+
if (!new_stack_frame(ctx)) {
653+
return;
654+
}
642655
jump_linenum(def->line, ctx);
643656
} else {
644657
tokenizer_error_print(ctx, "PROC: stack exhausted");
@@ -699,7 +712,7 @@ void endproc_statement(struct basic_ctx* ctx)
699712

700713
if (ctx->call_stack_ptr > 0) {
701714
free_local_heap(ctx);
702-
ctx->call_stack_ptr--;
715+
pop_stack_frame(ctx);
703716

704717
/* Now restore the *caller*'s return type. */
705718
ctx->fn_type = ctx->fn_type_stack[ctx->call_stack_ptr];

src/basic/main.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,9 @@ void library_statement(struct basic_ctx *ctx) {
450450
if (ctx->call_stack_ptr < MAX_CALL_STACK_DEPTH) {
451451
ctx->call_stack[ctx->call_stack_ptr] = next_line;
452452
ctx->fn_type_stack[ctx->call_stack_ptr] = ctx->fn_type; // save caller’s type
453-
ctx->call_stack_ptr++;
453+
if (!new_stack_frame(ctx)) {
454+
return;
455+
}
454456
init_local_heap(ctx);
455457
ctx->fn_type = RT_NONE;
456458
jump_linenum(def->line, ctx);
@@ -700,7 +702,9 @@ void eval_statement(struct basic_ctx *ctx) {
700702
*/
701703
ctx->eval_linenum = ctx->current_linenum;
702704
ctx->call_stack[ctx->call_stack_ptr] = ctx->current_linenum;
703-
ctx->call_stack_ptr++;
705+
if (!new_stack_frame(ctx)) {
706+
return;
707+
}
704708
init_local_heap(ctx);
705709

706710
jump_linenum(EVAL_LINE, ctx);
@@ -741,7 +745,7 @@ void basic_run(struct basic_ctx *ctx) {
741745
ctx->errored = false;
742746
if (ctx->call_stack_ptr > 0) {
743747
free_local_heap(ctx);
744-
ctx->call_stack_ptr--;
748+
pop_stack_frame(ctx);
745749
if (jump_linenum(ctx->call_stack[ctx->call_stack_ptr], ctx)) {
746750
line_statement(ctx);
747751
}

src/basic/tokenizer.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,11 @@ void tokenizer_error_print(struct basic_ctx* ctx, const char* error)
293293
if (def && ctx->call_stack_ptr < MAX_CALL_STACK_DEPTH) {
294294
buddy_free(ctx->allocator, ctx->error_handler);
295295
ctx->error_handler = NULL;
296-
ctx->call_stack_ptr++;
296+
if (!new_stack_frame(ctx)) {
297+
return;
298+
}
297299
init_local_heap(ctx);
298-
ctx->call_stack_ptr--;
300+
pop_stack_frame(ctx);
299301
ctx->fn_type_stack[ctx->call_stack_ptr] = ctx->fn_type; // save caller’s type
300302
ctx->fn_type = RT_NONE;
301303
/*Move to next line */
@@ -305,7 +307,9 @@ void tokenizer_error_print(struct basic_ctx* ctx, const char* error)
305307
accept_or_return(NEWLINE, ctx);
306308
/* Return point is the line after the error */
307309
ctx->call_stack[ctx->call_stack_ptr] = tokenizer_num(ctx, NUMBER);
308-
ctx->call_stack_ptr++;
310+
if (!new_stack_frame(ctx)) {
311+
return;
312+
}
309313
if (!jump_linenum(def->line, ctx)) {
310314
setforeground(COLOUR_LIGHTRED);
311315
kprintf("Error on line %ld: Unable to call error handler 'PROC%s', missing line %lu\n", ctx->current_linenum, ctx->error_handler, def->line);

0 commit comments

Comments
 (0)