4 From: Bram Moolenaar <Bram@moolenaar.net>
6 Content-Type: text/plain; charset=ISO-8859-1
7 Content-Transfer-Encoding: 8bit
11 Problem: Crash when garbage collecting list or dict with loop.
12 Solution: Don't use DEL_REFCOUNT but don't recurse into Lists and
13 Dictionaries when freeing them in the garbage collector.
14 Also add allocated Dictionaries to the list of Dictionaries to
16 Files: src/eval.c, src/proto/eval.pro, src/tag.c
19 *** ../vim-7.0.134/src/eval.c Sun Oct 15 15:10:08 2006
20 --- src/eval.c Sun Oct 15 22:30:09 2006
23 #define FC_RANGE 2 /* function accepts range */
24 #define FC_DICT 4 /* Dict function, uses "self" */
26 - #define DEL_REFCOUNT 999999 /* list/dict is being deleted */
29 * All user-defined functions are found in this hashtable.
34 static void set_ref_in_list __ARGS((list_T *l, int copyID));
35 static void set_ref_in_item __ARGS((typval_T *tv, int copyID));
36 static void dict_unref __ARGS((dict_T *d));
37 ! static void dict_free __ARGS((dict_T *d));
38 static dictitem_T *dictitem_alloc __ARGS((char_u *key));
39 static dictitem_T *dictitem_copy __ARGS((dictitem_T *org));
40 static void dictitem_remove __ARGS((dict_T *dict, dictitem_T *item));
42 static void set_ref_in_list __ARGS((list_T *l, int copyID));
43 static void set_ref_in_item __ARGS((typval_T *tv, int copyID));
44 static void dict_unref __ARGS((dict_T *d));
45 ! static void dict_free __ARGS((dict_T *d, int recurse));
46 static dictitem_T *dictitem_alloc __ARGS((char_u *key));
47 static dictitem_T *dictitem_copy __ARGS((dictitem_T *org));
48 static void dictitem_remove __ARGS((dict_T *dict, dictitem_T *item));
52 if (list_append_tv(l, &item->li_tv) == FAIL)
60 if (list_append_tv(l, &item->li_tv) == FAIL)
68 EMSG2(_("E697: Missing end of List ']': %s"), *arg);
76 EMSG2(_("E697: Missing end of List ']': %s"), *arg);
88 ! if (l != NULL && l->lv_refcount != DEL_REFCOUNT && --l->lv_refcount <= 0)
97 ! if (l != NULL && --l->lv_refcount <= 0)
104 * Ignores the reference count.
112 - /* Avoid that recursive reference to the list frees us again. */
113 - l->lv_refcount = DEL_REFCOUNT;
115 /* Remove the list from the list of lists for garbage collection. */
116 if (l->lv_used_prev == NULL)
117 first_list = l->lv_used_next;
119 * Ignores the reference count.
122 ! list_free(l, recurse)
124 ! int recurse; /* Free Lists and Dictionaries recursively. */
128 /* Remove the list from the list of lists for garbage collection. */
129 if (l->lv_used_prev == NULL)
130 first_list = l->lv_used_next;
134 /* Remove the item before deleting it. */
135 l->lv_first = item->li_next;
136 ! listitem_free(item);
142 /* Remove the item before deleting it. */
143 l->lv_first = item->li_next;
144 ! if (recurse || (item->li_tv.v_type != VAR_LIST
145 ! && item->li_tv.v_type != VAR_DICT))
146 ! clear_tv(&item->li_tv);
153 for (dd = first_dict; dd != NULL; )
154 if (dd->dv_copyID != copyID)
159 /* restart, next dict may also have been freed */
161 for (dd = first_dict; dd != NULL; )
162 if (dd->dv_copyID != copyID)
164 ! /* Free the Dictionary and ordinary items it contains, but don't
165 ! * recurse into Lists and Dictionaries, they will be in the list
166 ! * of dicts or list of lists. */
167 ! dict_free(dd, FALSE);
170 /* restart, next dict may also have been freed */
173 for (ll = first_list; ll != NULL; )
174 if (ll->lv_copyID != copyID && ll->lv_watch == NULL)
179 /* restart, next list may also have been freed */
181 for (ll = first_list; ll != NULL; )
182 if (ll->lv_copyID != copyID && ll->lv_watch == NULL)
184 ! /* Free the List and ordinary items it contains, but don't recurse
185 ! * into Lists and Dictionaries, they will be in the list of dicts
186 ! * or list of lists. */
187 ! list_free(ll, FALSE);
190 /* restart, next list may also have been freed */
193 d = (dict_T *)alloc(sizeof(dict_T));
196 ! /* Add the list to the hashtable for garbage collection. */
197 if (first_dict != NULL)
198 first_dict->dv_used_prev = d;
199 d->dv_used_next = first_dict;
200 d->dv_used_prev = NULL;
202 hash_init(&d->dv_hashtab);
205 d = (dict_T *)alloc(sizeof(dict_T));
208 ! /* Add the list to the list of dicts for garbage collection. */
209 if (first_dict != NULL)
210 first_dict->dv_used_prev = d;
211 d->dv_used_next = first_dict;
212 d->dv_used_prev = NULL;
215 hash_init(&d->dv_hashtab);
222 ! if (d != NULL && d->dv_refcount != DEL_REFCOUNT && --d->dv_refcount <= 0)
231 ! if (d != NULL && --d->dv_refcount <= 0)
232 ! dict_free(d, TRUE);
238 * Ignores the reference count.
248 - /* Avoid that recursive reference to the dict frees us again. */
249 - d->dv_refcount = DEL_REFCOUNT;
251 /* Remove the dict from the list of dicts for garbage collection. */
252 if (d->dv_used_prev == NULL)
253 first_dict = d->dv_used_next;
255 * Ignores the reference count.
258 ! dict_free(d, recurse)
260 ! int recurse; /* Free Lists and Dictionaries recursively. */
266 /* Remove the dict from the list of dicts for garbage collection. */
267 if (d->dv_used_prev == NULL)
268 first_dict = d->dv_used_next;
271 * something recursive causing trouble. */
273 hash_remove(&d->dv_hashtab, hi);
279 * something recursive causing trouble. */
281 hash_remove(&d->dv_hashtab, hi);
282 ! if (recurse || (di->di_tv.v_type != VAR_LIST
283 ! && di->di_tv.v_type != VAR_DICT))
284 ! clear_tv(&di->di_tv);
291 EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg);
299 EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg);
302 ! dict_free(d, TRUE);
306 *** ../vim-7.0.134/src/proto/eval.pro Fri Mar 24 23:16:28 2006
307 --- src/proto/eval.pro Sun Oct 15 22:08:11 2006
310 extern char_u *get_user_var_name __ARGS((expand_T *xp, int idx));
311 extern list_T *list_alloc __ARGS((void));
312 extern void list_unref __ARGS((list_T *l));
313 ! extern void list_free __ARGS((list_T *l));
314 extern dictitem_T *dict_lookup __ARGS((hashitem_T *hi));
315 extern int list_append_dict __ARGS((list_T *list, dict_T *dict));
316 extern int garbage_collect __ARGS((void));
318 extern char_u *get_user_var_name __ARGS((expand_T *xp, int idx));
319 extern list_T *list_alloc __ARGS((void));
320 extern void list_unref __ARGS((list_T *l));
321 ! extern void list_free __ARGS((list_T *l, int recurse));
322 extern dictitem_T *dict_lookup __ARGS((hashitem_T *hi));
323 extern int list_append_dict __ARGS((list_T *list, dict_T *dict));
324 extern int garbage_collect __ARGS((void));
325 *** ../vim-7.0.134/src/tag.c Sun Sep 10 13:56:06 2006
326 --- src/tag.c Sun Oct 15 21:44:56 2006
330 set_errorlist(curwin, list, ' ');
334 cur_match = 0; /* Jump to the first tag */
338 set_errorlist(curwin, list, ' ');
340 ! list_free(list, TRUE);
342 cur_match = 0; /* Jump to the first tag */
344 *** ../vim-7.0.134/src/version.c Sun Oct 15 15:10:08 2006
345 --- src/version.c Sun Oct 15 22:01:53 2006
349 { /* Add new patch number below this line */
355 Well, you come from nothing, you go back to nothing... What have you
357 -- Monty Python: The life of Brian
359 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
360 /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
361 \\\ download, build and distribute -- http://www.A-A-P.org ///
362 \\\ help me help AIDS victims -- http://ICCF-Holland.org ///