Skip to content

Commit bebf069

Browse files
rbtnnbrammool
authored andcommitted
patch 8.2.3364: Vim9: crash when :for is skipped
Problem: Vim9: crash when :for is skipped. Solution: Skip more code generation. (Naruhiko Nishino, closes #8777)
1 parent b8bd2e6 commit bebf069

File tree

3 files changed

+202
-130
lines changed

3 files changed

+202
-130
lines changed

src/testdir/test_vim9_script.vim

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,6 +2552,70 @@ def Test_for_outside_of_function()
25522552
delete('Xvim9for.vim')
25532553
enddef
25542554

2555+
def Test_for_skipped_block()
2556+
# test skipped blocks at outside of function
2557+
var lines =<< trim END
2558+
var result = []
2559+
if true
2560+
for n in [1, 2]
2561+
result += [n]
2562+
endfor
2563+
else
2564+
for n in [3, 4]
2565+
result += [n]
2566+
endfor
2567+
endif
2568+
assert_equal([1, 2], result)
2569+
2570+
result = []
2571+
if false
2572+
for n in [1, 2]
2573+
result += [n]
2574+
endfor
2575+
else
2576+
for n in [3, 4]
2577+
result += [n]
2578+
endfor
2579+
endif
2580+
assert_equal([3, 4], result)
2581+
END
2582+
CheckDefAndScriptSuccess(lines)
2583+
2584+
# test skipped blocks at inside of function
2585+
lines =<< trim END
2586+
def DefTrue()
2587+
var result = []
2588+
if true
2589+
for n in [1, 2]
2590+
result += [n]
2591+
endfor
2592+
else
2593+
for n in [3, 4]
2594+
result += [n]
2595+
endfor
2596+
endif
2597+
assert_equal([1, 2], result)
2598+
enddef
2599+
DefTrue()
2600+
2601+
def DefFalse()
2602+
var result = []
2603+
if false
2604+
for n in [1, 2]
2605+
result += [n]
2606+
endfor
2607+
else
2608+
for n in [3, 4]
2609+
result += [n]
2610+
endfor
2611+
endif
2612+
assert_equal([3, 4], result)
2613+
enddef
2614+
DefFalse()
2615+
END
2616+
CheckDefAndScriptSuccess(lines)
2617+
enddef
2618+
25552619
def Test_for_loop()
25562620
var lines =<< trim END
25572621
var result = ''

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+
3364,
758760
/**/
759761
3363,
760762
/**/

src/vim9compile.c

Lines changed: 136 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -8041,151 +8041,154 @@ compile_for(char_u *arg_start, cctx_T *cctx)
80418041
}
80428042
arg_end = arg;
80438043

8044-
// If we know the type of "var" and it is a not a supported type we can
8045-
// give an error now.
8046-
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
8047-
if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING
8048-
&& vartype->tt_type != VAR_BLOB && vartype->tt_type != VAR_ANY)
8044+
if (cctx->ctx_skip != SKIP_YES)
80498045
{
8050-
semsg(_(e_for_loop_on_str_not_supported),
8046+
// If we know the type of "var" and it is a not a supported type we can
8047+
// give an error now.
8048+
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
8049+
if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING
8050+
&& vartype->tt_type != VAR_BLOB && vartype->tt_type != VAR_ANY)
8051+
{
8052+
semsg(_(e_for_loop_on_str_not_supported),
80518053
vartype_name(vartype->tt_type));
8052-
drop_scope(cctx);
8053-
return NULL;
8054-
}
8054+
drop_scope(cctx);
8055+
return NULL;
8056+
}
80558057

8056-
if (vartype->tt_type == VAR_STRING)
8057-
item_type = &t_string;
8058-
else if (vartype->tt_type == VAR_BLOB)
8059-
item_type = &t_number;
8060-
else if (vartype->tt_type == VAR_LIST
8058+
if (vartype->tt_type == VAR_STRING)
8059+
item_type = &t_string;
8060+
else if (vartype->tt_type == VAR_BLOB)
8061+
item_type = &t_number;
8062+
else if (vartype->tt_type == VAR_LIST
80618063
&& vartype->tt_member->tt_type != VAR_ANY)
8062-
{
8063-
if (!var_list)
8064-
item_type = vartype->tt_member;
8065-
else if (vartype->tt_member->tt_type == VAR_LIST
8066-
&& vartype->tt_member->tt_member->tt_type != VAR_ANY)
8067-
// TODO: should get the type for each lhs
8068-
item_type = vartype->tt_member->tt_member;
8069-
}
8064+
{
8065+
if (!var_list)
8066+
item_type = vartype->tt_member;
8067+
else if (vartype->tt_member->tt_type == VAR_LIST
8068+
&& vartype->tt_member->tt_member->tt_type != VAR_ANY)
8069+
// TODO: should get the type for each lhs
8070+
item_type = vartype->tt_member->tt_member;
8071+
}
80708072

8071-
// CMDMOD_REV must come before the FOR instruction.
8072-
generate_undo_cmdmods(cctx);
8073+
// CMDMOD_REV must come before the FOR instruction.
8074+
generate_undo_cmdmods(cctx);
80738075

8074-
// "for_end" is set when ":endfor" is found
8075-
scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
8076+
// "for_end" is set when ":endfor" is found
8077+
scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
80768078

8077-
generate_FOR(cctx, loop_lvar->lv_idx);
8079+
generate_FOR(cctx, loop_lvar->lv_idx);
80788080

8079-
arg = arg_start;
8080-
if (var_list)
8081-
{
8082-
generate_UNPACK(cctx, var_count, semicolon);
8083-
arg = skipwhite(arg + 1); // skip white after '['
8084-
8085-
// the list item is replaced by a number of items
8086-
if (GA_GROW_FAILS(stack, var_count - 1))
8081+
arg = arg_start;
8082+
if (var_list)
80878083
{
8088-
drop_scope(cctx);
8089-
return NULL;
8084+
generate_UNPACK(cctx, var_count, semicolon);
8085+
arg = skipwhite(arg + 1); // skip white after '['
8086+
8087+
// the list item is replaced by a number of items
8088+
if (GA_GROW_FAILS(stack, var_count - 1))
8089+
{
8090+
drop_scope(cctx);
8091+
return NULL;
8092+
}
8093+
--stack->ga_len;
8094+
for (idx = 0; idx < var_count; ++idx)
8095+
{
8096+
((type_T **)stack->ga_data)[stack->ga_len] =
8097+
(semicolon && idx == 0) ? vartype : item_type;
8098+
++stack->ga_len;
8099+
}
80908100
}
8091-
--stack->ga_len;
8101+
80928102
for (idx = 0; idx < var_count; ++idx)
80938103
{
8094-
((type_T **)stack->ga_data)[stack->ga_len] =
8095-
(semicolon && idx == 0) ? vartype : item_type;
8096-
++stack->ga_len;
8097-
}
8098-
}
8104+
assign_dest_T dest = dest_local;
8105+
int opt_flags = 0;
8106+
int vimvaridx = -1;
8107+
type_T *type = &t_any;
8108+
type_T *lhs_type = &t_any;
8109+
where_T where = WHERE_INIT;
80998110

8100-
for (idx = 0; idx < var_count; ++idx)
8101-
{
8102-
assign_dest_T dest = dest_local;
8103-
int opt_flags = 0;
8104-
int vimvaridx = -1;
8105-
type_T *type = &t_any;
8106-
type_T *lhs_type = &t_any;
8107-
where_T where = WHERE_INIT;
8108-
8109-
p = skip_var_one(arg, FALSE);
8110-
varlen = p - arg;
8111-
name = vim_strnsave(arg, varlen);
8112-
if (name == NULL)
8113-
goto failed;
8114-
if (*p == ':')
8115-
{
8116-
p = skipwhite(p + 1);
8117-
lhs_type = parse_type(&p, cctx->ctx_type_list, TRUE);
8118-
}
8111+
p = skip_var_one(arg, FALSE);
8112+
varlen = p - arg;
8113+
name = vim_strnsave(arg, varlen);
8114+
if (name == NULL)
8115+
goto failed;
8116+
if (*p == ':')
8117+
{
8118+
p = skipwhite(p + 1);
8119+
lhs_type = parse_type(&p, cctx->ctx_type_list, TRUE);
8120+
}
81198121

8120-
// TODO: script var not supported?
8121-
if (get_var_dest(name, &dest, CMD_for, &opt_flags,
8122+
// TODO: script var not supported?
8123+
if (get_var_dest(name, &dest, CMD_for, &opt_flags,
81228124
&vimvaridx, &type, cctx) == FAIL)
8123-
goto failed;
8124-
if (dest != dest_local)
8125-
{
8126-
if (generate_store_var(cctx, dest, opt_flags, vimvaridx,
8127-
0, 0, type, name) == FAIL)
8128-
goto failed;
8129-
}
8130-
else if (varlen == 1 && *arg == '_')
8131-
{
8132-
// Assigning to "_": drop the value.
8133-
if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
81348125
goto failed;
8135-
}
8136-
else
8137-
{
8138-
if (lookup_local(arg, varlen, NULL, cctx) == OK)
8126+
if (dest != dest_local)
81398127
{
8140-
semsg(_(e_variable_already_declared), arg);
8141-
goto failed;
8128+
if (generate_store_var(cctx, dest, opt_flags, vimvaridx,
8129+
0, 0, type, name) == FAIL)
8130+
goto failed;
81428131
}
8143-
8144-
if (STRNCMP(name, "s:", 2) == 0)
8132+
else if (varlen == 1 && *arg == '_')
81458133
{
8146-
semsg(_(e_cannot_declare_script_variable_in_function), name);
8147-
goto failed;
8134+
// Assigning to "_": drop the value.
8135+
if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
8136+
goto failed;
81488137
}
8138+
else
8139+
{
8140+
if (lookup_local(arg, varlen, NULL, cctx) == OK)
8141+
{
8142+
semsg(_(e_variable_already_declared), arg);
8143+
goto failed;
8144+
}
81498145

8150-
// Reserve a variable to store "var".
8151-
where.wt_index = var_list ? idx + 1 : 0;
8152-
where.wt_variable = TRUE;
8153-
if (lhs_type == &t_any)
8154-
lhs_type = item_type;
8155-
else if (item_type != &t_unknown
8156-
&& (item_type == &t_any
8157-
? need_type(item_type, lhs_type,
8146+
if (STRNCMP(name, "s:", 2) == 0)
8147+
{
8148+
semsg(_(e_cannot_declare_script_variable_in_function), name);
8149+
goto failed;
8150+
}
8151+
8152+
// Reserve a variable to store "var".
8153+
where.wt_index = var_list ? idx + 1 : 0;
8154+
where.wt_variable = TRUE;
8155+
if (lhs_type == &t_any)
8156+
lhs_type = item_type;
8157+
else if (item_type != &t_unknown
8158+
&& (item_type == &t_any
8159+
? need_type(item_type, lhs_type,
81588160
-1, 0, cctx, FALSE, FALSE)
8159-
: check_type(lhs_type, item_type, TRUE, where))
8160-
== FAIL)
8161-
goto failed;
8162-
var_lvar = reserve_local(cctx, arg, varlen, TRUE, lhs_type);
8163-
if (var_lvar == NULL)
8164-
// out of memory or used as an argument
8165-
goto failed;
8161+
: check_type(lhs_type, item_type, TRUE, where))
8162+
== FAIL)
8163+
goto failed;
8164+
var_lvar = reserve_local(cctx, arg, varlen, TRUE, lhs_type);
8165+
if (var_lvar == NULL)
8166+
// out of memory or used as an argument
8167+
goto failed;
8168+
8169+
if (semicolon && idx == var_count - 1)
8170+
var_lvar->lv_type = vartype;
8171+
else
8172+
var_lvar->lv_type = item_type;
8173+
generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
8174+
}
81668175

8167-
if (semicolon && idx == var_count - 1)
8168-
var_lvar->lv_type = vartype;
8169-
else
8170-
var_lvar->lv_type = item_type;
8171-
generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
8176+
if (*p == ',' || *p == ';')
8177+
++p;
8178+
arg = skipwhite(p);
8179+
vim_free(name);
81728180
}
81738181

8174-
if (*p == ',' || *p == ';')
8175-
++p;
8176-
arg = skipwhite(p);
8177-
vim_free(name);
8178-
}
8179-
8180-
if (cctx->ctx_compile_type == CT_DEBUG)
8181-
{
8182-
int save_prev_lnum = cctx->ctx_prev_lnum;
8182+
if (cctx->ctx_compile_type == CT_DEBUG)
8183+
{
8184+
int save_prev_lnum = cctx->ctx_prev_lnum;
81838185

8184-
// Add ISN_DEBUG here, so that the loop variables can be inspected.
8185-
// Use the prev_lnum from the ISN_DEBUG instruction removed above.
8186-
cctx->ctx_prev_lnum = prev_lnum;
8187-
generate_instr_debug(cctx);
8188-
cctx->ctx_prev_lnum = save_prev_lnum;
8186+
// Add ISN_DEBUG here, so that the loop variables can be inspected.
8187+
// Use the prev_lnum from the ISN_DEBUG instruction removed above.
8188+
cctx->ctx_prev_lnum = prev_lnum;
8189+
generate_instr_debug(cctx);
8190+
cctx->ctx_prev_lnum = save_prev_lnum;
8191+
}
81898192
}
81908193

81918194
return arg_end;
@@ -8217,21 +8220,24 @@ compile_endfor(char_u *arg, cctx_T *cctx)
82178220
}
82188221
forscope = &scope->se_u.se_for;
82198222
cctx->ctx_scope = scope->se_outer;
8220-
unwind_locals(cctx, scope->se_local_count);
8223+
if (cctx->ctx_skip != SKIP_YES)
8224+
{
8225+
unwind_locals(cctx, scope->se_local_count);
82218226

8222-
// At end of ":for" scope jump back to the FOR instruction.
8223-
generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
8227+
// At end of ":for" scope jump back to the FOR instruction.
8228+
generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
82248229

8225-
// Fill in the "end" label in the FOR statement so it can jump here.
8226-
isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label;
8227-
isn->isn_arg.forloop.for_end = instr->ga_len;
8230+
// Fill in the "end" label in the FOR statement so it can jump here.
8231+
isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label;
8232+
isn->isn_arg.forloop.for_end = instr->ga_len;
82288233

8229-
// Fill in the "end" label any BREAK statements
8230-
compile_fill_jump_to_end(&forscope->fs_end_label, instr->ga_len, cctx);
8234+
// Fill in the "end" label any BREAK statements
8235+
compile_fill_jump_to_end(&forscope->fs_end_label, instr->ga_len, cctx);
82318236

8232-
// Below the ":for" scope drop the "expr" list from the stack.
8233-
if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
8234-
return NULL;
8237+
// Below the ":for" scope drop the "expr" list from the stack.
8238+
if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
8239+
return NULL;
8240+
}
82358241

82368242
vim_free(scope);
82378243

0 commit comments

Comments
 (0)