Skip to content

Commit 3558afe

Browse files
committed
patch 9.0.0742: reading past end of the line when compiling a function
Problem: Reading past end of the line when compiling a function with errors. Solution: Do not return an invalid pointer. Fix skipping redirection.
1 parent d93009e commit 3558afe

File tree

5 files changed

+136
-33
lines changed

5 files changed

+136
-33
lines changed

Diff for: src/testdir/test_vim9_func.vim

+27
Original file line numberDiff line numberDiff line change
@@ -4339,6 +4339,33 @@ def Test_defer()
43394339
assert_equal('', glob('XdeferFile'))
43404340
enddef
43414341

4342+
def Test_invalid_redir()
4343+
var lines =<< trim END
4344+
def Tone()
4345+
if 1
4346+
redi =>@0
4347+
redi END
4348+
endif
4349+
enddef
4350+
defcompile
4351+
END
4352+
v9.CheckScriptFailure(lines, 'E354:')
4353+
delfunc g:Tone
4354+
4355+
# this was reading past the end of the line
4356+
lines =<< trim END
4357+
def Ttwo()
4358+
if 0
4359+
redi =>@0
4360+
redi END
4361+
endif
4362+
enddef
4363+
defcompile
4364+
END
4365+
v9.CheckScriptFailure(lines, 'E354:')
4366+
delfunc g:Ttwo
4367+
enddef
4368+
43424369
" The following messes up syntax highlight, keep near the end.
43434370
if has('python3')
43444371
def Test_python3_command()

Diff for: src/testdir/test_vim9_script.vim

+53-2
Original file line numberDiff line numberDiff line change
@@ -2136,15 +2136,66 @@ enddef
21362136

21372137
def Test_skipped_redir()
21382138
var lines =<< trim END
2139-
def T()
2139+
def Tredir()
21402140
if 0
2141-
redir =>l[0]
2141+
redir => l[0]
21422142
redir END
21432143
endif
21442144
enddef
21452145
defcompile
21462146
END
21472147
v9.CheckScriptSuccess(lines)
2148+
delfunc g:Tredir
2149+
2150+
lines =<< trim END
2151+
def Tredir()
2152+
if 0
2153+
redir => l[0]
2154+
endif
2155+
echo 'executed'
2156+
if 0
2157+
redir END
2158+
endif
2159+
enddef
2160+
defcompile
2161+
END
2162+
v9.CheckScriptSuccess(lines)
2163+
delfunc g:Tredir
2164+
2165+
lines =<< trim END
2166+
def Tredir()
2167+
var l = ['']
2168+
if 1
2169+
redir => l[0]
2170+
endif
2171+
echo 'executed'
2172+
if 0
2173+
redir END
2174+
else
2175+
redir END
2176+
endif
2177+
enddef
2178+
defcompile
2179+
END
2180+
v9.CheckScriptSuccess(lines)
2181+
delfunc g:Tredir
2182+
2183+
lines =<< trim END
2184+
let doit = 1
2185+
def Tredir()
2186+
var l = ['']
2187+
if g:doit
2188+
redir => l[0]
2189+
endif
2190+
echo 'executed'
2191+
if g:doit
2192+
redir END
2193+
endif
2194+
enddef
2195+
defcompile
2196+
END
2197+
v9.CheckScriptSuccess(lines)
2198+
delfunc g:Tredir
21482199
enddef
21492200

21502201
def Test_for_loop()

Diff for: src/version.c

+2
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ static char *(features[]) =
699699

700700
static int included_patches[] =
701701
{ /* Add new patch number below this line */
702+
/**/
703+
742,
702704
/**/
703705
741,
704706
/**/

Diff for: src/vim9cmds.c

+36-26
Original file line numberDiff line numberDiff line change
@@ -2412,34 +2412,37 @@ compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx)
24122412
{
24132413
if (STRNCMP(arg, "END", 3) == 0)
24142414
{
2415-
if (lhs->lhs_append)
2415+
if (cctx->ctx_skip != SKIP_YES)
24162416
{
2417-
// First load the current variable value.
2418-
if (compile_load_lhs_with_index(lhs, lhs->lhs_whole,
2417+
if (lhs->lhs_append)
2418+
{
2419+
// First load the current variable value.
2420+
if (compile_load_lhs_with_index(lhs, lhs->lhs_whole,
24192421
cctx) == FAIL)
2420-
return NULL;
2421-
}
2422+
return NULL;
2423+
}
24222424

2423-
// Gets the redirected text and put it on the stack, then store it
2424-
// in the variable.
2425-
generate_instr_type(cctx, ISN_REDIREND, &t_string);
2425+
// Gets the redirected text and put it on the stack, then store
2426+
// it in the variable.
2427+
generate_instr_type(cctx, ISN_REDIREND, &t_string);
24262428

2427-
if (lhs->lhs_append)
2428-
generate_CONCAT(cctx, 2);
2429+
if (lhs->lhs_append)
2430+
generate_CONCAT(cctx, 2);
24292431

2430-
if (lhs->lhs_has_index)
2431-
{
2432-
// Use the info in "lhs" to store the value at the index in the
2433-
// list or dict.
2434-
if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE,
2432+
if (lhs->lhs_has_index)
2433+
{
2434+
// Use the info in "lhs" to store the value at the index in
2435+
// the list or dict.
2436+
if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE,
24352437
&t_string, cctx) == FAIL)
2438+
return NULL;
2439+
}
2440+
else if (generate_store_lhs(cctx, lhs, -1, FALSE) == FAIL)
24362441
return NULL;
2437-
}
2438-
else if (generate_store_lhs(cctx, lhs, -1, FALSE) == FAIL)
2439-
return NULL;
24402442

2441-
VIM_CLEAR(lhs->lhs_name);
2442-
VIM_CLEAR(lhs->lhs_whole);
2443+
VIM_CLEAR(lhs->lhs_name);
2444+
VIM_CLEAR(lhs->lhs_whole);
2445+
}
24432446
return arg + 3;
24442447
}
24452448
emsg(_(e_cannot_nest_redir));
@@ -2465,13 +2468,20 @@ compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx)
24652468
if (need_type(&t_string, lhs->lhs_member_type,
24662469
-1, 0, cctx, FALSE, FALSE) == FAIL)
24672470
return NULL;
2468-
generate_instr(cctx, ISN_REDIRSTART);
2469-
lhs->lhs_append = append;
2470-
if (lhs->lhs_has_index)
2471+
if (cctx->ctx_skip == SKIP_YES)
24712472
{
2472-
lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total);
2473-
if (lhs->lhs_whole == NULL)
2474-
return NULL;
2473+
VIM_CLEAR(lhs->lhs_name);
2474+
}
2475+
else
2476+
{
2477+
generate_instr(cctx, ISN_REDIRSTART);
2478+
lhs->lhs_append = append;
2479+
if (lhs->lhs_has_index)
2480+
{
2481+
lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total);
2482+
if (lhs->lhs_whole == NULL)
2483+
return NULL;
2484+
}
24752485
}
24762486

24772487
return arg + lhs->lhs_varlen_total;

Diff for: src/vim9compile.c

+18-5
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,19 @@ vim9_declare_error(char_u *name)
12831283
semsg(_(e_cannot_declare_a_scope_variable), scope, name);
12841284
}
12851285

1286+
/*
1287+
* Return TRUE if "name" is a valid register to use.
1288+
* Return FALSE and give an error message if not.
1289+
*/
1290+
static int
1291+
valid_dest_reg(int name)
1292+
{
1293+
if ((name == '@' || valid_yank_reg(name, FALSE)) && name != '.')
1294+
return TRUE;
1295+
emsg_invreg(name);
1296+
return FAIL;
1297+
}
1298+
12861299
/*
12871300
* For one assignment figure out the type of destination. Return it in "dest".
12881301
* When not recognized "dest" is not set.
@@ -1364,12 +1377,8 @@ get_var_dest(
13641377
}
13651378
else if (*name == '@')
13661379
{
1367-
if (name[1] != '@'
1368-
&& (!valid_yank_reg(name[1], FALSE) || name[1] == '.'))
1369-
{
1370-
emsg_invreg(name[1]);
1380+
if (!valid_dest_reg(name[1]))
13711381
return FAIL;
1372-
}
13731382
*dest = dest_reg;
13741383
*type = name[1] == '#' ? &t_number_or_string : &t_string;
13751384
}
@@ -1445,7 +1454,11 @@ compile_lhs(
14451454
// "var_end" is the end of the variable/option/etc. name.
14461455
lhs->lhs_dest_end = skip_var_one(var_start, FALSE);
14471456
if (*var_start == '@')
1457+
{
1458+
if (!valid_dest_reg(var_start[1]))
1459+
return FAIL;
14481460
var_end = var_start + 2;
1461+
}
14491462
else
14501463
{
14511464
// skip over the leading "&", "&l:", "&g:" and "$"

0 commit comments

Comments
 (0)