diff --git a/src/context.c b/src/context.c index 2312156..c8c11ae 100644 --- a/src/context.c +++ b/src/context.c @@ -589,21 +589,22 @@ apfl_ctx_new(struct apfl_allocator base_allocator) return NULL; } - apfl_gc_init(&ctx->gc, base_allocator, get_roots, ctx); - + // It's important that we initialize all these before initializing the + // garbage collector, otherwise it might try to follow invalid pointers. + ctx->error_handler = NULL; + ctx->panic_callback = NULL; + ctx->panic_callback_data = NULL; ctx->toplevel_stack = apfl_stack_new(); ctx->call_stack = call_stack_new(); + ctx->globals = NULL; + ctx->iterative_runners = iterative_runners_list_new(); + + apfl_gc_init(&ctx->gc, base_allocator, get_roots, ctx); if ((ctx->globals = apfl_scope_new(&ctx->gc)) == NULL) { goto error; } - ctx->error_handler = NULL; - ctx->panic_callback = NULL; - ctx->panic_callback_data = NULL; - - ctx->iterative_runners = iterative_runners_list_new(); - if (!init_globals(ctx)) { goto error; } @@ -663,9 +664,34 @@ find_iterative_runner(apfl_ctx ctx, apfl_iterative_runner runner, size_t *index) return false; } -bool -apfl_ctx_register_iterative_runner(apfl_ctx ctx, apfl_iterative_runner runner) +struct iterative_runner_tmproot_data { + struct gc *gc; + bool ok; +}; + +static void +ctx_register_iterative_runner_tmproot(void *opaque, struct gc_object *object) { + struct iterative_runner_tmproot_data *data = opaque; + if (!data->ok) { + return; + } + data->ok = apfl_gc_tmproot_add(data->gc, object); +} + +static bool +ctx_register_iterative_runner_inner(apfl_ctx ctx, apfl_iterative_runner runner) +{ + struct iterative_runner_tmproot_data data = { + .gc = &ctx->gc, + .ok = true + }; + apfl_iterative_runner_visit_gc_objects(runner, ctx_register_iterative_runner_tmproot, &data); + + if (!data.ok) { + return false; + } + if (find_iterative_runner(ctx, runner, NULL)) { return true; } @@ -681,6 +707,15 @@ apfl_ctx_register_iterative_runner(apfl_ctx ctx, apfl_iterative_runner runner) ); } +bool +apfl_ctx_register_iterative_runner(apfl_ctx ctx, apfl_iterative_runner runner) +{ + size_t tmproots = apfl_gc_tmproots_begin(&ctx->gc); + bool out = ctx_register_iterative_runner_inner(ctx, runner); + apfl_gc_tmproots_restore(&ctx->gc, tmproots); + return out; +} + void apfl_ctx_unregister_iterative_runner(apfl_ctx ctx, apfl_iterative_runner runner) {