From d895b1d918f7d56dd9dd564be4820082ba6492e9 Mon Sep 17 00:00:00 2001 From: rbtnn <naru123456789@gmail.com> Date: Fri, 20 Aug 2021 20:54:25 +0200 Subject: [PATCH] patch 8.2.3361: Vim9: crash with nested :while Problem: Vim9: crash with nested :while. Solution: Handle skipping better. (Naruhiko Nishino, closes #8778) --- src/testdir/test_vim9_script.vim | 83 ++++++++++++++++++++++++++++++++ src/version.c | 2 + src/vim9compile.c | 39 ++++++++------- 3 files changed, 107 insertions(+), 17 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 407ace32ab..ffea2acb27 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -2856,6 +2856,89 @@ def Test_for_loop_with_try_continue() CheckDefAndScriptSuccess(lines) enddef +def Test_while_skipped_block() + # test skipped blocks at outside of function + var lines =<< trim END + var result = [] + var n = 0 + if true + n = 1 + while n < 3 + result += [n] + n += 1 + endwhile + else + n = 3 + while n < 5 + result += [n] + n += 1 + endwhile + endif + assert_equal([1, 2], result) + + result = [] + if false + n = 1 + while n < 3 + result += [n] + n += 1 + endwhile + else + n = 3 + while n < 5 + result += [n] + n += 1 + endwhile + endif + assert_equal([3, 4], result) + END + CheckDefAndScriptSuccess(lines) + + # test skipped blocks at inside of function + lines =<< trim END + def DefTrue() + var result = [] + var n = 0 + if true + n = 1 + while n < 3 + result += [n] + n += 1 + endwhile + else + n = 3 + while n < 5 + result += [n] + n += 1 + endwhile + endif + assert_equal([1, 2], result) + enddef + DefTrue() + + def DefFalse() + var result = [] + var n = 0 + if false + n = 1 + while n < 3 + result += [n] + n += 1 + endwhile + else + n = 3 + while n < 5 + result += [n] + n += 1 + endwhile + endif + assert_equal([3, 4], result) + enddef + DefFalse() + END + CheckDefAndScriptSuccess(lines) +enddef + def Test_while_loop() var result = '' var cnt = 0 diff --git a/src/version.c b/src/version.c index 2d890f83c3..e064df3e7b 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3361, /**/ 3360, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 5b47746e35..ccfb4ee16f 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4469,8 +4469,6 @@ compile_subscript( // dict member: dict[key] // string index: text[123] // blob index: blob[123] - // TODO: more arguments - // TODO: recognize list or dict at runtime if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; ppconst->pp_is_const = FALSE; @@ -8267,22 +8265,26 @@ compile_while(char_u *arg, cctx_T *cctx) // compile "expr" if (compile_expr0(&p, cctx) == FAIL) return NULL; + if (!ends_excmd2(arg, skipwhite(p))) { semsg(_(e_trailing_arg), p); return NULL; } - if (bool_on_stack(cctx) == FAIL) - return FAIL; + if (cctx->ctx_skip != SKIP_YES) + { + if (bool_on_stack(cctx) == FAIL) + return FAIL; - // CMDMOD_REV must come before the jump - generate_undo_cmdmods(cctx); + // CMDMOD_REV must come before the jump + generate_undo_cmdmods(cctx); - // "while_end" is set when ":endwhile" is found - if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label, + // "while_end" is set when ":endwhile" is found + if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label, JUMP_IF_FALSE, cctx) == FAIL) - return FAIL; + return FAIL; + } return p; } @@ -8304,20 +8306,23 @@ compile_endwhile(char_u *arg, cctx_T *cctx) return NULL; } cctx->ctx_scope = scope->se_outer; - unwind_locals(cctx, scope->se_local_count); + if (cctx->ctx_skip != SKIP_YES) + { + unwind_locals(cctx, scope->se_local_count); #ifdef FEAT_PROFILE - // count the endwhile before jumping - may_generate_prof_end(cctx, cctx->ctx_lnum); + // count the endwhile before jumping + may_generate_prof_end(cctx, cctx->ctx_lnum); #endif - // At end of ":for" scope jump back to the FOR instruction. - generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label); + // At end of ":for" scope jump back to the FOR instruction. + generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label); - // Fill in the "end" label in the WHILE statement so it can jump here. - // And in any jumps for ":break" - compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label, + // Fill in the "end" label in the WHILE statement so it can jump here. + // And in any jumps for ":break" + compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label, instr->ga_len, cctx); + } vim_free(scope); -- GitLab