comparison src/eval.c @ 8863:e1b84109506a v7.4.1719

commit https://github.com/vim/vim/commit/107e1eef1df3b786ad3ad49fbdb9e058649303b5 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Apr 8 17:07:19 2016 +0200 patch 7.4.1719 Problem: Leaking memory when there is a cycle involving a job and a partial. Solution: Add a copyID to job and channel. Set references in items referred by them. Go through all jobs and channels to find unreferenced items. Also, decrement reference counts when garbage collecting.
author Christian Brabandt <cb@256bit.org>
date Fri, 08 Apr 2016 17:15:06 +0200
parents 45fe799c9672
children 30988ffb7498
comparison
equal deleted inserted replaced
8862:e759159b4432 8863:e1b84109506a
428 static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose); 428 static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose);
429 static int get_option_tv(char_u **arg, typval_T *rettv, int evaluate); 429 static int get_option_tv(char_u **arg, typval_T *rettv, int evaluate);
430 static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); 430 static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate);
431 static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); 431 static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate);
432 static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate); 432 static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate);
433 static void list_free_contents(list_T *l);
434 static void list_free_list(list_T *l);
433 static long list_len(list_T *l); 435 static long list_len(list_T *l);
434 static int list_equal(list_T *l1, list_T *l2, int ic, int recursive); 436 static int list_equal(list_T *l1, list_T *l2, int ic, int recursive);
435 static int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); 437 static int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive);
436 static int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); 438 static int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive);
437 static long list_find_nr(list_T *l, long idx, int *errorp); 439 static long list_find_nr(list_T *l, long idx, int *errorp);
456 static int find_internal_func(char_u *name); 458 static int find_internal_func(char_u *name);
457 static char_u *deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload); 459 static char_u *deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload);
458 static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict); 460 static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict);
459 static void emsg_funcname(char *ermsg, char_u *name); 461 static void emsg_funcname(char *ermsg, char_u *name);
460 static int non_zero_arg(typval_T *argvars); 462 static int non_zero_arg(typval_T *argvars);
463
464 static void dict_free_contents(dict_T *d);
465 static void dict_free_dict(dict_T *d);
461 466
462 #ifdef FEAT_FLOAT 467 #ifdef FEAT_FLOAT
463 static void f_abs(typval_T *argvars, typval_T *rettv); 468 static void f_abs(typval_T *argvars, typval_T *rettv);
464 static void f_acos(typval_T *argvars, typval_T *rettv); 469 static void f_acos(typval_T *argvars, typval_T *rettv);
465 #endif 470 #endif
5587 for (item = list_find(rettv->vval.v_list, n1); 5592 for (item = list_find(rettv->vval.v_list, n1);
5588 n1 <= n2; ++n1) 5593 n1 <= n2; ++n1)
5589 { 5594 {
5590 if (list_append_tv(l, &item->li_tv) == FAIL) 5595 if (list_append_tv(l, &item->li_tv) == FAIL)
5591 { 5596 {
5592 list_free(l, TRUE); 5597 list_free(l);
5593 return FAIL; 5598 return FAIL;
5594 } 5599 }
5595 item = item->li_next; 5600 item = item->li_next;
5596 } 5601 }
5597 clear_tv(rettv); 5602 clear_tv(rettv);
5928 5933
5929 return OK; 5934 return OK;
5930 } 5935 }
5931 5936
5932 static void 5937 static void
5933 partial_free(partial_T *pt, int recursive) 5938 partial_free(partial_T *pt)
5934 { 5939 {
5935 int i; 5940 int i;
5936 5941
5937 for (i = 0; i < pt->pt_argc; ++i) 5942 for (i = 0; i < pt->pt_argc; ++i)
5938 { 5943 clear_tv(&pt->pt_argv[i]);
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); 5944 vim_free(pt->pt_argv);
5945 if (recursive) 5945 dict_unref(pt->pt_dict);
5946 dict_unref(pt->pt_dict);
5947 func_unref(pt->pt_name); 5946 func_unref(pt->pt_name);
5948 vim_free(pt->pt_name); 5947 vim_free(pt->pt_name);
5949 vim_free(pt); 5948 vim_free(pt);
5950 } 5949 }
5951 5950
5955 */ 5954 */
5956 void 5955 void
5957 partial_unref(partial_T *pt) 5956 partial_unref(partial_T *pt)
5958 { 5957 {
5959 if (pt != NULL && --pt->pt_refcount <= 0) 5958 if (pt != NULL && --pt->pt_refcount <= 0)
5960 partial_free(pt, TRUE); 5959 partial_free(pt);
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 } 5960 }
5982 5961
5983 /* 5962 /*
5984 * Allocate a variable for a List and fill it from "*arg". 5963 * Allocate a variable for a List and fill it from "*arg".
5985 * Return OK or FAIL. 5964 * Return OK or FAIL.
6029 if (**arg != ']') 6008 if (**arg != ']')
6030 { 6009 {
6031 EMSG2(_("E697: Missing end of List ']': %s"), *arg); 6010 EMSG2(_("E697: Missing end of List ']': %s"), *arg);
6032 failret: 6011 failret:
6033 if (evaluate) 6012 if (evaluate)
6034 list_free(l, TRUE); 6013 list_free(l);
6035 return FAIL; 6014 return FAIL;
6036 } 6015 }
6037 6016
6038 *arg = skipwhite(*arg + 1); 6017 *arg = skipwhite(*arg + 1);
6039 if (evaluate) 6018 if (evaluate)
6093 */ 6072 */
6094 void 6073 void
6095 list_unref(list_T *l) 6074 list_unref(list_T *l)
6096 { 6075 {
6097 if (l != NULL && --l->lv_refcount <= 0) 6076 if (l != NULL && --l->lv_refcount <= 0)
6098 list_free(l, TRUE); 6077 list_free(l);
6099 } 6078 }
6100 6079
6101 /* 6080 /*
6102 * Free a list, including all non-container items it points to. 6081 * Free a list, including all non-container items it points to.
6103 * Ignores the reference count. 6082 * Ignores the reference count.
6104 */ 6083 */
6105 void 6084 static void
6106 list_free( 6085 list_free_contents(list_T *l)
6107 list_T *l,
6108 int recurse) /* Free Lists and Dictionaries recursively. */
6109 { 6086 {
6110 listitem_T *item; 6087 listitem_T *item;
6111 6088
6089 for (item = l->lv_first; item != NULL; item = l->lv_first)
6090 {
6091 /* Remove the item before deleting it. */
6092 l->lv_first = item->li_next;
6093 clear_tv(&item->li_tv);
6094 vim_free(item);
6095 }
6096 }
6097
6098 static void
6099 list_free_list(list_T *l)
6100 {
6112 /* Remove the list from the list of lists for garbage collection. */ 6101 /* Remove the list from the list of lists for garbage collection. */
6113 if (l->lv_used_prev == NULL) 6102 if (l->lv_used_prev == NULL)
6114 first_list = l->lv_used_next; 6103 first_list = l->lv_used_next;
6115 else 6104 else
6116 l->lv_used_prev->lv_used_next = l->lv_used_next; 6105 l->lv_used_prev->lv_used_next = l->lv_used_next;
6117 if (l->lv_used_next != NULL) 6106 if (l->lv_used_next != NULL)
6118 l->lv_used_next->lv_used_prev = l->lv_used_prev; 6107 l->lv_used_next->lv_used_prev = l->lv_used_prev;
6119 6108
6120 for (item = l->lv_first; item != NULL; item = l->lv_first)
6121 {
6122 /* Remove the item before deleting it. */
6123 l->lv_first = item->li_next;
6124 if (recurse)
6125 clear_tv(&item->li_tv);
6126 else
6127 clear_tv_no_recurse(&item->li_tv);
6128 vim_free(item);
6129 }
6130 vim_free(l); 6109 vim_free(l);
6110 }
6111
6112 void
6113 list_free(list_T *l)
6114 {
6115 if (!in_free_unref_items)
6116 {
6117 list_free_contents(l);
6118 list_free_list(l);
6119 }
6131 } 6120 }
6132 6121
6133 /* 6122 /*
6134 * Allocate a list item. 6123 * Allocate a list item.
6135 * It is not initialized, don't forget to set v_lock. 6124 * It is not initialized, don't forget to set v_lock.
7014 #ifdef FEAT_PYTHON3 7003 #ifdef FEAT_PYTHON3
7015 abort = abort || set_ref_in_python3(copyID); 7004 abort = abort || set_ref_in_python3(copyID);
7016 #endif 7005 #endif
7017 7006
7018 #ifdef FEAT_JOB_CHANNEL 7007 #ifdef FEAT_JOB_CHANNEL
7019 abort = abort || set_ref_in_channel(copyID); 7008 // abort = abort || set_ref_in_channel(copyID);
7020 #endif 7009 #endif
7021 7010
7022 if (!abort) 7011 if (!abort)
7023 { 7012 {
7024 /* 7013 /*
7054 7043
7055 return did_free; 7044 return did_free;
7056 } 7045 }
7057 7046
7058 /* 7047 /*
7059 * Free lists, dictionaries and jobs that are no longer referenced. 7048 * Free lists, dictionaries, channels and jobs that are no longer referenced.
7060 */ 7049 */
7061 static int 7050 static int
7062 free_unref_items(int copyID) 7051 free_unref_items(int copyID)
7063 { 7052 {
7064 dict_T *dd, *dd_next; 7053 dict_T *dd, *dd_next;
7065 list_T *ll, *ll_next; 7054 list_T *ll, *ll_next;
7066 int did_free = FALSE; 7055 int did_free = FALSE;
7067 7056
7057 /* Let all "free" functions know that we are here. This means no
7058 * dictionaries, lists, channels or jobs are to be freed, because we will
7059 * do that here. */
7060 in_free_unref_items = TRUE;
7061
7062 /*
7063 * PASS 1: free the contents of the items. We don't free the items
7064 * themselves yet, so that it is possible to decrement refcount counters
7065 */
7066
7068 /* 7067 /*
7069 * Go through the list of dicts and free items without the copyID. 7068 * Go through the list of dicts and free items without the copyID.
7070 */ 7069 */
7071 for (dd = first_dict; dd != NULL; ) 7070 for (dd = first_dict; dd != NULL; dd = dd->dv_used_next)
7072 {
7073 dd_next = dd->dv_used_next;
7074 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) 7071 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
7075 { 7072 {
7076 /* Free the Dictionary and ordinary items it contains, but don't 7073 /* Free the Dictionary and ordinary items it contains, but don't
7077 * recurse into Lists and Dictionaries, they will be in the list 7074 * recurse into Lists and Dictionaries, they will be in the list
7078 * of dicts or list of lists. */ 7075 * of dicts or list of lists. */
7079 dict_free(dd, FALSE); 7076 dict_free_contents(dd);
7080 did_free = TRUE; 7077 did_free = TRUE;
7081 } 7078 }
7082 dd = dd_next;
7083 }
7084 7079
7085 /* 7080 /*
7086 * Go through the list of lists and free items without the copyID. 7081 * Go through the list of lists and free items without the copyID.
7087 * But don't free a list that has a watcher (used in a for loop), these 7082 * But don't free a list that has a watcher (used in a for loop), these
7088 * are not referenced anywhere. 7083 * are not referenced anywhere.
7089 */ 7084 */
7090 for (ll = first_list; ll != NULL; ) 7085 for (ll = first_list; ll != NULL; ll = ll->lv_used_next)
7086 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
7087 && ll->lv_watch == NULL)
7088 {
7089 /* Free the List and ordinary items it contains, but don't recurse
7090 * into Lists and Dictionaries, they will be in the list of dicts
7091 * or list of lists. */
7092 list_free_contents(ll);
7093 did_free = TRUE;
7094 }
7095
7096 #ifdef FEAT_JOB_CHANNEL
7097 /* Go through the list of jobs and free items without the copyID. This
7098 * must happen before doing channels, because jobs refer to channels, but
7099 * the reference from the channel to the job isn't tracked. */
7100 did_free |= free_unused_jobs_contents(copyID, COPYID_MASK);
7101
7102 /* Go through the list of channels and free items without the copyID. */
7103 did_free |= free_unused_channels_contents(copyID, COPYID_MASK);
7104 #endif
7105
7106 /*
7107 * PASS 2: free the items themselves.
7108 */
7109 for (dd = first_dict; dd != NULL; dd = dd_next)
7110 {
7111 dd_next = dd->dv_used_next;
7112 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
7113 dict_free_dict(dd);
7114 }
7115
7116 for (ll = first_list; ll != NULL; ll = ll_next)
7091 { 7117 {
7092 ll_next = ll->lv_used_next; 7118 ll_next = ll->lv_used_next;
7093 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) 7119 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
7094 && ll->lv_watch == NULL) 7120 && ll->lv_watch == NULL)
7095 { 7121 {
7096 /* Free the List and ordinary items it contains, but don't recurse 7122 /* Free the List and ordinary items it contains, but don't recurse
7097 * into Lists and Dictionaries, they will be in the list of dicts 7123 * into Lists and Dictionaries, they will be in the list of dicts
7098 * or list of lists. */ 7124 * or list of lists. */
7099 list_free(ll, FALSE); 7125 list_free_list(ll);
7100 did_free = TRUE; 7126 }
7101 } 7127 }
7102 ll = ll_next; 7128
7103 } 7129 #ifdef FEAT_JOB_CHANNEL
7130 /* Go through the list of jobs and free items without the copyID. This
7131 * must happen before doing channels, because jobs refer to channels, but
7132 * the reference from the channel to the job isn't tracked. */
7133 free_unused_jobs(copyID, COPYID_MASK);
7134
7135 /* Go through the list of channels and free items without the copyID. */
7136 free_unused_channels(copyID, COPYID_MASK);
7137 #endif
7138
7139 in_free_unref_items = FALSE;
7104 7140
7105 return did_free; 7141 return did_free;
7106 } 7142 }
7107 7143
7108 /* 7144 /*
7202 typval_T *tv, 7238 typval_T *tv,
7203 int copyID, 7239 int copyID,
7204 ht_stack_T **ht_stack, 7240 ht_stack_T **ht_stack,
7205 list_stack_T **list_stack) 7241 list_stack_T **list_stack)
7206 { 7242 {
7207 dict_T *dd;
7208 list_T *ll;
7209 int abort = FALSE; 7243 int abort = FALSE;
7210 7244
7211 if (tv->v_type == VAR_DICT || tv->v_type == VAR_PARTIAL) 7245 if (tv->v_type == VAR_DICT)
7212 { 7246 {
7213 if (tv->v_type == VAR_DICT) 7247 dict_T *dd = tv->vval.v_dict;
7214 dd = tv->vval.v_dict; 7248
7215 else if (tv->vval.v_partial != NULL)
7216 dd = tv->vval.v_partial->pt_dict;
7217 else
7218 dd = NULL;
7219 if (dd != NULL && dd->dv_copyID != copyID) 7249 if (dd != NULL && dd->dv_copyID != copyID)
7220 { 7250 {
7221 /* Didn't see this dict yet. */ 7251 /* Didn't see this dict yet. */
7222 dd->dv_copyID = copyID; 7252 dd->dv_copyID = copyID;
7223 if (ht_stack == NULL) 7253 if (ht_stack == NULL)
7235 newitem->prev = *ht_stack; 7265 newitem->prev = *ht_stack;
7236 *ht_stack = newitem; 7266 *ht_stack = newitem;
7237 } 7267 }
7238 } 7268 }
7239 } 7269 }
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 abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
7248 ht_stack, list_stack);
7249 }
7250 } 7270 }
7251 else if (tv->v_type == VAR_LIST) 7271 else if (tv->v_type == VAR_LIST)
7252 { 7272 {
7253 ll = tv->vval.v_list; 7273 list_T *ll = tv->vval.v_list;
7274
7254 if (ll != NULL && ll->lv_copyID != copyID) 7275 if (ll != NULL && ll->lv_copyID != copyID)
7255 { 7276 {
7256 /* Didn't see this list yet. */ 7277 /* Didn't see this list yet. */
7257 ll->lv_copyID = copyID; 7278 ll->lv_copyID = copyID;
7258 if (list_stack == NULL) 7279 if (list_stack == NULL)
7272 *list_stack = newitem; 7293 *list_stack = newitem;
7273 } 7294 }
7274 } 7295 }
7275 } 7296 }
7276 } 7297 }
7298 else if (tv->v_type == VAR_PARTIAL)
7299 {
7300 partial_T *pt = tv->vval.v_partial;
7301 int i;
7302
7303 /* A partial does not have a copyID, because it cannot contain itself.
7304 */
7305 if (pt != NULL)
7306 {
7307 if (pt->pt_dict != NULL)
7308 {
7309 typval_T dtv;
7310
7311 dtv.v_type = VAR_DICT;
7312 dtv.vval.v_dict = pt->pt_dict;
7313 set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
7314 }
7315
7316 for (i = 0; i < pt->pt_argc; ++i)
7317 abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
7318 ht_stack, list_stack);
7319 }
7320 }
7321 #ifdef FEAT_JOB_CHANNEL
7322 else if (tv->v_type == VAR_JOB)
7323 {
7324 job_T *job = tv->vval.v_job;
7325 typval_T dtv;
7326
7327 if (job != NULL && job->jv_copyID != copyID)
7328 {
7329 if (job->jv_channel != NULL)
7330 {
7331 dtv.v_type = VAR_CHANNEL;
7332 dtv.vval.v_channel = job->jv_channel;
7333 set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
7334 }
7335 if (job->jv_exit_partial != NULL)
7336 {
7337 dtv.v_type = VAR_PARTIAL;
7338 dtv.vval.v_partial = job->jv_exit_partial;
7339 set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
7340 }
7341 }
7342 }
7343 else if (tv->v_type == VAR_CHANNEL)
7344 {
7345 channel_T *ch =tv->vval.v_channel;
7346 int part;
7347 typval_T dtv;
7348 jsonq_T *jq;
7349 cbq_T *cq;
7350
7351 if (ch != NULL && ch->ch_copyID != copyID)
7352 {
7353 for (part = PART_SOCK; part <= PART_IN; ++part)
7354 {
7355 for (jq = ch->ch_part[part].ch_json_head.jq_next; jq != NULL;
7356 jq = jq->jq_next)
7357 set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack);
7358 for (cq = ch->ch_part[part].ch_cb_head.cq_next; cq != NULL;
7359 cq = cq->cq_next)
7360 if (cq->cq_partial != NULL)
7361 {
7362 dtv.v_type = VAR_PARTIAL;
7363 dtv.vval.v_partial = cq->cq_partial;
7364 set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
7365 }
7366 if (ch->ch_part[part].ch_partial != NULL)
7367 {
7368 dtv.v_type = VAR_PARTIAL;
7369 dtv.vval.v_partial = ch->ch_part[part].ch_partial;
7370 set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
7371 }
7372 }
7373 if (ch->ch_partial != NULL)
7374 {
7375 dtv.v_type = VAR_PARTIAL;
7376 dtv.vval.v_partial = ch->ch_partial;
7377 set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
7378 }
7379 if (ch->ch_close_partial != NULL)
7380 {
7381 dtv.v_type = VAR_PARTIAL;
7382 dtv.vval.v_partial = ch->ch_close_partial;
7383 set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
7384 }
7385 }
7386 }
7387 #endif
7277 return abort; 7388 return abort;
7278 } 7389 }
7279 7390
7280 /* 7391 /*
7281 * Allocate an empty header for a dictionary. 7392 * Allocate an empty header for a dictionary.
7330 */ 7441 */
7331 void 7442 void
7332 dict_unref(dict_T *d) 7443 dict_unref(dict_T *d)
7333 { 7444 {
7334 if (d != NULL && --d->dv_refcount <= 0) 7445 if (d != NULL && --d->dv_refcount <= 0)
7335 dict_free(d, TRUE); 7446 dict_free(d);
7336 } 7447 }
7337 7448
7338 /* 7449 /*
7339 * Free a Dictionary, including all non-container items it contains. 7450 * Free a Dictionary, including all non-container items it contains.
7340 * Ignores the reference count. 7451 * Ignores the reference count.
7341 */ 7452 */
7342 void 7453 static void
7343 dict_free( 7454 dict_free_contents(dict_T *d)
7344 dict_T *d,
7345 int recurse) /* Free Lists and Dictionaries recursively. */
7346 { 7455 {
7347 int todo; 7456 int todo;
7348 hashitem_T *hi; 7457 hashitem_T *hi;
7349 dictitem_T *di; 7458 dictitem_T *di;
7350 7459
7460 /* Lock the hashtab, we don't want it to resize while freeing items. */
7461 hash_lock(&d->dv_hashtab);
7462 todo = (int)d->dv_hashtab.ht_used;
7463 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7464 {
7465 if (!HASHITEM_EMPTY(hi))
7466 {
7467 /* Remove the item before deleting it, just in case there is
7468 * something recursive causing trouble. */
7469 di = HI2DI(hi);
7470 hash_remove(&d->dv_hashtab, hi);
7471 clear_tv(&di->di_tv);
7472 vim_free(di);
7473 --todo;
7474 }
7475 }
7476 hash_clear(&d->dv_hashtab);
7477 }
7478
7479 static void
7480 dict_free_dict(dict_T *d)
7481 {
7351 /* Remove the dict from the list of dicts for garbage collection. */ 7482 /* Remove the dict from the list of dicts for garbage collection. */
7352 if (d->dv_used_prev == NULL) 7483 if (d->dv_used_prev == NULL)
7353 first_dict = d->dv_used_next; 7484 first_dict = d->dv_used_next;
7354 else 7485 else
7355 d->dv_used_prev->dv_used_next = d->dv_used_next; 7486 d->dv_used_prev->dv_used_next = d->dv_used_next;
7356 if (d->dv_used_next != NULL) 7487 if (d->dv_used_next != NULL)
7357 d->dv_used_next->dv_used_prev = d->dv_used_prev; 7488 d->dv_used_next->dv_used_prev = d->dv_used_prev;
7358
7359 /* Lock the hashtab, we don't want it to resize while freeing items. */
7360 hash_lock(&d->dv_hashtab);
7361 todo = (int)d->dv_hashtab.ht_used;
7362 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7363 {
7364 if (!HASHITEM_EMPTY(hi))
7365 {
7366 /* Remove the item before deleting it, just in case there is
7367 * something recursive causing trouble. */
7368 di = HI2DI(hi);
7369 hash_remove(&d->dv_hashtab, hi);
7370 if (recurse)
7371 clear_tv(&di->di_tv);
7372 else
7373 clear_tv_no_recurse(&di->di_tv);
7374 vim_free(di);
7375 --todo;
7376 }
7377 }
7378 hash_clear(&d->dv_hashtab);
7379 vim_free(d); 7489 vim_free(d);
7490 }
7491
7492 void
7493 dict_free(dict_T *d)
7494 {
7495 if (!in_free_unref_items)
7496 {
7497 dict_free_contents(d);
7498 dict_free_dict(d);
7499 }
7380 } 7500 }
7381 7501
7382 /* 7502 /*
7383 * Allocate a Dictionary item. 7503 * Allocate a Dictionary item.
7384 * The "key" is copied to the new item. 7504 * The "key" is copied to the new item.
7825 if (**arg != '}') 7945 if (**arg != '}')
7826 { 7946 {
7827 EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg); 7947 EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg);
7828 failret: 7948 failret:
7829 if (evaluate) 7949 if (evaluate)
7830 dict_free(d, TRUE); 7950 dict_free(d);
7831 return FAIL; 7951 return FAIL;
7832 } 7952 }
7833 7953
7834 *arg = skipwhite(*arg + 1); 7954 *arg = skipwhite(*arg + 1);
7835 if (evaluate) 7955 if (evaluate)
7839 ++d->dv_refcount; 7959 ++d->dv_refcount;
7840 } 7960 }
7841 7961
7842 return OK; 7962 return OK;
7843 } 7963 }
7844
7845 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7846 #endif
7847 7964
7848 static char * 7965 static char *
7849 get_var_special_name(int nr) 7966 get_var_special_name(int nr)
7850 { 7967 {
7851 switch (nr) 7968 switch (nr)
15389 || list_append_number(rettv->vval.v_list, 15506 || list_append_number(rettv->vval.v_list,
15390 (varnumber_T)-1) == FAIL 15507 (varnumber_T)-1) == FAIL
15391 || list_append_number(rettv->vval.v_list, 15508 || list_append_number(rettv->vval.v_list,
15392 (varnumber_T)-1) == FAIL)) 15509 (varnumber_T)-1) == FAIL))
15393 { 15510 {
15394 list_free(rettv->vval.v_list, TRUE); 15511 list_free(rettv->vval.v_list);
15395 rettv->vval.v_list = NULL; 15512 rettv->vval.v_list = NULL;
15396 goto theend; 15513 goto theend;
15397 } 15514 }
15398 } 15515 }
15399 else if (type == 2) 15516 else if (type == 2)
16486 --cnt; 16603 --cnt;
16487 } 16604 }
16488 16605
16489 if (failed) 16606 if (failed)
16490 { 16607 {
16491 list_free(rettv->vval.v_list, TRUE); 16608 list_free(rettv->vval.v_list);
16492 /* readfile doc says an empty list is returned on error */ 16609 /* readfile doc says an empty list is returned on error */
16493 rettv->vval.v_list = list_alloc(); 16610 rettv->vval.v_list = list_alloc();
16494 } 16611 }
16495 16612
16496 vim_free(prev); 16613 vim_free(prev);
20068 vim_free(infile); 20185 vim_free(infile);
20069 } 20186 }
20070 if (res != NULL) 20187 if (res != NULL)
20071 vim_free(res); 20188 vim_free(res);
20072 if (list != NULL) 20189 if (list != NULL)
20073 list_free(list, TRUE); 20190 list_free(list);
20074 } 20191 }
20075 20192
20076 /* 20193 /*
20077 * "system()" function 20194 * "system()" function
20078 */ 20195 */