To: vim_dev@googlegroups.com Subject: Patch 8.2.3361 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3361 Problem: Vim9: crash with nested :while. Solution: Handle skipping better. (Naruhiko Nishino, closes #8778) Files: src/vim9compile.c, src/testdir/test_vim9_script.vim *** ../vim-8.2.3360/src/vim9compile.c 2021-08-15 20:36:24.363246790 +0200 --- src/vim9compile.c 2021-08-20 20:50:00.554684340 +0200 *************** *** 4469,4476 **** // 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; --- 4469,4474 ---- *************** *** 8267,8288 **** // 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; ! // 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, JUMP_IF_FALSE, cctx) == FAIL) ! return FAIL; return p; } --- 8265,8290 ---- // compile "expr" if (compile_expr0(&p, cctx) == FAIL) return NULL; + if (!ends_excmd2(arg, skipwhite(p))) { semsg(_(e_trailing_arg), p); return NULL; } ! 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); ! // "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 p; } *************** *** 8304,8323 **** return NULL; } cctx->ctx_scope = scope->se_outer; ! unwind_locals(cctx, scope->se_local_count); #ifdef FEAT_PROFILE ! // 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); ! // 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); --- 8306,8328 ---- return NULL; } cctx->ctx_scope = scope->se_outer; ! 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); #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); ! // 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); *** ../vim-8.2.3360/src/testdir/test_vim9_script.vim 2021-08-15 20:36:24.363246790 +0200 --- src/testdir/test_vim9_script.vim 2021-08-20 20:46:45.551115044 +0200 *************** *** 2856,2861 **** --- 2856,2944 ---- 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 *** ../vim-8.2.3360/src/version.c 2021-08-19 21:20:36.709042712 +0200 --- src/version.c 2021-08-20 20:48:37.566863032 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3361, /**/ -- Dogs must have a permit signed by the mayor in order to congregate in groups of three or more on private property. [real standing law in Oklahoma, United States of America] /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///