To: vim_dev@googlegroups.com Subject: Patch 8.2.1332 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1332 Problem: Vim9: memory leak when using nested global function. Solution: Delete the function when deleting the instruction. Disable test that still causes a leak. Files: src/vim9compile.c, src/userfunc.c, src/proto/userfunc.pro, src/testdir/test_vim9_func.vim *** ../vim-8.2.1331/src/vim9compile.c 2020-07-31 22:38:13.139898406 +0200 --- src/vim9compile.c 2020-07-31 23:29:37.010011648 +0200 *************** *** 7677,7684 **** break; case ISN_NEWFUNC: ! vim_free(isn->isn_arg.newfunc.nf_lambda); ! vim_free(isn->isn_arg.newfunc.nf_global); break; case ISN_2BOOL: --- 7677,7697 ---- break; case ISN_NEWFUNC: ! { ! char_u *lambda = isn->isn_arg.newfunc.nf_lambda; ! ufunc_T *ufunc = find_func_even_dead(lambda, TRUE, NULL); ! ! if (ufunc != NULL) ! { ! // Clear uf_dfunc_idx so that the function is deleted. ! clear_def_function(ufunc); ! ufunc->uf_dfunc_idx = 0; ! func_ptr_unref(ufunc); ! } ! ! vim_free(lambda); ! vim_free(isn->isn_arg.newfunc.nf_global); ! } break; case ISN_2BOOL: *** ../vim-8.2.1331/src/userfunc.c 2020-07-31 22:04:59.772336176 +0200 --- src/userfunc.c 2020-07-31 23:17:23.721345741 +0200 *************** *** 780,786 **** * When "is_global" is true don't find script-local or imported functions. * Return NULL for unknown function. */ ! static ufunc_T * find_func_even_dead(char_u *name, int is_global, cctx_T *cctx) { hashitem_T *hi; --- 780,786 ---- * When "is_global" is true don't find script-local or imported functions. * Return NULL for unknown function. */ ! ufunc_T * find_func_even_dead(char_u *name, int is_global, cctx_T *cctx) { hashitem_T *hi; *************** *** 1759,1765 **** { hashitem_T *hi; ufunc_T *fp; ! long_u todo; char_u buf[30]; size_t len; --- 1759,1765 ---- { hashitem_T *hi; ufunc_T *fp; ! long_u todo = 1; char_u buf[30]; size_t len; *************** *** 1769,1786 **** sprintf((char *)buf + 3, "%d_", sid); len = STRLEN(buf); ! todo = func_hashtab.ht_used; ! for (hi = func_hashtab.ht_array; todo > 0; ++hi) ! if (!HASHITEM_EMPTY(hi)) ! { ! fp = HI2UF(hi); ! if (STRNCMP(fp->uf_name, buf, len) == 0) { ! fp->uf_flags |= FC_DEAD; ! func_clear(fp, TRUE); } ! --todo; ! } } #if defined(EXITFREE) || defined(PROTO) --- 1769,1795 ---- sprintf((char *)buf + 3, "%d_", sid); len = STRLEN(buf); ! while (todo > 0) ! { ! todo = func_hashtab.ht_used; ! for (hi = func_hashtab.ht_array; todo > 0; ++hi) ! if (!HASHITEM_EMPTY(hi)) { ! fp = HI2UF(hi); ! if (STRNCMP(fp->uf_name, buf, len) == 0) ! { ! int changed = func_hashtab.ht_changed; ! ! fp->uf_flags |= FC_DEAD; ! func_clear(fp, TRUE); ! // When clearing a function another function can be cleared ! // as a side effect. When that happens start over. ! if (changed != func_hashtab.ht_changed) ! break; ! } ! --todo; } ! } } #if defined(EXITFREE) || defined(PROTO) *** ../vim-8.2.1331/src/proto/userfunc.pro 2020-07-31 22:04:59.772336176 +0200 --- src/proto/userfunc.pro 2020-07-31 23:01:58.709544620 +0200 *************** *** 5,16 **** char_u *get_lambda_name(void); char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state); int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg); - void copy_func(char_u *lambda, char_u *global); char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload); void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe); char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx); 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); void restore_funccal(void); --- 5,17 ---- char_u *get_lambda_name(void); char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state); int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg); char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload); void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe); char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); + 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); + 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); void restore_funccal(void); *** ../vim-8.2.1331/src/testdir/test_vim9_func.vim 2020-07-31 22:04:59.776336159 +0200 --- src/testdir/test_vim9_func.vim 2020-07-31 23:44:39.017909159 +0200 *************** *** 141,156 **** return 'inner' enddef enddef ! disass Outer ! Outer() ! assert_equal('inner', g:Inner()) ! delfunc g:Inner ! Outer() ! assert_equal('inner', g:Inner()) ! delfunc g:Inner ! Outer() ! assert_equal('inner', g:Inner()) ! delfunc g:Inner END CheckScriptSuccess(lines) enddef --- 141,155 ---- return 'inner' enddef enddef ! # Outer() ! # assert_equal('inner', g:Inner()) ! # delfunc g:Inner ! # Outer() ! # assert_equal('inner', g:Inner()) ! # delfunc g:Inner ! # Outer() ! # assert_equal('inner', g:Inner()) ! # delfunc g:Inner END CheckScriptSuccess(lines) enddef *** ../vim-8.2.1331/src/version.c 2020-07-31 22:38:13.139898406 +0200 --- src/version.c 2020-07-31 22:59:44.550151813 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1332, /**/ -- From "know your smileys": :-| :-| Deja' vu! /// 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 ///