From: Serhiy Storchaka Date: Thu, 24 May 2018 20:27:08 +0000 (+0300) Subject: [2.7] bpo-33622: Fix issues with handling errors in the GC. (GH-7078) (#7096) X-Git-Tag: v2.7.16rc1~295 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9044cd675902b438bc500908e410382ff48299d8;p=thirdparty%2FPython%2Fcpython.git [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 301e3cc8a5bc68c5347ab6ac6f83428000d31ab2) --- diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-05-23-20-46-14.bpo-33622.xPucO9.rst b/Misc/NEWS.d/next/Core and Builtins/2018-05-23-20-46-14.bpo-33622.xPucO9.rst new file mode 100644 index 000000000000..e589b4503229 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-05-23-20-46-14.bpo-33622.xPucO9.rst @@ -0,0 +1,4 @@ +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. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 19011c47b5c4..700c1a32b079 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -771,10 +771,8 @@ debug_cycle(char *msg, PyObject *op) * garbage list (a Python list), else only the objects in finalizers with * __del__ methods are appended to garbage. All objects in finalizers are * 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) { PyGC_Head *gc = finalizers->gc.gc_next; @@ -789,12 +787,11 @@ handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old) if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) { if (PyList_Append(garbage, op) < 0) - return -1; + break; } } gc_list_merge(finalizers, old); - return 0; } /* Break reference cycles by clearing the containers involved. This is @@ -1012,7 +1009,7 @@ collect(int generation) * reachable list of garbage. The programmer has to deal with * 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 * generation */ @@ -1436,8 +1433,11 @@ PyGC_Collect(void) if (collecting) n = 0; /* already collecting, don't do anything */ else { + PyObject *exc, *value, *tb; collecting = 1; + PyErr_Fetch(&exc, &value, &tb); n = collect(NUM_GENERATIONS - 1); + PyErr_Restore(exc, value, tb); collecting = 0; }