mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.3361: Vim9: crash with nested :while
Problem: Vim9: crash with nested :while. Solution: Handle skipping better. (Naruhiko Nishino, closes #8778)
This commit is contained in:
@@ -2856,6 +2856,89 @@ def Test_for_loop_with_try_continue()
|
|||||||
CheckDefAndScriptSuccess(lines)
|
CheckDefAndScriptSuccess(lines)
|
||||||
enddef
|
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()
|
def Test_while_loop()
|
||||||
var result = ''
|
var result = ''
|
||||||
var cnt = 0
|
var cnt = 0
|
||||||
|
@@ -755,6 +755,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3361,
|
||||||
/**/
|
/**/
|
||||||
3360,
|
3360,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -4469,8 +4469,6 @@ compile_subscript(
|
|||||||
// dict member: dict[key]
|
// dict member: dict[key]
|
||||||
// string index: text[123]
|
// string index: text[123]
|
||||||
// blob index: blob[123]
|
// blob index: blob[123]
|
||||||
// TODO: more arguments
|
|
||||||
// TODO: recognize list or dict at runtime
|
|
||||||
if (generate_ppconst(cctx, ppconst) == FAIL)
|
if (generate_ppconst(cctx, ppconst) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
ppconst->pp_is_const = FALSE;
|
ppconst->pp_is_const = FALSE;
|
||||||
@@ -8267,22 +8265,26 @@ compile_while(char_u *arg, cctx_T *cctx)
|
|||||||
// compile "expr"
|
// compile "expr"
|
||||||
if (compile_expr0(&p, cctx) == FAIL)
|
if (compile_expr0(&p, cctx) == FAIL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!ends_excmd2(arg, skipwhite(p)))
|
if (!ends_excmd2(arg, skipwhite(p)))
|
||||||
{
|
{
|
||||||
semsg(_(e_trailing_arg), p);
|
semsg(_(e_trailing_arg), p);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bool_on_stack(cctx) == FAIL)
|
if (cctx->ctx_skip != SKIP_YES)
|
||||||
return FAIL;
|
{
|
||||||
|
if (bool_on_stack(cctx) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
// CMDMOD_REV must come before the jump
|
// CMDMOD_REV must come before the jump
|
||||||
generate_undo_cmdmods(cctx);
|
generate_undo_cmdmods(cctx);
|
||||||
|
|
||||||
// "while_end" is set when ":endwhile" is found
|
// "while_end" is set when ":endwhile" is found
|
||||||
if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label,
|
if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label,
|
||||||
JUMP_IF_FALSE, cctx) == FAIL)
|
JUMP_IF_FALSE, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -8304,20 +8306,23 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cctx->ctx_scope = scope->se_outer;
|
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
|
#ifdef FEAT_PROFILE
|
||||||
// count the endwhile before jumping
|
// count the endwhile before jumping
|
||||||
may_generate_prof_end(cctx, cctx->ctx_lnum);
|
may_generate_prof_end(cctx, cctx->ctx_lnum);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// At end of ":for" scope jump back to the FOR instruction.
|
// At end of ":for" scope jump back to the FOR instruction.
|
||||||
generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label);
|
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.
|
// Fill in the "end" label in the WHILE statement so it can jump here.
|
||||||
// And in any jumps for ":break"
|
// And in any jumps for ":break"
|
||||||
compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label,
|
compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label,
|
||||||
instr->ga_len, cctx);
|
instr->ga_len, cctx);
|
||||||
|
}
|
||||||
|
|
||||||
vim_free(scope);
|
vim_free(scope);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user