patch 8.2.2539: Vim9: return from finally block causes a hang
Problem: Vim9: return from finally block causes a hang.
Solution: Store both the finally and endtry indexes. (closes #7885)
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 6734f4f..d2cc62f 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -26,8 +26,9 @@
typedef struct {
int tcd_frame_idx; // ec_frame_idx at ISN_TRY
int tcd_stack_len; // size of ectx.ec_stack at ISN_TRY
- int tcd_catch_idx; // instruction of the first catch
- int tcd_finally_idx; // instruction of the finally block or :endtry
+ int tcd_catch_idx; // instruction of the first :catch or :finally
+ int tcd_finally_idx; // instruction of the :finally block or zero
+ int tcd_endtry_idx; // instruction of the :endtry
int tcd_caught; // catch block entered
int tcd_cont; // :continue encountered, jump here
int tcd_return; // when TRUE return from end of :finally
@@ -2517,10 +2518,9 @@
+ trystack->ga_len - 1;
if (trycmd != NULL
&& trycmd->tcd_frame_idx == ectx.ec_frame_idx
- && ectx.ec_instr[trycmd->tcd_finally_idx]
- .isn_type != ISN_ENDTRY)
+ && trycmd->tcd_finally_idx != 0)
{
- // jump to ":finally"
+ // jump to ":finally" once
ectx.ec_iidx = trycmd->tcd_finally_idx;
trycmd->tcd_return = TRUE;
}
@@ -2665,8 +2665,9 @@
CLEAR_POINTER(trycmd);
trycmd->tcd_frame_idx = ectx.ec_frame_idx;
trycmd->tcd_stack_len = ectx.ec_stack.ga_len;
- trycmd->tcd_catch_idx = iptr->isn_arg.try.try_catch;
- trycmd->tcd_finally_idx = iptr->isn_arg.try.try_finally;
+ trycmd->tcd_catch_idx = iptr->isn_arg.try.try_ref->try_catch;
+ trycmd->tcd_finally_idx = iptr->isn_arg.try.try_ref->try_finally;
+ trycmd->tcd_endtry_idx = iptr->isn_arg.try.try_ref->try_endtry;
}
break;
@@ -2731,13 +2732,26 @@
trycmd = ((trycmd_T *)trystack->ga_data)
+ trystack->ga_len - i;
trycmd->tcd_cont = iidx;
- iidx = trycmd->tcd_finally_idx;
+ iidx = trycmd->tcd_finally_idx == 0
+ ? trycmd->tcd_endtry_idx : trycmd->tcd_finally_idx;
}
// jump to :finally or :endtry of current try statement
ectx.ec_iidx = iidx;
}
break;
+ case ISN_FINALLY:
+ {
+ garray_T *trystack = &ectx.ec_trystack;
+ trycmd_T *trycmd = ((trycmd_T *)trystack->ga_data)
+ + trystack->ga_len - 1;
+
+ // Reset the index to avoid a return statement jumps here
+ // again.
+ trycmd->tcd_finally_idx = 0;
+ break;
+ }
+
// end of ":try" block
case ISN_ENDTRY:
{
@@ -4348,11 +4362,17 @@
{
try_T *try = &iptr->isn_arg.try;
- smsg("%4d TRY catch -> %d, %s -> %d", current,
- try->try_catch,
- instr[try->try_finally].isn_type == ISN_ENDTRY
- ? "end" : "finally",
- try->try_finally);
+ if (try->try_ref->try_finally == 0)
+ smsg("%4d TRY catch -> %d, endtry -> %d",
+ current,
+ try->try_ref->try_catch,
+ try->try_ref->try_endtry);
+ else
+ smsg("%4d TRY catch -> %d, finally -> %d, endtry -> %d",
+ current,
+ try->try_ref->try_catch,
+ try->try_ref->try_finally,
+ try->try_ref->try_endtry);
}
break;
case ISN_CATCH:
@@ -4369,6 +4389,9 @@
trycont->tct_where);
}
break;
+ case ISN_FINALLY:
+ smsg("%4d FINALLY", current);
+ break;
case ISN_ENDTRY:
smsg("%4d ENDTRY", current);
break;