To: vim_dev@googlegroups.com Subject: Patch 9.0.0742 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.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. Files: src/vim9compile.c, src/vim9cmds.c, src/testdir/test_vim9_func.vim, src/testdir/test_vim9_script.vim *** ../vim-9.0.0741/src/vim9compile.c 2022-10-11 20:04:05.880795466 +0100 --- src/vim9compile.c 2022-10-13 16:11:09.580587352 +0100 *************** *** 1284,1289 **** --- 1284,1302 ---- } /* + * 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,1375 **** } else if (*name == '@') { ! if (name[1] != '@' ! && (!valid_yank_reg(name[1], FALSE) || name[1] == '.')) ! { ! emsg_invreg(name[1]); return FAIL; - } *dest = dest_reg; *type = name[1] == '#' ? &t_number_or_string : &t_string; } --- 1377,1384 ---- } else if (*name == '@') { ! if (!valid_dest_reg(name[1])) return FAIL; *dest = dest_reg; *type = name[1] == '#' ? &t_number_or_string : &t_string; } *************** *** 1445,1451 **** --- 1454,1464 ---- // "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 "$" *** ../vim-9.0.0741/src/vim9cmds.c 2022-10-11 21:41:21.446173722 +0100 --- src/vim9cmds.c 2022-10-13 15:53:05.036099874 +0100 *************** *** 2412,2445 **** { if (STRNCMP(arg, "END", 3) == 0) { ! if (lhs->lhs_append) { ! // First load the current variable value. ! if (compile_load_lhs_with_index(lhs, lhs->lhs_whole, cctx) == FAIL) ! 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); ! ! 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, &t_string, cctx) == 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); return arg + 3; } emsg(_(e_cannot_nest_redir)); --- 2412,2448 ---- { if (STRNCMP(arg, "END", 3) == 0) { ! if (cctx->ctx_skip != SKIP_YES) { ! if (lhs->lhs_append) ! { ! // First load the current variable value. ! if (compile_load_lhs_with_index(lhs, lhs->lhs_whole, cctx) == FAIL) ! 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); ! ! 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, &t_string, cctx) == 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); ! } return arg + 3; } emsg(_(e_cannot_nest_redir)); *************** *** 2465,2477 **** 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) { ! lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total); ! if (lhs->lhs_whole == NULL) ! return NULL; } return arg + lhs->lhs_varlen_total; --- 2468,2487 ---- if (need_type(&t_string, lhs->lhs_member_type, -1, 0, cctx, FALSE, FALSE) == FAIL) return NULL; ! if (cctx->ctx_skip == SKIP_YES) ! { ! 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; *** ../vim-9.0.0741/src/testdir/test_vim9_func.vim 2022-09-30 19:19:00.769677730 +0100 --- src/testdir/test_vim9_func.vim 2022-10-13 15:39:22.488958480 +0100 *************** *** 4339,4344 **** --- 4339,4371 ---- assert_equal('', glob('XdeferFile')) enddef + def Test_invalid_redir() + var lines =<< trim END + def Tone() + if 1 + redi =>@0 + 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 =>@0 + 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() *** ../vim-9.0.0741/src/testdir/test_vim9_script.vim 2022-10-11 21:41:21.446173722 +0100 --- src/testdir/test_vim9_script.vim 2022-10-13 15:58:05.860942860 +0100 *************** *** 2136,2150 **** def Test_skipped_redir() var lines =<< trim END ! def T() if 0 ! redir =>l[0] redir END endif enddef defcompile END v9.CheckScriptSuccess(lines) enddef def Test_for_loop() --- 2136,2201 ---- def Test_skipped_redir() var lines =<< trim END ! def Tredir() if 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() *** ../vim-9.0.0741/src/version.c 2022-10-13 14:34:39.577698160 +0100 --- src/version.c 2022-10-13 15:58:45.408619517 +0100 *************** *** 701,702 **** --- 701,704 ---- { /* Add new patch number below this line */ + /**/ + 742, /**/ -- There can't be a crisis today, my schedule is already full. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///