]> granicus.if.org Git - vim/commitdiff
patch 8.2.0697: Vim9: memory leak when using nested function v8.2.0697
authorBram Moolenaar <Bram@vim.org>
Tue, 5 May 2020 17:46:20 +0000 (19:46 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 5 May 2020 17:46:20 +0000 (19:46 +0200)
Problem:    Vim9: memory leak when using nested function.
Solution:   Unreference function when deleting instructions. Adjust reference
            count for local variables.

src/version.c
src/vim9compile.c
src/vim9execute.c

index 38755db73ff2318df446c6ef48bcad39a4fcb9f6..edbfa9349bad9e9078b65f5af3ef59307e1fb88a 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    697,
 /**/
     696,
 /**/
index de2fb96b516abfb783f1d25376fd6725401a8c9f..42fc0749add3fd9295ec40f34f8442e1eb243fc3 100644 (file)
@@ -6629,6 +6629,14 @@ delete_instr(isn_T *isn)
            vim_free(isn->isn_arg.ufunc.cuf_name);
            break;
 
+       case ISN_FUNCREF:
+           {
+               dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+                                              + isn->isn_arg.funcref.fr_func;
+               func_ptr_unref(dfunc->df_ufunc);
+           }
+           break;
+
        case ISN_2BOOL:
        case ISN_2STRING:
        case ISN_ADDBLOB:
@@ -6657,7 +6665,6 @@ delete_instr(isn_T *isn)
        case ISN_EXECCONCAT:
        case ISN_EXECUTE:
        case ISN_FOR:
-       case ISN_FUNCREF:
        case ISN_INDEX:
        case ISN_JUMP:
        case ISN_LOAD:
index c74240ff2037f217b3b12da791959dcbea602b23..386b8491f933cdea3c84c9b2e2b81022148855b3 100644 (file)
@@ -264,10 +264,27 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments)
     {
        tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
                                                   + dfunc->df_varcount + idx);
-       if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial->pt_refcount > 1)
+       if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL
+                                       && tv->vval.v_partial->pt_refcount > 1)
        {
-           closure_in_use = TRUE;
-           break;
+           int refcount = tv->vval.v_partial->pt_refcount;
+           int i;
+
+           // A Reference in a local variables doesn't count, its get
+           // unreferenced on return.
+           for (i = 0; i < dfunc->df_varcount; ++i)
+           {
+               typval_T *stv = STACK_TV(ectx->ec_frame_idx
+                                                      + STACK_FRAME_SIZE + i);
+               if (stv->v_type == VAR_PARTIAL
+                                 && tv->vval.v_partial == stv->vval.v_partial)
+                   --refcount;
+           }
+           if (refcount > 1)
+           {
+               closure_in_use = TRUE;
+               break;
+           }
        }
     }