Mercurial > vim
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); |