comparison src/eval.c @ 8855:b76195a1e38e v7.4.1715

commit https://github.com/vim/vim/commit/ddecc25947dbdd689d5bcaed32f298a08abdd497 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Apr 6 22:59:37 2016 +0200 patch 7.4.1715 Problem: Double free when a partial is in a cycle with a list or dict. (Nikolai Pavlov) Solution: Do not free a nested list or dict used by the partial.
author Christian Brabandt <cb@256bit.org>
date Wed, 06 Apr 2016 23:00:05 +0200
parents 9fa567d13551
children 03250bc0c63a
comparison
equal deleted inserted replaced
8854:183f05a25a5b 8855:b76195a1e38e
5927 *arg = p + 1; 5927 *arg = p + 1;
5928 5928
5929 return OK; 5929 return OK;
5930 } 5930 }
5931 5931
5932 static void
5933 partial_free(partial_T *pt, int recursive)
5934 {
5935 int i;
5936
5937 for (i = 0; i < pt->pt_argc; ++i)
5938 {
5939 typval_T *tv = &pt->pt_argv[i];
5940
5941 if (recursive || (tv->v_type != VAR_DICT && tv->v_type != VAR_LIST))
5942 clear_tv(tv);
5943 }
5944 vim_free(pt->pt_argv);
5945 if (recursive)
5946 dict_unref(pt->pt_dict);
5947 func_unref(pt->pt_name);
5948 vim_free(pt->pt_name);
5949 vim_free(pt);
5950 }
5951
5952 /*
5953 * Unreference a closure: decrement the reference count and free it when it
5954 * becomes zero.
5955 */
5956 void
5957 partial_unref(partial_T *pt)
5958 {
5959 if (pt != NULL && --pt->pt_refcount <= 0)
5960 partial_free(pt, TRUE);
5961 }
5962
5963 /*
5964 * Like clear_tv(), but do not free lists or dictionaries.
5965 * This is when called via free_unref_items().
5966 */
5967 static void
5968 clear_tv_no_recurse(typval_T *tv)
5969 {
5970 if (tv->v_type == VAR_PARTIAL)
5971 {
5972 partial_T *pt = tv->vval.v_partial;
5973
5974 /* We unref the partial but not the dict or any list it
5975 * refers to. */
5976 if (pt != NULL && --pt->pt_refcount == 0)
5977 partial_free(pt, FALSE);
5978 }
5979 else if (tv->v_type != VAR_LIST && tv->v_type != VAR_DICT)
5980 clear_tv(tv);
5981 }
5982
5932 /* 5983 /*
5933 * Allocate a variable for a List and fill it from "*arg". 5984 * Allocate a variable for a List and fill it from "*arg".
5934 * Return OK or FAIL. 5985 * Return OK or FAIL.
5935 */ 5986 */
5936 static int 5987 static int
6068 6119
6069 for (item = l->lv_first; item != NULL; item = l->lv_first) 6120 for (item = l->lv_first; item != NULL; item = l->lv_first)
6070 { 6121 {
6071 /* Remove the item before deleting it. */ 6122 /* Remove the item before deleting it. */
6072 l->lv_first = item->li_next; 6123 l->lv_first = item->li_next;
6073 if (recurse || (item->li_tv.v_type != VAR_LIST 6124 if (recurse)
6074 && item->li_tv.v_type != VAR_DICT))
6075 clear_tv(&item->li_tv); 6125 clear_tv(&item->li_tv);
6126 else
6127 clear_tv_no_recurse(&item->li_tv);
6076 vim_free(item); 6128 vim_free(item);
6077 } 6129 }
6078 vim_free(l); 6130 vim_free(l);
6079 } 6131 }
6080 6132
7182 newitem->ht = &dd->dv_hashtab; 7234 newitem->ht = &dd->dv_hashtab;
7183 newitem->prev = *ht_stack; 7235 newitem->prev = *ht_stack;
7184 *ht_stack = newitem; 7236 *ht_stack = newitem;
7185 } 7237 }
7186 } 7238 }
7239 }
7240 if (tv->v_type == VAR_PARTIAL)
7241 {
7242 partial_T *pt = tv->vval.v_partial;
7243 int i;
7244
7245 if (pt != NULL)
7246 for (i = 0; i < pt->pt_argc; ++i)
7247 set_ref_in_item(&pt->pt_argv[i], copyID,
7248 ht_stack, list_stack);
7187 } 7249 }
7188 } 7250 }
7189 else if (tv->v_type == VAR_LIST) 7251 else if (tv->v_type == VAR_LIST)
7190 { 7252 {
7191 ll = tv->vval.v_list; 7253 ll = tv->vval.v_list;
7213 } 7275 }
7214 } 7276 }
7215 return abort; 7277 return abort;
7216 } 7278 }
7217 7279
7218 static void
7219 partial_free(partial_T *pt, int free_dict)
7220 {
7221 int i;
7222
7223 for (i = 0; i < pt->pt_argc; ++i)
7224 clear_tv(&pt->pt_argv[i]);
7225 vim_free(pt->pt_argv);
7226 if (free_dict)
7227 dict_unref(pt->pt_dict);
7228 func_unref(pt->pt_name);
7229 vim_free(pt->pt_name);
7230 vim_free(pt);
7231 }
7232
7233 /*
7234 * Unreference a closure: decrement the reference count and free it when it
7235 * becomes zero.
7236 */
7237 void
7238 partial_unref(partial_T *pt)
7239 {
7240 if (pt != NULL && --pt->pt_refcount <= 0)
7241 partial_free(pt, TRUE);
7242 }
7243
7244 /* 7280 /*
7245 * Allocate an empty header for a dictionary. 7281 * Allocate an empty header for a dictionary.
7246 */ 7282 */
7247 dict_T * 7283 dict_T *
7248 dict_alloc(void) 7284 dict_alloc(void)
7329 { 7365 {
7330 /* Remove the item before deleting it, just in case there is 7366 /* Remove the item before deleting it, just in case there is
7331 * something recursive causing trouble. */ 7367 * something recursive causing trouble. */
7332 di = HI2DI(hi); 7368 di = HI2DI(hi);
7333 hash_remove(&d->dv_hashtab, hi); 7369 hash_remove(&d->dv_hashtab, hi);
7334 if (recurse || (di->di_tv.v_type != VAR_LIST 7370 if (recurse)
7335 && di->di_tv.v_type != VAR_DICT)) 7371 clear_tv(&di->di_tv);
7336 { 7372 else
7337 if (!recurse && di->di_tv.v_type == VAR_PARTIAL) 7373 clear_tv_no_recurse(&di->di_tv);
7338 {
7339 partial_T *pt = di->di_tv.vval.v_partial;
7340
7341 /* We unref the partial but not the dict it refers to. */
7342 if (pt != NULL && --pt->pt_refcount == 0)
7343 partial_free(pt, FALSE);
7344 }
7345 else
7346 clear_tv(&di->di_tv);
7347 }
7348 vim_free(di); 7374 vim_free(di);
7349 --todo; 7375 --todo;
7350 } 7376 }
7351 } 7377 }
7352 hash_clear(&d->dv_hashtab); 7378 hash_clear(&d->dv_hashtab);