]> granicus.if.org Git - vim/commitdiff
patch 8.2.1001: Vim9: crash with nested "if" and assignment v8.2.1001
authorBram Moolenaar <Bram@vim.org>
Thu, 18 Jun 2020 16:26:24 +0000 (18:26 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 18 Jun 2020 16:26:24 +0000 (18:26 +0200)
Problem:    Vim9: crash with nested "if" and assignment.
Solution:   Skip more of the assignment.  Do not set ctx_skip when code is
            reachable.

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

index 2fa88e8365d9577f6e0f56b5d8ccab87bd9db148..d4cd60222327877d31c87dfff842bf876f35fbd9 100644 (file)
@@ -1162,6 +1162,26 @@ def Test_if_const_expr_fails()
   call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
 enddef
 
+def RunNested(i: number): number
+  let x: number = 0
+  if i % 2
+    if 1
+      " comment
+    else
+      " comment
+    endif
+    x += 1
+  else
+    x += 1000
+  endif
+  return x
+enddef
+
+def Test_nested_if()
+  assert_equal(1, RunNested(1))
+  assert_equal(1000, RunNested(2))
+enddef
+
 def Test_execute_cmd()
   new
   setline(1, 'default')
index 5f4ff7172ac8c58058eac833ba5495805e89ef68..5d69674a8417a8a79c375399cb338059a033b624 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1001,
 /**/
     1000,
 /**/
index 7beecd9a308d1ab31d347744443a255618b875d7..2bfc4d0fe68f81009c334778ada9dfa4cefac7e2 100644 (file)
@@ -5067,8 +5067,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
 
        if (!heredoc)
        {
-           if (oplen > 0)
+           if (cctx->ctx_skip == TRUE)
            {
+               if (oplen > 0 && var_count == 0)
+               {
+                   // skip over the "=" and the expression
+                   p = skipwhite(op + oplen);
+                   compile_expr0(&p, cctx);
+               }
+           }
+           else if (oplen > 0)
+           {
+               type_T  *stacktype;
+
                // For "var = expr" evaluate the expression.
                if (var_count == 0)
                {
@@ -5113,52 +5124,47 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                        return FAIL;
                }
 
-               if (cctx->ctx_skip != TRUE)
+               stacktype = stack->ga_len == 0 ? &t_void
+                         : ((type_T **)stack->ga_data)[stack->ga_len - 1];
+               if (lvar != NULL && (is_decl || !has_type))
                {
-                   type_T      *stacktype;
-
-                   stacktype = stack->ga_len == 0 ? &t_void
-                             : ((type_T **)stack->ga_data)[stack->ga_len - 1];
-                   if (lvar != NULL && (is_decl || !has_type))
+                   if (new_local && !has_type)
                    {
-                       if (new_local && !has_type)
+                       if (stacktype->tt_type == VAR_VOID)
                        {
-                           if (stacktype->tt_type == VAR_VOID)
-                           {
-                               emsg(_(e_cannot_use_void));
-                               goto theend;
-                           }
-                           else
-                           {
-                               // An empty list or dict has a &t_void member,
-                               // for a variable that implies &t_any.
-                               if (stacktype == &t_list_empty)
-                                   lvar->lv_type = &t_list_any;
-                               else if (stacktype == &t_dict_empty)
-                                   lvar->lv_type = &t_dict_any;
-                               else
-                                   lvar->lv_type = stacktype;
-                           }
+                           emsg(_(e_cannot_use_void));
+                           goto theend;
                        }
                        else
                        {
-                           type_T *use_type = lvar->lv_type;
+                           // An empty list or dict has a &t_void member,
+                           // for a variable that implies &t_any.
+                           if (stacktype == &t_list_empty)
+                               lvar->lv_type = &t_list_any;
+                           else if (stacktype == &t_dict_empty)
+                               lvar->lv_type = &t_dict_any;
+                           else
+                               lvar->lv_type = stacktype;
+                       }
+                   }
+                   else
+                   {
+                       type_T *use_type = lvar->lv_type;
 
-                           if (has_index)
-                           {
-                               use_type = use_type->tt_member;
-                               if (use_type == NULL)
-                                   use_type = &t_void;
-                           }
-                           if (need_type(stacktype, use_type, -1, cctx)
-                                                                      == FAIL)
-                               goto theend;
+                       if (has_index)
+                       {
+                           use_type = use_type->tt_member;
+                           if (use_type == NULL)
+                               use_type = &t_void;
                        }
+                       if (need_type(stacktype, use_type, -1, cctx)
+                                                                  == FAIL)
+                           goto theend;
                    }
-                   else if (*p != '=' && need_type(stacktype, member_type, -1,
-                                                                cctx) == FAIL)
-                       goto theend;
                }
+               else if (*p != '=' && need_type(stacktype, member_type, -1,
+                                                            cctx) == FAIL)
+                   goto theend;
            }
            else if (cmdidx == CMD_const)
            {
@@ -5220,6 +5226,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                end = p;
        }
 
+       // no need to parse more when skipping
+       if (cctx->ctx_skip == TRUE)
+           break;
+
        if (oplen > 0 && *op != '=')
        {
            type_T          *expected = &t_number;
@@ -5806,7 +5816,8 @@ compile_endif(char_u *arg, cctx_T *cctx)
     }
     // Fill in the "end" label in jumps at the end of the blocks.
     compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
-    cctx->ctx_skip = FALSE;
+    // TODO: this should restore the value from before the :if
+    cctx->ctx_skip = MAYBE;
 
     drop_scope(cctx);
     return arg;