Mercurial > vim
diff src/vim9execute.c @ 23994:3daeb2060f25 v8.2.2539
patch 8.2.2539: Vim9: return from finally block causes a hang
Commit: https://github.com/vim/vim/commit/7e82c5f338efe5661951675565f27f6512901a6e
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Feb 21 21:32:45 2021 +0100
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 https://github.com/vim/vim/issues/7885)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 21 Feb 2021 21:45:03 +0100 |
parents | 9fcd71d0db89 |
children | 5dbed4837ea3 |
line wrap: on
line diff
--- 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 @@ call_def_function( + 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 @@ call_def_function( 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 @@ call_def_function( 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 @@ ex_disassemble(exarg_T *eap) { 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 @@ ex_disassemble(exarg_T *eap) trycont->tct_where); } break; + case ISN_FINALLY: + smsg("%4d FINALLY", current); + break; case ISN_ENDTRY: smsg("%4d ENDTRY", current); break;