]> granicus.if.org Git - vim/commitdiff
patch 9.0.0742: reading past end of the line when compiling a function v9.0.0742
authorBram Moolenaar <Bram@vim.org>
Thu, 13 Oct 2022 15:12:57 +0000 (16:12 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 13 Oct 2022 15:12:57 +0000 (16:12 +0100)
Problem:    Reading past end of the line when compiling a function with
            errors.
Solution:   Do not return an invalid pointer.  Fix skipping redirection.

src/testdir/test_vim9_func.vim
src/testdir/test_vim9_script.vim
src/version.c
src/vim9cmds.c
src/vim9compile.c

index 38766e3301568cc42a62de65fa6676e18e3d25b5..bb5635626484e3f2d732718f0c9fa0d704a9daf2 100644 (file)
@@ -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 =>@\00
+          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 =>@\00
+          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()
index a0b8352f3f727311a7a24bdf89c06f4e3cbc557a..6c8f1f0ce0b0de46f4f9dbb2f72a064a3794d700 100644 (file)
@@ -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()
index 6570ac52a8a983621204b7ede087e4fffe330912..467f8e083690bff984cb60eb589c11ec9dd27b4f 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    742,
 /**/
     741,
 /**/
index 73f95b26dfe52bb76c9e3f2df7f1149b681f02ac..e5abf895e6a73cd3bcd680d386bcf7bbd17a76bd 100644 (file)
@@ -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;
index b3e1b83ea4ef60d709a35244e5ff881e815ef7eb..73bfa6c6af1e20655175f4a6ae76bd0be022ee2f 100644 (file)
@@ -1283,6 +1283,19 @@ vim9_declare_error(char_u *name)
     semsg(_(e_cannot_declare_a_scope_variable), scope, 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.
@@ -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 "$"