Skip to content

Commit 5d5ab8d

Browse files
fix ENDPROC inside a loop causing loop-stack exhaustion
1 parent 9b021e8 commit 5d5ab8d

3 files changed

Lines changed: 21 additions & 1 deletion

File tree

include/basic/context.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ typedef struct basic_sound_t {
2424
struct basic_sound_t* next; /* Next */
2525
} basic_sound_t;
2626

27+
typedef struct control_stack_state {
28+
uint64_t for_stack_ptr;
29+
uint64_t while_stack_ptr;
30+
uint64_t repeat_stack_ptr;
31+
} control_stack_state;
32+
2733
/**
2834
* @brief BASIC program context.
2935
*
@@ -198,6 +204,11 @@ typedef struct basic_ctx {
198204
*/
199205
int64_t eval_linenum;
200206

207+
/**
208+
* @brief The saved loop pointer state when entering PROC
209+
*/
210+
control_stack_state loop_state_stack[MAX_CALL_STACK_DEPTH];
211+
201212
/**
202213
* @brief FOR loop stack to handle `FOR...NEXT` loops.
203214
*

modules/xm/xm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1591,7 +1591,7 @@ static bool xm_from_memory(const char *filename, const void *bytes, size_t len,
15911591
* @return true on success, false on failure.
15921592
*/
15931593
bool EXPORTED MOD_INIT_SYM(KMOD_ABI)(void) {
1594-
dprintf("xm: loaded - this module is experimental. There may be audio artifacts.\n");
1594+
dprintf("xm: loaded\n");
15951595

15961596
audio_file_loader_t *loader = (audio_file_loader_t *) kmalloc(sizeof(audio_file_loader_t));
15971597
if (!loader) {

src/basic/function.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,9 @@ void proc_statement(struct basic_ctx* ctx)
668668

669669
ctx->fn_type_stack[ctx->call_stack_ptr] = ctx->fn_type; // save caller’s type
670670
ctx->fn_type = RT_NONE;
671+
ctx->loop_state_stack[ctx->call_stack_ptr].for_stack_ptr = ctx->for_stack_ptr;
672+
ctx->loop_state_stack[ctx->call_stack_ptr].while_stack_ptr = ctx->while_stack_ptr;
673+
ctx->loop_state_stack[ctx->call_stack_ptr].repeat_stack_ptr = ctx->repeat_stack_ptr;
671674

672675
while (tokenizer_token(ctx) != NEWLINE && tokenizer_token(ctx) != ENDOFINPUT) {
673676
tokenizer_next(ctx);
@@ -744,6 +747,12 @@ void endproc_statement(struct basic_ctx* ctx)
744747

745748
/* Now restore the *caller*'s return type. */
746749
ctx->fn_type = ctx->fn_type_stack[ctx->call_stack_ptr];
750+
while (ctx->for_stack_ptr > ctx->loop_state_stack[ctx->call_stack_ptr].for_stack_ptr) {
751+
ctx->for_stack_ptr--;
752+
buddy_free(ctx->allocator, ctx->for_stack[ctx->for_stack_ptr].for_variable);
753+
}
754+
ctx->while_stack_ptr = ctx->loop_state_stack[ctx->call_stack_ptr].while_stack_ptr;
755+
ctx->repeat_stack_ptr = ctx->loop_state_stack[ctx->call_stack_ptr].repeat_stack_ptr;
747756

748757
ctx->if_nest_level = 0; // If we exit a proc, we clear the nest level
749758

0 commit comments

Comments
 (0)