To: vim_dev@googlegroups.com Subject: Patch 9.0.0487 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0487 (after 9.0.0485) Problem: Using freed memory with combination of closures. Solution: Do not use a partial after it has been freed through the funcstack. Files: src/vim9execute.c, src/proto/vim9execute.pro, src/eval.c *** ../vim-9.0.0486/src/vim9execute.c 2022-09-17 15:44:48.365409503 +0100 --- src/vim9execute.c 2022-09-17 16:23:46.339316875 +0100 *************** *** 797,812 **** * funcstack may be the only reference to the partials in the local variables. * Go over all of them, the funcref and can be freed if all partials * referencing the funcstack have a reference count of one. */ ! void funcstack_check_refcount(funcstack_T *funcstack) { ! int i; ! garray_T *gap = &funcstack->fs_ga; ! int done = 0; if (funcstack->fs_refcount > funcstack->fs_min_refcount) ! return; for (i = funcstack->fs_var_offset; i < gap->ga_len; ++i) { typval_T *tv = ((typval_T *)gap->ga_data) + i; --- 797,815 ---- * funcstack may be the only reference to the partials in the local variables. * Go over all of them, the funcref and can be freed if all partials * referencing the funcstack have a reference count of one. + * Returns TRUE if the funcstack is freed, the partial referencing it will then + * also have been freed. */ ! int funcstack_check_refcount(funcstack_T *funcstack) { ! int i; ! garray_T *gap = &funcstack->fs_ga; ! int done = 0; ! typval_T *stack; if (funcstack->fs_refcount > funcstack->fs_min_refcount) ! return FALSE; for (i = funcstack->fs_var_offset; i < gap->ga_len; ++i) { typval_T *tv = ((typval_T *)gap->ga_data) + i; *************** *** 816,833 **** && tv->vval.v_partial->pt_refcount == 1) ++done; } ! if (done == funcstack->fs_min_refcount) ! { ! typval_T *stack = gap->ga_data; ! // All partials referencing the funcstack have a reference count of ! // one, thus the funcstack is no longer of use. ! for (i = 0; i < gap->ga_len; ++i) ! clear_tv(stack + i); ! vim_free(stack); ! remove_funcstack_from_list(funcstack); ! vim_free(funcstack); ! } } /* --- 819,838 ---- && tv->vval.v_partial->pt_refcount == 1) ++done; } ! if (done != funcstack->fs_min_refcount) ! return FALSE; ! stack = gap->ga_data; ! ! // All partials referencing the funcstack have a reference count of ! // one, thus the funcstack is no longer of use. ! for (i = 0; i < gap->ga_len; ++i) ! clear_tv(stack + i); ! vim_free(stack); ! remove_funcstack_from_list(funcstack); ! vim_free(funcstack); ! ! return TRUE; } /* *** ../vim-9.0.0486/src/proto/vim9execute.pro 2022-09-17 15:44:48.365409503 +0100 --- src/proto/vim9execute.pro 2022-09-17 16:23:50.291303723 +0100 *************** *** 1,7 **** /* vim9execute.c */ void to_string_error(vartype_T vartype); void update_has_breakpoint(ufunc_T *ufunc); ! void funcstack_check_refcount(funcstack_T *funcstack); int set_ref_in_funcstacks(int copyID); int in_def_function(void); ectx_T *clear_currrent_ectx(void); --- 1,7 ---- /* vim9execute.c */ void to_string_error(vartype_T vartype); void update_has_breakpoint(ufunc_T *ufunc); ! int funcstack_check_refcount(funcstack_T *funcstack); int set_ref_in_funcstacks(int copyID); int in_def_function(void); ectx_T *clear_currrent_ectx(void); *** ../vim-9.0.0486/src/eval.c 2022-09-17 15:44:48.365409503 +0100 --- src/eval.c 2022-09-17 16:25:09.007048831 +0100 *************** *** 4876,4881 **** --- 4876,4883 ---- { if (pt != NULL) { + int done = FALSE; + if (--pt->pt_refcount <= 0) partial_free(pt); *************** *** 4883,4891 **** // only reference and can be freed if no other partials reference it. else if (pt->pt_refcount == 1) { if (pt->pt_funcstack != NULL) ! funcstack_check_refcount(pt->pt_funcstack); ! if (pt->pt_loopvars != NULL) loopvars_check_refcount(pt->pt_loopvars); } } --- 4885,4896 ---- // only reference and can be freed if no other partials reference it. else if (pt->pt_refcount == 1) { + // careful: if the funcstack is freed it may contain this partial + // and it gets freed as well if (pt->pt_funcstack != NULL) ! done = funcstack_check_refcount(pt->pt_funcstack); ! ! if (!done && pt->pt_loopvars != NULL) loopvars_check_refcount(pt->pt_loopvars); } } *** ../vim-9.0.0486/src/version.c 2022-09-17 16:16:31.925060698 +0100 --- src/version.c 2022-09-17 16:27:20.622649155 +0100 *************** *** 705,706 **** --- 705,708 ---- { /* Add new patch number below this line */ + /**/ + 487, /**/ -- From "know your smileys": 8<}} Glasses, big nose, beard /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///