diff --git a/src/interpreter.c b/src/interpreter.c index 338853b56f692..35c70a9ead2f1 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -540,6 +540,9 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, s->locals[jl_source_nslots(s->src) + ip] = jl_box_ulong(jl_excstack_state(ct)); if (jl_enternode_scope(stmt)) { jl_value_t *scope = eval_value(jl_enternode_scope(stmt), s); + // GC preserve the scope, since it is not rooted in the `jl_handler_t *` + // and may be removed from jl_current_task by any nested block and then + // replaced later JL_GC_PUSH1(&scope); ct->scope = scope; if (!jl_setjmp(__eh.eh_ctx, 1)) { @@ -606,8 +609,11 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, // equivalent to jl_pop_handler(hand_n_leave), longjmping // to the :enter code above instead, which handles cleanup jl_handler_t *eh = ct->eh; - while (--hand_n_leave > 0) + while (--hand_n_leave > 0) { + // pop GC frames for any skipped handlers + ct->gcstack = eh->gcstack; eh = eh->prev; + } // leave happens during normal control flow, but we must // longjmp to pop the eval_body call for each enter. s->continue_at = next_ip; diff --git a/test/scopedvalues.jl b/test/scopedvalues.jl index 174bc690ac0a2..e9b36d80fc2c4 100644 --- a/test/scopedvalues.jl +++ b/test/scopedvalues.jl @@ -182,3 +182,16 @@ end @test Core.current_scope() === nothing end nothrow_scope() + +# https://github.com/JuliaLang/julia/issues/56062 +@testset "issue #56062" begin + ts = Int[] + try + @with begin + return + end + catch err + finally + push!(ts, 2) + end +end