comparison src/userfunc.c @ 9735:8037eb704e93 v7.4.2143

commit https://github.com/vim/vim/commit/bc7ce675b2d1c9fb58c067eff3edd59abc30aba4 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Aug 1 22:49:22 2016 +0200 patch 7.4.2143 Problem: A funccal is garbage collected while it can still be used. Solution: Set copyID in all referenced functions. Do not list lambda functions with ":function".
author Christian Brabandt <cb@256bit.org>
date Mon, 01 Aug 2016 23:00:07 +0200
parents 59565cdd7261
children 9ce5941b77d3
comparison
equal deleted inserted replaced
9734:9bdde041199c 9735:8037eb704e93
63 # ifdef __BORLANDC__ 63 # ifdef __BORLANDC__
64 _RTLENTRYF 64 _RTLENTRYF
65 # endif 65 # endif
66 prof_self_cmp(const void *s1, const void *s2); 66 prof_self_cmp(const void *s1, const void *s2);
67 #endif 67 #endif
68 static void funccal_unref(funccall_T *fc, ufunc_T *fp); 68 static void funccal_unref(funccall_T *fc, ufunc_T *fp, int force);
69 69
70 void 70 void
71 func_init() 71 func_init()
72 { 72 {
73 hash_init(&func_hashtab); 73 hash_init(&func_hashtab);
180 register_closure(ufunc_T *fp) 180 register_closure(ufunc_T *fp)
181 { 181 {
182 if (fp->uf_scoped == current_funccal) 182 if (fp->uf_scoped == current_funccal)
183 /* no change */ 183 /* no change */
184 return OK; 184 return OK;
185 funccal_unref(fp->uf_scoped, fp); 185 funccal_unref(fp->uf_scoped, fp, FALSE);
186 fp->uf_scoped = current_funccal; 186 fp->uf_scoped = current_funccal;
187 current_funccal->fc_refcount++; 187 current_funccal->fc_refcount++;
188 func_ptr_ref(current_funccal->func);
189 188
190 if (ga_grow(&current_funccal->fc_funcs, 1) == FAIL) 189 if (ga_grow(&current_funccal->fc_funcs, 1) == FAIL)
191 return FAIL; 190 return FAIL;
192 ((ufunc_T **)current_funccal->fc_funcs.ga_data) 191 ((ufunc_T **)current_funccal->fc_funcs.ga_data)
193 [current_funccal->fc_funcs.ga_len++] = fp; 192 [current_funccal->fc_funcs.ga_len++] = fp;
601 600
602 for (i = 0; i < fc->fc_funcs.ga_len; ++i) 601 for (i = 0; i < fc->fc_funcs.ga_len; ++i)
603 { 602 {
604 ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i]; 603 ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i];
605 604
606 if (fp != NULL) 605 /* When garbage collecting a funccall_T may be freed before the
607 { 606 * function that references it, clear its uf_scoped field.
608 /* Function may have been redefined and point to another 607 * The function may have been redefined and point to another
609 * funccall_T, don't clear it then. */ 608 * funccall_T, don't clear it then. */
610 if (fp->uf_scoped == fc) 609 if (fp != NULL && fp->uf_scoped == fc)
611 fp->uf_scoped = NULL; 610 fp->uf_scoped = NULL;
612 func_ptr_unref(fc->func);
613 }
614 } 611 }
615 ga_clear(&fc->fc_funcs); 612 ga_clear(&fc->fc_funcs);
616 613
617 /* The a: variables typevals may not have been allocated, only free the 614 /* The a: variables typevals may not have been allocated, only free the
618 * allocated variables. */ 615 * allocated variables. */
1028 } 1025 }
1029 1026
1030 /* 1027 /*
1031 * Unreference "fc": decrement the reference count and free it when it 1028 * Unreference "fc": decrement the reference count and free it when it
1032 * becomes zero. "fp" is detached from "fc". 1029 * becomes zero. "fp" is detached from "fc".
1030 * When "force" is TRUE we are exiting.
1033 */ 1031 */
1034 static void 1032 static void
1035 funccal_unref(funccall_T *fc, ufunc_T *fp) 1033 funccal_unref(funccall_T *fc, ufunc_T *fp, int force)
1036 { 1034 {
1037 funccall_T **pfc; 1035 funccall_T **pfc;
1038 int i; 1036 int i;
1039 1037
1040 if (fc == NULL) 1038 if (fc == NULL)
1041 return; 1039 return;
1042 1040
1043 if (--fc->fc_refcount <= 0 1041 if (--fc->fc_refcount <= 0 && (force || (
1044 && fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT 1042 fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
1045 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT 1043 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
1046 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) 1044 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)))
1047 for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) 1045 for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller)
1048 { 1046 {
1049 if (fc == *pfc) 1047 if (fc == *pfc)
1050 { 1048 {
1051 *pfc = fc->caller; 1049 *pfc = fc->caller;
1052 free_funccal(fc, TRUE); 1050 free_funccal(fc, TRUE);
1053 return; 1051 return;
1054 } 1052 }
1055 } 1053 }
1056 for (i = 0; i < fc->fc_funcs.ga_len; ++i) 1054 for (i = 0; i < fc->fc_funcs.ga_len; ++i)
1057 {
1058 if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp) 1055 if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp)
1059 {
1060 func_ptr_unref(fc->func);
1061 ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL; 1056 ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL;
1062 }
1063 }
1064 } 1057 }
1065 1058
1066 /* 1059 /*
1067 * Remove the function from the function hashtable. If the function was 1060 * Remove the function from the function hashtable. If the function was
1068 * deleted while it still has references this was already done. 1061 * deleted while it still has references this was already done.
1081 return FALSE; 1074 return FALSE;
1082 } 1075 }
1083 1076
1084 /* 1077 /*
1085 * Free a function and remove it from the list of functions. 1078 * Free a function and remove it from the list of functions.
1079 * When "force" is TRUE we are exiting.
1086 */ 1080 */
1087 static void 1081 static void
1088 func_free(ufunc_T *fp) 1082 func_free(ufunc_T *fp, int force)
1089 { 1083 {
1090 /* clear this function */ 1084 /* clear this function */
1091 ga_clear_strings(&(fp->uf_args)); 1085 ga_clear_strings(&(fp->uf_args));
1092 ga_clear_strings(&(fp->uf_lines)); 1086 ga_clear_strings(&(fp->uf_lines));
1093 #ifdef FEAT_PROFILE 1087 #ifdef FEAT_PROFILE
1098 /* only remove it when not done already, otherwise we would remove a newer 1092 /* only remove it when not done already, otherwise we would remove a newer
1099 * version of the function */ 1093 * version of the function */
1100 if ((fp->uf_flags & (FC_DELETED | FC_REMOVED)) == 0) 1094 if ((fp->uf_flags & (FC_DELETED | FC_REMOVED)) == 0)
1101 func_remove(fp); 1095 func_remove(fp);
1102 1096
1103 funccal_unref(fp->uf_scoped, fp); 1097 funccal_unref(fp->uf_scoped, fp, force);
1104 1098
1105 vim_free(fp); 1099 vim_free(fp);
1106 } 1100 }
1107 1101
1108 #if defined(EXITFREE) || defined(PROTO) 1102 #if defined(EXITFREE) || defined(PROTO)
1115 * hash table. */ 1109 * hash table. */
1116 while (func_hashtab.ht_used > 0) 1110 while (func_hashtab.ht_used > 0)
1117 for (hi = func_hashtab.ht_array; ; ++hi) 1111 for (hi = func_hashtab.ht_array; ; ++hi)
1118 if (!HASHITEM_EMPTY(hi)) 1112 if (!HASHITEM_EMPTY(hi))
1119 { 1113 {
1120 func_free(HI2UF(hi)); 1114 func_free(HI2UF(hi), TRUE);
1121 break; 1115 break;
1122 } 1116 }
1123 hash_clear(&func_hashtab); 1117 hash_clear(&func_hashtab);
1124 } 1118 }
1125 #endif 1119 #endif
1329 firstline, lastline, 1323 firstline, lastline,
1330 (fp->uf_flags & FC_DICT) ? selfdict : NULL); 1324 (fp->uf_flags & FC_DICT) ? selfdict : NULL);
1331 if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0) 1325 if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
1332 /* Function was unreferenced while being used, free it 1326 /* Function was unreferenced while being used, free it
1333 * now. */ 1327 * now. */
1334 func_free(fp); 1328 func_free(fp, FALSE);
1335 if (did_save_redo) 1329 if (did_save_redo)
1336 restoreRedobuff(); 1330 restoreRedobuff();
1337 restore_search_patterns(); 1331 restore_search_patterns();
1338 error = ERROR_NONE; 1332 error = ERROR_NONE;
1339 } 1333 }
1670 *pp = end; 1664 *pp = end;
1671 1665
1672 theend: 1666 theend:
1673 clear_lval(&lv); 1667 clear_lval(&lv);
1674 return name; 1668 return name;
1669 }
1670
1671 /*
1672 * There are two kinds of function names:
1673 * 1. ordinary names, function defined with :function
1674 * 2. numbered functions and lambdas
1675 * For the first we only count the name stored in func_hashtab as a reference,
1676 * using function() does not count as a reference, because the function is
1677 * looked up by name.
1678 */
1679 static int
1680 func_name_refcount(char_u *name)
1681 {
1682 return isdigit(*name) || *name == '<';
1675 } 1683 }
1676 1684
1677 /* 1685 /*
1678 * ":function" 1686 * ":function"
1679 */ 1687 */
1719 { 1727 {
1720 if (!HASHITEM_EMPTY(hi)) 1728 if (!HASHITEM_EMPTY(hi))
1721 { 1729 {
1722 --todo; 1730 --todo;
1723 fp = HI2UF(hi); 1731 fp = HI2UF(hi);
1724 if (!isdigit(*fp->uf_name)) 1732 if (!func_name_refcount(fp->uf_name))
1725 list_func_head(fp, FALSE); 1733 list_func_head(fp, FALSE);
1726 } 1734 }
1727 } 1735 }
1728 } 1736 }
1729 eap->nextcmd = check_nextcmd(eap->arg); 1737 eap->nextcmd = check_nextcmd(eap->arg);
2654 } 2662 }
2655 2663
2656 #endif /* FEAT_CMDL_COMPL */ 2664 #endif /* FEAT_CMDL_COMPL */
2657 2665
2658 /* 2666 /*
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 /*
2673 * ":delfunction {name}" 2667 * ":delfunction {name}"
2674 */ 2668 */
2675 void 2669 void
2676 ex_delfunction(exarg_T *eap) 2670 ex_delfunction(exarg_T *eap)
2677 { 2671 {
2736 if (func_remove(fp)) 2730 if (func_remove(fp))
2737 fp->uf_refcount--; 2731 fp->uf_refcount--;
2738 fp->uf_flags |= FC_DELETED; 2732 fp->uf_flags |= FC_DELETED;
2739 } 2733 }
2740 else 2734 else
2741 func_free(fp); 2735 func_free(fp, FALSE);
2742 } 2736 }
2743 } 2737 }
2744 } 2738 }
2745 2739
2746 /* 2740 /*
2765 if (fp != NULL && --fp->uf_refcount <= 0) 2759 if (fp != NULL && --fp->uf_refcount <= 0)
2766 { 2760 {
2767 /* Only delete it when it's not being used. Otherwise it's done 2761 /* Only delete it when it's not being used. Otherwise it's done
2768 * when "uf_calls" becomes zero. */ 2762 * when "uf_calls" becomes zero. */
2769 if (fp->uf_calls == 0) 2763 if (fp->uf_calls == 0)
2770 func_free(fp); 2764 func_free(fp, FALSE);
2771 } 2765 }
2772 } 2766 }
2773 2767
2774 /* 2768 /*
2775 * Unreference a Function: decrement the reference count and free it when it 2769 * Unreference a Function: decrement the reference count and free it when it
2781 if (fp != NULL && --fp->uf_refcount <= 0) 2775 if (fp != NULL && --fp->uf_refcount <= 0)
2782 { 2776 {
2783 /* Only delete it when it's not being used. Otherwise it's done 2777 /* Only delete it when it's not being used. Otherwise it's done
2784 * when "uf_calls" becomes zero. */ 2778 * when "uf_calls" becomes zero. */
2785 if (fp->uf_calls == 0) 2779 if (fp->uf_calls == 0)
2786 func_free(fp); 2780 func_free(fp, FALSE);
2787 } 2781 }
2788 } 2782 }
2789 2783
2790 /* 2784 /*
2791 * Count a reference to a Function. 2785 * Count a reference to a Function.
3674 NULL); 3668 NULL);
3675 } 3669 }
3676 return abort; 3670 return abort;
3677 } 3671 }
3678 3672
3679 /* 3673 static int
3680 * Set "copyID" in all local vars and arguments in the call stack. 3674 set_ref_in_funccal(funccall_T *fc, int copyID)
3681 */ 3675 {
3682 int 3676 int abort = FALSE;
3683 set_ref_in_call_stack(int copyID) 3677
3684 { 3678 if (fc->fc_copyID != copyID)
3685 int abort = FALSE;
3686 funccall_T *fc;
3687
3688 for (fc = current_funccal; fc != NULL; fc = fc->caller)
3689 { 3679 {
3690 fc->fc_copyID = copyID; 3680 fc->fc_copyID = copyID;
3691 abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL); 3681 abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL);
3692 abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL); 3682 abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL);
3683 abort = abort || set_ref_in_func(NULL, fc->func, copyID);
3684 }
3685 return abort;
3686 }
3687
3688 /*
3689 * Set "copyID" in all local vars and arguments in the call stack.
3690 */
3691 int
3692 set_ref_in_call_stack(int copyID)
3693 {
3694 int abort = FALSE;
3695 funccall_T *fc;
3696
3697 for (fc = current_funccal; fc != NULL; fc = fc->caller)
3698 abort = abort || set_ref_in_funccal(fc, copyID);
3699 return abort;
3700 }
3701
3702 /*
3703 * Set "copyID" in all functions available by name.
3704 */
3705 int
3706 set_ref_in_functions(int copyID)
3707 {
3708 int todo;
3709 hashitem_T *hi = NULL;
3710 int abort = FALSE;
3711 ufunc_T *fp;
3712
3713 todo = (int)func_hashtab.ht_used;
3714 for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
3715 {
3716 if (!HASHITEM_EMPTY(hi))
3717 {
3718 --todo;
3719 fp = HI2UF(hi);
3720 if (!func_name_refcount(fp->uf_name))
3721 abort = abort || set_ref_in_func(NULL, fp, copyID);
3722 }
3693 } 3723 }
3694 return abort; 3724 return abort;
3695 } 3725 }
3696 3726
3697 /* 3727 /*
3709 return abort; 3739 return abort;
3710 } 3740 }
3711 3741
3712 /* 3742 /*
3713 * Mark all lists and dicts referenced through function "name" with "copyID". 3743 * Mark all lists and dicts referenced through function "name" with "copyID".
3714 * "list_stack" is used to add lists to be marked. Can be NULL.
3715 * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
3716 *
3717 * Returns TRUE if setting references failed somehow. 3744 * Returns TRUE if setting references failed somehow.
3718 */ 3745 */
3719 int 3746 int
3720 set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) 3747 set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
3721 { 3748 {
3723 funccall_T *fc; 3750 funccall_T *fc;
3724 int error = ERROR_NONE; 3751 int error = ERROR_NONE;
3725 char_u fname_buf[FLEN_FIXED + 1]; 3752 char_u fname_buf[FLEN_FIXED + 1];
3726 char_u *tofree = NULL; 3753 char_u *tofree = NULL;
3727 char_u *fname; 3754 char_u *fname;
3755 int abort = FALSE;
3728 3756
3729 if (name == NULL && fp_in == NULL) 3757 if (name == NULL && fp_in == NULL)
3730 return FALSE; 3758 return FALSE;
3731 3759
3732 if (fp_in == NULL) 3760 if (fp_in == NULL)
3735 fp = find_func(fname); 3763 fp = find_func(fname);
3736 } 3764 }
3737 if (fp != NULL) 3765 if (fp != NULL)
3738 { 3766 {
3739 for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped) 3767 for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
3740 { 3768 abort = abort || set_ref_in_funccal(fc, copyID);
3741 if (fc->fc_copyID != copyID)
3742 {
3743 fc->fc_copyID = copyID;
3744 set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL);
3745 set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL);
3746 }
3747 }
3748 } 3769 }
3749 vim_free(tofree); 3770 vim_free(tofree);
3750 return FALSE; 3771 return abort;
3751 } 3772 }
3752 3773
3753 #endif /* FEAT_EVAL */ 3774 #endif /* FEAT_EVAL */