Commit 9044cd67 authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

[2.7] bpo-33622: Fix issues with handling errors in the GC. (GH-7078) (#7096)

* Fixed a leak when the GC fails to add an object with __del__ into
  the gc.garbage list.
* PyGC_Collect() can now be called when an exception is set and
  preserves it.
(cherry picked from commit 301e3cc8)
parent 8cbde8a4
Fixed a leak when the garbage collector fails to add an object with the
``__del__`` method or referenced by it into the :data:`gc.garbage` list.
:c:func:`PyGC_Collect` can now be called when an exception is set and
preserves it.
...@@ -771,10 +771,8 @@ debug_cycle(char *msg, PyObject *op) ...@@ -771,10 +771,8 @@ debug_cycle(char *msg, PyObject *op)
* garbage list (a Python list), else only the objects in finalizers with * garbage list (a Python list), else only the objects in finalizers with
* __del__ methods are appended to garbage. All objects in finalizers are * __del__ methods are appended to garbage. All objects in finalizers are
* merged into the old list regardless. * merged into the old list regardless.
* Returns 0 if all OK, <0 on error (out of memory to grow the garbage list).
* The finalizers list is made empty on a successful return.
*/ */
static int static void
handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old) handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
{ {
PyGC_Head *gc = finalizers->gc.gc_next; PyGC_Head *gc = finalizers->gc.gc_next;
...@@ -789,12 +787,11 @@ handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old) ...@@ -789,12 +787,11 @@ handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) { if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) {
if (PyList_Append(garbage, op) < 0) if (PyList_Append(garbage, op) < 0)
return -1; break;
} }
} }
gc_list_merge(finalizers, old); gc_list_merge(finalizers, old);
return 0;
} }
/* Break reference cycles by clearing the containers involved. This is /* Break reference cycles by clearing the containers involved. This is
...@@ -1012,7 +1009,7 @@ collect(int generation) ...@@ -1012,7 +1009,7 @@ collect(int generation)
* reachable list of garbage. The programmer has to deal with * reachable list of garbage. The programmer has to deal with
* this if they insist on creating this type of structure. * this if they insist on creating this type of structure.
*/ */
(void)handle_finalizers(&finalizers, old); handle_finalizers(&finalizers, old);
/* Clear free list only during the collection of the highest /* Clear free list only during the collection of the highest
* generation */ * generation */
...@@ -1436,8 +1433,11 @@ PyGC_Collect(void) ...@@ -1436,8 +1433,11 @@ PyGC_Collect(void)
if (collecting) if (collecting)
n = 0; /* already collecting, don't do anything */ n = 0; /* already collecting, don't do anything */
else { else {
PyObject *exc, *value, *tb;
collecting = 1; collecting = 1;
PyErr_Fetch(&exc, &value, &tb);
n = collect(NUM_GENERATIONS - 1); n = collect(NUM_GENERATIONS - 1);
PyErr_Restore(exc, value, tb);
collecting = 0; collecting = 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment