diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-10-13 16:12:57 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-10-13 16:12:57 +0100 |
commit | 3558afe9e9e904cabb8475392d859f2d2fc21041 (patch) | |
tree | 3ec453686754ece5109f487f5cd9843a4632bf5b /src | |
parent | d93009eb35c88bfc38781fefdf42ebdb02c61474 (diff) | |
download | vim-git-3558afe9e9e904cabb8475392d859f2d2fc21041.tar.gz |
patch 9.0.0742: reading past end of the line when compiling a functionv9.0.0742
Problem: Reading past end of the line when compiling a function with
errors.
Solution: Do not return an invalid pointer. Fix skipping redirection.
Diffstat (limited to 'src')
-rw-r--r-- | src/testdir/test_vim9_func.vim | 27 | ||||
-rw-r--r-- | src/testdir/test_vim9_script.vim | 55 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9cmds.c | 62 | ||||
-rw-r--r-- | src/vim9compile.c | 23 |
5 files changed, 136 insertions, 33 deletions
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 38766e330..bb5635626 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -4339,6 +4339,33 @@ def Test_defer() assert_equal('', glob('XdeferFile')) enddef +def Test_invalid_redir() + var lines =<< trim END + def Tone() + if 1 + redi =>@ + redi END + endif + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E354:') + delfunc g:Tone + + # this was reading past the end of the line + lines =<< trim END + def Ttwo() + if 0 + redi =>@ + redi END + endif + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E354:') + delfunc g:Ttwo +enddef + " The following messes up syntax highlight, keep near the end. if has('python3') def Test_python3_command() diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index a0b8352f3..6c8f1f0ce 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -2136,15 +2136,66 @@ enddef def Test_skipped_redir() var lines =<< trim END - def T() + def Tredir() if 0 - redir =>l[0] + redir => l[0] redir END endif enddef defcompile END v9.CheckScriptSuccess(lines) + delfunc g:Tredir + + lines =<< trim END + def Tredir() + if 0 + redir => l[0] + endif + echo 'executed' + if 0 + redir END + endif + enddef + defcompile + END + v9.CheckScriptSuccess(lines) + delfunc g:Tredir + + lines =<< trim END + def Tredir() + var l = [''] + if 1 + redir => l[0] + endif + echo 'executed' + if 0 + redir END + else + redir END + endif + enddef + defcompile + END + v9.CheckScriptSuccess(lines) + delfunc g:Tredir + + lines =<< trim END + let doit = 1 + def Tredir() + var l = [''] + if g:doit + redir => l[0] + endif + echo 'executed' + if g:doit + redir END + endif + enddef + defcompile + END + v9.CheckScriptSuccess(lines) + delfunc g:Tredir enddef def Test_for_loop() diff --git a/src/version.c b/src/version.c index 6570ac52a..467f8e083 100644 --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 742, +/**/ 741, /**/ 740, diff --git a/src/vim9cmds.c b/src/vim9cmds.c index 73f95b26d..e5abf895e 100644 --- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -2412,34 +2412,37 @@ compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx) { if (STRNCMP(arg, "END", 3) == 0) { - if (lhs->lhs_append) + if (cctx->ctx_skip != SKIP_YES) { - // First load the current variable value. - if (compile_load_lhs_with_index(lhs, lhs->lhs_whole, + if (lhs->lhs_append) + { + // First load the current variable value. + if (compile_load_lhs_with_index(lhs, lhs->lhs_whole, cctx) == FAIL) - return NULL; - } + return NULL; + } - // Gets the redirected text and put it on the stack, then store it - // in the variable. - generate_instr_type(cctx, ISN_REDIREND, &t_string); + // Gets the redirected text and put it on the stack, then store + // it in the variable. + generate_instr_type(cctx, ISN_REDIREND, &t_string); - if (lhs->lhs_append) - generate_CONCAT(cctx, 2); + if (lhs->lhs_append) + generate_CONCAT(cctx, 2); - if (lhs->lhs_has_index) - { - // Use the info in "lhs" to store the value at the index in the - // list or dict. - if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE, + if (lhs->lhs_has_index) + { + // Use the info in "lhs" to store the value at the index in + // the list or dict. + if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE, &t_string, cctx) == FAIL) + return NULL; + } + else if (generate_store_lhs(cctx, lhs, -1, FALSE) == FAIL) return NULL; - } - else if (generate_store_lhs(cctx, lhs, -1, FALSE) == FAIL) - return NULL; - VIM_CLEAR(lhs->lhs_name); - VIM_CLEAR(lhs->lhs_whole); + VIM_CLEAR(lhs->lhs_name); + VIM_CLEAR(lhs->lhs_whole); + } return arg + 3; } emsg(_(e_cannot_nest_redir)); @@ -2465,13 +2468,20 @@ compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx) if (need_type(&t_string, lhs->lhs_member_type, -1, 0, cctx, FALSE, FALSE) == FAIL) return NULL; - generate_instr(cctx, ISN_REDIRSTART); - lhs->lhs_append = append; - if (lhs->lhs_has_index) + if (cctx->ctx_skip == SKIP_YES) { - lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total); - if (lhs->lhs_whole == NULL) - return NULL; + VIM_CLEAR(lhs->lhs_name); + } + else + { + generate_instr(cctx, ISN_REDIRSTART); + lhs->lhs_append = append; + if (lhs->lhs_has_index) + { + lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total); + if (lhs->lhs_whole == NULL) + return NULL; + } } return arg + lhs->lhs_varlen_total; diff --git a/src/vim9compile.c b/src/vim9compile.c index b3e1b83ea..73bfa6c6a 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1284,6 +1284,19 @@ vim9_declare_error(char_u *name) } /* + * Return TRUE if "name" is a valid register to use. + * Return FALSE and give an error message if not. + */ + static int +valid_dest_reg(int name) +{ + if ((name == '@' || valid_yank_reg(name, FALSE)) && name != '.') + return TRUE; + emsg_invreg(name); + return FAIL; +} + +/* * For one assignment figure out the type of destination. Return it in "dest". * When not recognized "dest" is not set. * For an option "option_scope" is set. @@ -1364,12 +1377,8 @@ get_var_dest( } else if (*name == '@') { - if (name[1] != '@' - && (!valid_yank_reg(name[1], FALSE) || name[1] == '.')) - { - emsg_invreg(name[1]); + if (!valid_dest_reg(name[1])) return FAIL; - } *dest = dest_reg; *type = name[1] == '#' ? &t_number_or_string : &t_string; } @@ -1445,7 +1454,11 @@ compile_lhs( // "var_end" is the end of the variable/option/etc. name. lhs->lhs_dest_end = skip_var_one(var_start, FALSE); if (*var_start == '@') + { + if (!valid_dest_reg(var_start[1])) + return FAIL; var_end = var_start + 2; + } else { // skip over the leading "&", "&l:", "&g:" and "$" |