To: vim_dev@googlegroups.com Subject: Patch 8.2.1712 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1712 Problem: Vim9: leaking memory when calling a lambda. Solution: Decrement function reference from ISN_DCALL. Files: src/vim9compile.c, src/userfunc.c, src/proto/userfunc.pro *** ../vim-8.2.1711/src/vim9compile.c 2020-09-19 15:16:46.395622457 +0200 --- src/vim9compile.c 2020-09-19 18:05:00.907313691 +0200 *************** *** 1452,1458 **** ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL : ISN_UCALL)) == NULL) return FAIL; ! if (ufunc->uf_def_status != UF_NOT_COMPILED) { isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx; isn->isn_arg.dfunc.cdf_argcount = argcount; --- 1452,1458 ---- ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL : ISN_UCALL)) == NULL) return FAIL; ! if (isn->isn_type == ISN_DCALL) { isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx; isn->isn_arg.dfunc.cdf_argcount = argcount; *************** *** 2634,2641 **** clear_tv(&rettv); ga_init2(&ufunc->uf_type_list, sizeof(type_T *), 10); ! // The function will have one line: "return {expr}". ! // Compile it into instructions. compile_def_function(ufunc, TRUE, cctx); // compile the arguments --- 2634,2641 ---- clear_tv(&rettv); ga_init2(&ufunc->uf_type_list, sizeof(type_T *), 10); ! // The function will have one line: "return {expr}". Compile it into ! // instructions so that we get any errors right now. compile_def_function(ufunc, TRUE, cctx); // compile the arguments *************** *** 7285,7291 **** { dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + isn->isn_arg.funcref.fr_func; ! func_ptr_unref(dfunc->df_ufunc); } break; --- 7285,7303 ---- { dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + isn->isn_arg.funcref.fr_func; ! ! if (func_name_refcount(dfunc->df_ufunc->uf_name)) ! func_ptr_unref(dfunc->df_ufunc); ! } ! break; ! ! case ISN_DCALL: ! { ! dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) ! + isn->isn_arg.dfunc.cdf_idx; ! ! if (func_name_refcount(dfunc->df_ufunc->uf_name)) ! func_ptr_unref(dfunc->df_ufunc); } break; *************** *** 7333,7339 **** case ISN_COMPARESPECIAL: case ISN_COMPARESTRING: case ISN_CONCAT: - case ISN_DCALL: case ISN_DROP: case ISN_ECHO: case ISN_ECHOERR: --- 7345,7350 ---- *** ../vim-8.2.1711/src/userfunc.c 2020-09-19 15:16:46.395622457 +0200 --- src/userfunc.c 2020-09-19 18:04:40.459403238 +0200 *************** *** 1058,1064 **** * using function() does not count as a reference, because the function is * looked up by name. */ ! static int func_name_refcount(char_u *name) { return isdigit(*name) || *name == '<'; --- 1058,1064 ---- * using function() does not count as a reference, because the function is * looked up by name. */ ! int func_name_refcount(char_u *name) { return isdigit(*name) || *name == '<'; *************** *** 1176,1183 **** * Free a function and remove it from the list of functions. Does not free * what a function contains, call func_clear() first. * When "force" is TRUE we are exiting. */ ! static void func_free(ufunc_T *fp, int force) { // Only remove it when not done already, otherwise we would remove a newer --- 1176,1184 ---- * Free a function and remove it from the list of functions. Does not free * what a function contains, call func_clear() first. * When "force" is TRUE we are exiting. + * Returns OK when the function was actually freed. */ ! static int func_free(ufunc_T *fp, int force) { // Only remove it when not done already, otherwise we would remove a newer *************** *** 1191,1197 **** --- 1192,1200 ---- unlink_def_function(fp); VIM_CLEAR(fp->uf_name_exp); vim_free(fp); + return OK; } + return FAIL; } /* *************** *** 1890,1898 **** ++skipped; else { ! func_free(fp, FALSE); ! skipped = 0; ! break; } } } --- 1893,1905 ---- ++skipped; else { ! if (func_free(fp, FALSE) == OK) ! { ! skipped = 0; ! break; ! } ! // did not actually free it ! ++skipped; } } } *** ../vim-8.2.1711/src/proto/userfunc.pro 2020-09-12 18:32:30.683427305 +0200 --- src/proto/userfunc.pro 2020-09-19 18:04:43.675389188 +0200 *************** *** 12,17 **** --- 12,18 ---- ufunc_T *find_func_even_dead(char_u *name, int is_global, cctx_T *cctx); ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx); int func_is_global(ufunc_T *ufunc); + int func_name_refcount(char_u *name); void copy_func(char_u *lambda, char_u *global); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); void save_funccal(funccal_entry_T *entry); *** ../vim-8.2.1711/src/version.c 2020-09-19 15:16:46.399622447 +0200 --- src/version.c 2020-09-19 18:17:36.135766329 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 1712, /**/ -- If you don't get everything you want, think of everything you didn't get and don't want. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///