Mercurial > vim
comparison src/userfunc.c @ 9733:59565cdd7261 v7.4.2142
commit https://github.com/vim/vim/commit/8dd3a43d75550e9b5736066124c97697564f769e
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Aug 1 20:46:25 2016 +0200
patch 7.4.2142
Problem: Leaking memory when redefining a function.
Solution: Don't increment the function reference count when it's found by
name. Don't remove the wrong function from the hashtab. More
reference counting fixes.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 01 Aug 2016 21:00:06 +0200 |
parents | f85d94eee05b |
children | 8037eb704e93 |
comparison
equal
deleted
inserted
replaced
9732:fe4bdbd102ea | 9733:59565cdd7261 |
---|---|
13 | 13 |
14 #include "vim.h" | 14 #include "vim.h" |
15 | 15 |
16 #if defined(FEAT_EVAL) || defined(PROTO) | 16 #if defined(FEAT_EVAL) || defined(PROTO) |
17 /* function flags */ | 17 /* function flags */ |
18 #define FC_ABORT 1 /* abort function on error */ | 18 #define FC_ABORT 0x01 /* abort function on error */ |
19 #define FC_RANGE 2 /* function accepts range */ | 19 #define FC_RANGE 0x02 /* function accepts range */ |
20 #define FC_DICT 4 /* Dict function, uses "self" */ | 20 #define FC_DICT 0x04 /* Dict function, uses "self" */ |
21 #define FC_CLOSURE 8 /* closure, uses outer scope variables */ | 21 #define FC_CLOSURE 0x08 /* closure, uses outer scope variables */ |
22 #define FC_DELETED 16 /* :delfunction used while uf_refcount > 0 */ | 22 #define FC_DELETED 0x10 /* :delfunction used while uf_refcount > 0 */ |
23 #define FC_REMOVED 0x20 /* function redefined while uf_refcount > 0 */ | |
23 | 24 |
24 /* From user function to hashitem and back. */ | 25 /* From user function to hashitem and back. */ |
25 #define UF2HIKEY(fp) ((fp)->uf_name) | 26 #define UF2HIKEY(fp) ((fp)->uf_name) |
26 #define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name))) | 27 #define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name))) |
27 #define HI2UF(hi) HIKEY2UF((hi)->hi_key) | 28 #define HI2UF(hi) HIKEY2UF((hi)->hi_key) |
176 * Register function "fp" as using "current_funccal" as its scope. | 177 * Register function "fp" as using "current_funccal" as its scope. |
177 */ | 178 */ |
178 static int | 179 static int |
179 register_closure(ufunc_T *fp) | 180 register_closure(ufunc_T *fp) |
180 { | 181 { |
181 funccal_unref(fp->uf_scoped, NULL); | 182 if (fp->uf_scoped == current_funccal) |
183 /* no change */ | |
184 return OK; | |
185 funccal_unref(fp->uf_scoped, fp); | |
182 fp->uf_scoped = current_funccal; | 186 fp->uf_scoped = current_funccal; |
183 current_funccal->fc_refcount++; | 187 current_funccal->fc_refcount++; |
188 func_ptr_ref(current_funccal->func); | |
189 | |
184 if (ga_grow(¤t_funccal->fc_funcs, 1) == FAIL) | 190 if (ga_grow(¤t_funccal->fc_funcs, 1) == FAIL) |
185 return FAIL; | 191 return FAIL; |
186 ((ufunc_T **)current_funccal->fc_funcs.ga_data) | 192 ((ufunc_T **)current_funccal->fc_funcs.ga_data) |
187 [current_funccal->fc_funcs.ga_len++] = fp; | 193 [current_funccal->fc_funcs.ga_len++] = fp; |
188 func_ptr_ref(current_funccal->func); | |
189 return OK; | 194 return OK; |
190 } | 195 } |
191 | 196 |
192 /* | 197 /* |
193 * Parse a lambda expression and get a Funcref from "*arg". | 198 * Parse a lambda expression and get a Funcref from "*arg". |
1022 } | 1027 } |
1023 } | 1028 } |
1024 | 1029 |
1025 /* | 1030 /* |
1026 * Unreference "fc": decrement the reference count and free it when it | 1031 * Unreference "fc": decrement the reference count and free it when it |
1027 * becomes zero. If "fp" is not NULL, "fp" is detached from "fc". | 1032 * becomes zero. "fp" is detached from "fc". |
1028 */ | 1033 */ |
1029 static void | 1034 static void |
1030 funccal_unref(funccall_T *fc, ufunc_T *fp) | 1035 funccal_unref(funccall_T *fc, ufunc_T *fp) |
1031 { | 1036 { |
1032 funccall_T **pfc; | 1037 funccall_T **pfc; |
1033 int i; | 1038 int i; |
1034 int freed = FALSE; | |
1035 | 1039 |
1036 if (fc == NULL) | 1040 if (fc == NULL) |
1037 return; | 1041 return; |
1038 | 1042 |
1039 if (--fc->fc_refcount <= 0) | 1043 if (--fc->fc_refcount <= 0 |
1040 { | 1044 && fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT |
1045 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT | |
1046 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) | |
1041 for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) | 1047 for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) |
1042 { | 1048 { |
1043 if (fc == *pfc) | 1049 if (fc == *pfc) |
1044 { | 1050 { |
1045 if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT | 1051 *pfc = fc->caller; |
1046 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT | 1052 free_funccal(fc, TRUE); |
1047 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) | 1053 return; |
1048 { | |
1049 *pfc = fc->caller; | |
1050 free_funccal(fc, TRUE); | |
1051 freed = TRUE; | |
1052 } | |
1053 break; | |
1054 } | 1054 } |
1055 } | 1055 } |
1056 } | 1056 for (i = 0; i < fc->fc_funcs.ga_len; ++i) |
1057 if (!freed) | 1057 { |
1058 { | 1058 if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp) |
1059 func_ptr_unref(fc->func); | 1059 { |
1060 | 1060 func_ptr_unref(fc->func); |
1061 if (fp != NULL) | 1061 ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL; |
1062 for (i = 0; i < fc->fc_funcs.ga_len; ++i) | 1062 } |
1063 { | |
1064 if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp) | |
1065 ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL; | |
1066 } | |
1067 } | 1063 } |
1068 } | 1064 } |
1069 | 1065 |
1070 /* | 1066 /* |
1071 * Remove the function from the function hashtable. If the function was | 1067 * Remove the function from the function hashtable. If the function was |
1072 * deleted while it still has references this was already done. | 1068 * deleted while it still has references this was already done. |
1073 */ | 1069 * Return TRUE if the entry was deleted, FALSE if it wasn't found. |
1074 static void | 1070 */ |
1071 static int | |
1075 func_remove(ufunc_T *fp) | 1072 func_remove(ufunc_T *fp) |
1076 { | 1073 { |
1077 hashitem_T *hi = hash_find(&func_hashtab, UF2HIKEY(fp)); | 1074 hashitem_T *hi = hash_find(&func_hashtab, UF2HIKEY(fp)); |
1078 | 1075 |
1079 if (!HASHITEM_EMPTY(hi)) | 1076 if (!HASHITEM_EMPTY(hi)) |
1077 { | |
1080 hash_remove(&func_hashtab, hi); | 1078 hash_remove(&func_hashtab, hi); |
1079 return TRUE; | |
1080 } | |
1081 return FALSE; | |
1081 } | 1082 } |
1082 | 1083 |
1083 /* | 1084 /* |
1084 * Free a function and remove it from the list of functions. | 1085 * Free a function and remove it from the list of functions. |
1085 */ | 1086 */ |
1092 #ifdef FEAT_PROFILE | 1093 #ifdef FEAT_PROFILE |
1093 vim_free(fp->uf_tml_count); | 1094 vim_free(fp->uf_tml_count); |
1094 vim_free(fp->uf_tml_total); | 1095 vim_free(fp->uf_tml_total); |
1095 vim_free(fp->uf_tml_self); | 1096 vim_free(fp->uf_tml_self); |
1096 #endif | 1097 #endif |
1097 func_remove(fp); | 1098 /* only remove it when not done already, otherwise we would remove a newer |
1099 * version of the function */ | |
1100 if ((fp->uf_flags & (FC_DELETED | FC_REMOVED)) == 0) | |
1101 func_remove(fp); | |
1098 | 1102 |
1099 funccal_unref(fp->uf_scoped, fp); | 1103 funccal_unref(fp->uf_scoped, fp); |
1100 | 1104 |
1101 vim_free(fp); | 1105 vim_free(fp); |
1102 } | 1106 } |
2156 if (fp->uf_refcount > 1) | 2160 if (fp->uf_refcount > 1) |
2157 { | 2161 { |
2158 /* This function is referenced somewhere, don't redefine it but | 2162 /* This function is referenced somewhere, don't redefine it but |
2159 * create a new one. */ | 2163 * create a new one. */ |
2160 --fp->uf_refcount; | 2164 --fp->uf_refcount; |
2165 fp->uf_flags |= FC_REMOVED; | |
2161 fp = NULL; | 2166 fp = NULL; |
2162 overwrite = TRUE; | 2167 overwrite = TRUE; |
2163 } | 2168 } |
2164 else | 2169 else |
2165 { | 2170 { |
2649 } | 2654 } |
2650 | 2655 |
2651 #endif /* FEAT_CMDL_COMPL */ | 2656 #endif /* FEAT_CMDL_COMPL */ |
2652 | 2657 |
2653 /* | 2658 /* |
2659 * There are two kinds of function names: | |
2660 * 1. ordinary names, function defined with :function | |
2661 * 2. numbered functions and lambdas | |
2662 * For the first we only count the name stored in func_hashtab as a reference, | |
2663 * using function() does not count as a reference, because the function is | |
2664 * looked up by name. | |
2665 */ | |
2666 static int | |
2667 func_name_refcount(char_u *name) | |
2668 { | |
2669 return isdigit(*name) || *name == '<'; | |
2670 } | |
2671 | |
2672 /* | |
2654 * ":delfunction {name}" | 2673 * ":delfunction {name}" |
2655 */ | 2674 */ |
2656 void | 2675 void |
2657 ex_delfunction(exarg_T *eap) | 2676 ex_delfunction(exarg_T *eap) |
2658 { | 2677 { |
2703 * invoke func_unref() and possibly delete the function. */ | 2722 * invoke func_unref() and possibly delete the function. */ |
2704 dictitem_remove(fudi.fd_dict, fudi.fd_di); | 2723 dictitem_remove(fudi.fd_dict, fudi.fd_di); |
2705 } | 2724 } |
2706 else | 2725 else |
2707 { | 2726 { |
2708 /* Normal functions (not numbered functions and lambdas) have a | 2727 /* A normal function (not a numbered function or lambda) has a |
2709 * refcount of 1 for the entry in the hashtable. When deleting | 2728 * refcount of 1 for the entry in the hashtable. When deleting |
2710 * them and the refcount is more than one, it should be kept. | 2729 * it and the refcount is more than one, it should be kept. |
2711 * Numbered functions and lambdas snould be kept if the refcount is | 2730 * A numbered function and lambda snould be kept if the refcount is |
2712 * one or more. */ | 2731 * one or more. */ |
2713 if (fp->uf_refcount > (isdigit(fp->uf_name[0]) | 2732 if (fp->uf_refcount > (func_name_refcount(fp->uf_name) ? 0 : 1)) |
2714 || fp->uf_name[0] == '<' ? 0 : 1)) | |
2715 { | 2733 { |
2716 /* Function is still referenced somewhere. Don't free it but | 2734 /* Function is still referenced somewhere. Don't free it but |
2717 * do remove it from the hashtable. */ | 2735 * do remove it from the hashtable. */ |
2718 func_remove(fp); | 2736 if (func_remove(fp)) |
2737 fp->uf_refcount--; | |
2719 fp->uf_flags |= FC_DELETED; | 2738 fp->uf_flags |= FC_DELETED; |
2720 fp->uf_refcount--; | |
2721 } | 2739 } |
2722 else | 2740 else |
2723 func_free(fp); | 2741 func_free(fp); |
2724 } | 2742 } |
2725 } | 2743 } |
2732 void | 2750 void |
2733 func_unref(char_u *name) | 2751 func_unref(char_u *name) |
2734 { | 2752 { |
2735 ufunc_T *fp = NULL; | 2753 ufunc_T *fp = NULL; |
2736 | 2754 |
2737 if (name == NULL) | 2755 if (name == NULL || !func_name_refcount(name)) |
2738 return; | 2756 return; |
2739 fp = find_func(name); | 2757 fp = find_func(name); |
2740 if (fp == NULL && isdigit(*name)) | 2758 if (fp == NULL && isdigit(*name)) |
2741 { | 2759 { |
2742 #ifdef EXITFREE | 2760 #ifdef EXITFREE |
2775 void | 2793 void |
2776 func_ref(char_u *name) | 2794 func_ref(char_u *name) |
2777 { | 2795 { |
2778 ufunc_T *fp; | 2796 ufunc_T *fp; |
2779 | 2797 |
2780 if (name == NULL) | 2798 if (name == NULL || !func_name_refcount(name)) |
2781 return; | 2799 return; |
2782 fp = find_func(name); | 2800 fp = find_func(name); |
2783 if (fp != NULL) | 2801 if (fp != NULL) |
2784 ++fp->uf_refcount; | 2802 ++fp->uf_refcount; |
2785 else if (isdigit(*name)) | 2803 else if (isdigit(*name)) |