Skip to content

Commit d895b1d

Browse files
rbtnnbrammool
authored andcommitted
patch 8.2.3361: Vim9: crash with nested :while
Problem: Vim9: crash with nested :while. Solution: Handle skipping better. (Naruhiko Nishino, closes #8778)
1 parent 5aec755 commit d895b1d

File tree

3 files changed

+107
-17
lines changed

3 files changed

+107
-17
lines changed

src/testdir/test_vim9_script.vim

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2856,6 +2856,89 @@ def Test_for_loop_with_try_continue()
28562856
CheckDefAndScriptSuccess(lines)
28572857
enddef
28582858

2859+
def Test_while_skipped_block()
2860+
# test skipped blocks at outside of function
2861+
var lines =<< trim END
2862+
var result = []
2863+
var n = 0
2864+
if true
2865+
n = 1
2866+
while n < 3
2867+
result += [n]
2868+
n += 1
2869+
endwhile
2870+
else
2871+
n = 3
2872+
while n < 5
2873+
result += [n]
2874+
n += 1
2875+
endwhile
2876+
endif
2877+
assert_equal([1, 2], result)
2878+
2879+
result = []
2880+
if false
2881+
n = 1
2882+
while n < 3
2883+
result += [n]
2884+
n += 1
2885+
endwhile
2886+
else
2887+
n = 3
2888+
while n < 5
2889+
result += [n]
2890+
n += 1
2891+
endwhile
2892+
endif
2893+
assert_equal([3, 4], result)
2894+
END
2895+
CheckDefAndScriptSuccess(lines)
2896+
2897+
# test skipped blocks at inside of function
2898+
lines =<< trim END
2899+
def DefTrue()
2900+
var result = []
2901+
var n = 0
2902+
if true
2903+
n = 1
2904+
while n < 3
2905+
result += [n]
2906+
n += 1
2907+
endwhile
2908+
else
2909+
n = 3
2910+
while n < 5
2911+
result += [n]
2912+
n += 1
2913+
endwhile
2914+
endif
2915+
assert_equal([1, 2], result)
2916+
enddef
2917+
DefTrue()
2918+
2919+
def DefFalse()
2920+
var result = []
2921+
var n = 0
2922+
if false
2923+
n = 1
2924+
while n < 3
2925+
result += [n]
2926+
n += 1
2927+
endwhile
2928+
else
2929+
n = 3
2930+
while n < 5
2931+
result += [n]
2932+
n += 1
2933+
endwhile
2934+
endif
2935+
assert_equal([3, 4], result)
2936+
enddef
2937+
DefFalse()
2938+
END
2939+
CheckDefAndScriptSuccess(lines)
2940+
enddef
2941+
28592942
def Test_while_loop()
28602943
var result = ''
28612944
var cnt = 0

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,8 @@ static char *(features[]) =
755755

756756
static int included_patches[] =
757757
{ /* Add new patch number below this line */
758+
/**/
759+
3361,
758760
/**/
759761
3360,
760762
/**/

src/vim9compile.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4469,8 +4469,6 @@ compile_subscript(
44694469
// dict member: dict[key]
44704470
// string index: text[123]
44714471
// blob index: blob[123]
4472-
// TODO: more arguments
4473-
// TODO: recognize list or dict at runtime
44744472
if (generate_ppconst(cctx, ppconst) == FAIL)
44754473
return FAIL;
44764474
ppconst->pp_is_const = FALSE;
@@ -8267,22 +8265,26 @@ compile_while(char_u *arg, cctx_T *cctx)
82678265
// compile "expr"
82688266
if (compile_expr0(&p, cctx) == FAIL)
82698267
return NULL;
8268+
82708269
if (!ends_excmd2(arg, skipwhite(p)))
82718270
{
82728271
semsg(_(e_trailing_arg), p);
82738272
return NULL;
82748273
}
82758274

8276-
if (bool_on_stack(cctx) == FAIL)
8277-
return FAIL;
8275+
if (cctx->ctx_skip != SKIP_YES)
8276+
{
8277+
if (bool_on_stack(cctx) == FAIL)
8278+
return FAIL;
82788279

8279-
// CMDMOD_REV must come before the jump
8280-
generate_undo_cmdmods(cctx);
8280+
// CMDMOD_REV must come before the jump
8281+
generate_undo_cmdmods(cctx);
82818282

8282-
// "while_end" is set when ":endwhile" is found
8283-
if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label,
8283+
// "while_end" is set when ":endwhile" is found
8284+
if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label,
82848285
JUMP_IF_FALSE, cctx) == FAIL)
8285-
return FAIL;
8286+
return FAIL;
8287+
}
82868288

82878289
return p;
82888290
}
@@ -8304,20 +8306,23 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
83048306
return NULL;
83058307
}
83068308
cctx->ctx_scope = scope->se_outer;
8307-
unwind_locals(cctx, scope->se_local_count);
8309+
if (cctx->ctx_skip != SKIP_YES)
8310+
{
8311+
unwind_locals(cctx, scope->se_local_count);
83088312

83098313
#ifdef FEAT_PROFILE
8310-
// count the endwhile before jumping
8311-
may_generate_prof_end(cctx, cctx->ctx_lnum);
8314+
// count the endwhile before jumping
8315+
may_generate_prof_end(cctx, cctx->ctx_lnum);
83128316
#endif
83138317

8314-
// At end of ":for" scope jump back to the FOR instruction.
8315-
generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label);
8318+
// At end of ":for" scope jump back to the FOR instruction.
8319+
generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label);
83168320

8317-
// Fill in the "end" label in the WHILE statement so it can jump here.
8318-
// And in any jumps for ":break"
8319-
compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label,
8321+
// Fill in the "end" label in the WHILE statement so it can jump here.
8322+
// And in any jumps for ":break"
8323+
compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label,
83208324
instr->ga_len, cctx);
8325+
}
83218326

83228327
vim_free(scope);
83238328

0 commit comments

Comments
 (0)