diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2018-05-24 12:19:29 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-24 12:19:29 (GMT) |
commit | 301e3cc8a5bc68c5347ab6ac6f83428000d31ab2 (patch) | |
tree | 3913f8bed57a749dc1940153c7d0ffc386008982 /Modules | |
parent | 03c0d2e1f272c7c6df5f6066a6abc222ff61073a (diff) | |
download | cpython-301e3cc8a5bc68c5347ab6ac6f83428000d31ab2.zip cpython-301e3cc8a5bc68c5347ab6ac6f83428000d31ab2.tar.gz cpython-301e3cc8a5bc68c5347ab6ac6f83428000d31ab2.tar.bz2 |
bpo-33622: Fix issues with handling errors in the GC. (GH-7078)
* 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.
* Fixed an undefined behavior with comparing a dead pointer with NULL.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/gcmodule.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 09c7356..4d701cb 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -648,10 +648,8 @@ debug_cycle(const 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_legacy_finalizers(PyGC_Head *finalizers, PyGC_Head *old) { PyGC_Head *gc = finalizers->gc.gc_next; @@ -666,12 +664,11 @@ handle_legacy_finalizers(PyGC_Head *finalizers, PyGC_Head *old) if ((_PyRuntime.gc.debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) { if (PyList_Append(_PyRuntime.gc.garbage, op) < 0) - return -1; + break; } } gc_list_merge(finalizers, old); - return 0; } /* Run first-time finalizers (if any) on all the objects in collectable. @@ -945,7 +942,7 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, * reachable list of garbage. The programmer has to deal with * this if they insist on creating this type of structure. */ - (void)handle_legacy_finalizers(&finalizers, old); + handle_legacy_finalizers(&finalizers, old); /* Clear free list only during the collection of the highest * generation */ @@ -1009,9 +1006,12 @@ invoke_gc_callback(const char *phase, int generation, PyObject *r, *cb = PyList_GET_ITEM(_PyRuntime.gc.callbacks, i); Py_INCREF(cb); /* make sure cb doesn't go away */ r = PyObject_CallFunction(cb, "sO", phase, info); - Py_XDECREF(r); - if (r == NULL) + if (r == NULL) { PyErr_WriteUnraisable(cb); + } + else { + Py_DECREF(r); + } Py_DECREF(cb); } Py_XDECREF(info); @@ -1567,8 +1567,11 @@ PyGC_Collect(void) if (_PyRuntime.gc.collecting) n = 0; /* already collecting, don't do anything */ else { + PyObject *exc, *value, *tb; _PyRuntime.gc.collecting = 1; + PyErr_Fetch(&exc, &value, &tb); n = collect_with_callback(NUM_GENERATIONS - 1); + PyErr_Restore(exc, value, tb); _PyRuntime.gc.collecting = 0; } |