]> granicus.if.org Git - vim/commitdiff
patch 8.1.1563: crash when using closures v8.1.1563
authorBram Moolenaar <Bram@vim.org>
Mon, 17 Jun 2019 19:18:41 +0000 (21:18 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 17 Jun 2019 19:18:41 +0000 (21:18 +0200)
Problem:    Crash when using closures.
Solution:   Set reference in varlist of funccal when running the garbage
            collector. (Ozaki Kiichi, closes #4554, closes #4547)

src/testdir/test_vimscript.vim
src/userfunc.c
src/version.c

index 39ee0bfeec89032fe30cdab7c7ba05c2f11bdcf0..328d19fa5a4973630dbf2fac450842f881a3b91c 100644 (file)
@@ -1665,6 +1665,17 @@ func Test_refcount()
     delfunc DictFunc
 endfunc
 
+func! Test_funccall_garbage_collect()
+    func Func(x, ...)
+        call add(a:x, a:000)
+    endfunc
+    call Func([], [])
+    " Must not crash cause by invalid freeing
+    call test_garbagecollect_now()
+    call assert_true(v:true)
+    delfunc Func
+endfunc
+
 "-------------------------------------------------------------------------------
 " Modelines                                                                {{{1
 " vim: ts=8 sw=4 tw=80 fdm=marker
index 3a0219af46a0538ab4be7536a4d1d1b0cfcce3f3..197e2e06315b1ce6e2e918d1bd850844a73f9076 100644 (file)
@@ -935,12 +935,9 @@ call_user_func(
            v->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
        }
 
-       if (isdefault)
-           v->di_tv = def_rettv;
-       else
-           // Note: the values are copied directly to avoid alloc/free.
-           // "argvars" must have VAR_FIXED for v_lock.
-           v->di_tv = argvars[i];
+       // Note: the values are copied directly to avoid alloc/free.
+       // "argvars" must have VAR_FIXED for v_lock.
+       v->di_tv = isdefault ? def_rettv : argvars[i];
        v->di_tv.v_lock = VAR_FIXED;
 
        if (addlocal)
@@ -1540,7 +1537,6 @@ call_func(
        }
     }
 
-
     /*
      * Execute the function if executing and no errors were detected.
      */
@@ -3998,13 +3994,13 @@ set_ref_in_previous_funccal(int copyID)
     int                abort = FALSE;
     funccall_T *fc;
 
-    for (fc = previous_funccal; fc != NULL; fc = fc->caller)
+    for (fc = previous_funccal; !abort && fc != NULL; fc = fc->caller)
     {
        fc->fc_copyID = copyID + 1;
-       abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1,
-                                                                       NULL);
-       abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1,
-                                                                       NULL);
+       abort = abort
+           || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL)
+           || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL)
+           || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL);
     }
     return abort;
 }
@@ -4017,9 +4013,11 @@ set_ref_in_funccal(funccall_T *fc, int copyID)
     if (fc->fc_copyID != copyID)
     {
        fc->fc_copyID = copyID;
-       abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL);
-       abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL);
-       abort = abort || set_ref_in_func(NULL, fc->func, copyID);
+       abort = abort
+           || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL)
+           || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL)
+           || set_ref_in_list(&fc->l_varlist, copyID, NULL)
+           || set_ref_in_func(NULL, fc->func, copyID);
     }
     return abort;
 }
index f82f3c5b3422291a425eea070655959156febfe0..7c9a227bb2fdda344560ff91fb7bb6a52c015aaf 100644 (file)
@@ -777,6 +777,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1563,
 /**/
     1562,
 /**/