diff options
author | rbtnn <naru123456789@gmail.com> | 2021-08-20 20:54:25 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-08-20 20:54:25 +0200 |
commit | d895b1d918f7d56dd9dd564be4820082ba6492e9 (patch) | |
tree | fac233d7aa5b0b1428b32dbc16ff6b99b0ba1143 | |
parent | 5aec755b678cfd434b8ea2158d06992f33e1ff80 (diff) | |
download | vim-git-d895b1d918f7d56dd9dd564be4820082ba6492e9.tar.gz |
patch 8.2.3361: Vim9: crash with nested :whilev8.2.3361
Problem: Vim9: crash with nested :while.
Solution: Handle skipping better. (Naruhiko Nishino, closes #8778)
-rw-r--r-- | src/testdir/test_vim9_script.vim | 83 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | 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 407ace32a..ffea2acb2 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 2d890f83c..e064df3e7 100644 --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3361, +/**/ 3360, /**/ 3359, diff --git a/src/vim9compile.c b/src/vim9compile.c index 5b47746e3..ccfb4ee16 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); |