summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2018-05-29 15:50:10 (GMT)
committerGitHub <noreply@github.com>2018-05-29 15:50:10 (GMT)
commitc4653c9bf159c3919a50f4ced32eef713e7e764e (patch)
tree4b05be57029bcd2603964a1b54ccd491df7bc44f /Modules
parenta9cab433bbf02f3a1de59d14dc8f583181ffe2d5 (diff)
downloadcpython-c4653c9bf159c3919a50f4ced32eef713e7e764e.zip
cpython-c4653c9bf159c3919a50f4ced32eef713e7e764e.tar.gz
cpython-c4653c9bf159c3919a50f4ced32eef713e7e764e.tar.bz2
bpo-33622: Add checks for exceptions leaks in the garbage collector. (GH-7126)
* Failure in adding to gc.garbage is no longer fatal. * An exception in tp_clear() no longer lead to crash (though tp_clear() should not leave exceptions).
Diffstat (limited to 'Modules')
-rw-r--r--Modules/gcmodule.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 4d701cb..7d23fc2 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -654,6 +654,7 @@ handle_legacy_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
{
PyGC_Head *gc = finalizers->gc.gc_next;
+ assert(!PyErr_Occurred());
if (_PyRuntime.gc.garbage == NULL) {
_PyRuntime.gc.garbage = PyList_New(0);
if (_PyRuntime.gc.garbage == NULL)
@@ -663,8 +664,10 @@ handle_legacy_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
PyObject *op = FROM_GC(gc);
if ((_PyRuntime.gc.debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) {
- if (PyList_Append(_PyRuntime.gc.garbage, op) < 0)
+ if (PyList_Append(_PyRuntime.gc.garbage, op) < 0) {
+ PyErr_Clear();
break;
+ }
}
}
@@ -701,6 +704,7 @@ finalize_garbage(PyGC_Head *collectable)
_PyGCHead_SET_FINALIZED(gc, 1);
Py_INCREF(op);
finalize(op);
+ assert(!PyErr_Occurred());
Py_DECREF(op);
}
}
@@ -748,17 +752,26 @@ delete_garbage(PyGC_Head *collectable, PyGC_Head *old)
{
inquiry clear;
+ assert(!PyErr_Occurred());
while (!gc_list_is_empty(collectable)) {
PyGC_Head *gc = collectable->gc.gc_next;
PyObject *op = FROM_GC(gc);
if (_PyRuntime.gc.debug & DEBUG_SAVEALL) {
- PyList_Append(_PyRuntime.gc.garbage, op);
+ assert(_PyRuntime.gc.garbage != NULL);
+ if (PyList_Append(_PyRuntime.gc.garbage, op) < 0) {
+ PyErr_Clear();
+ }
}
else {
if ((clear = Py_TYPE(op)->tp_clear) != NULL) {
Py_INCREF(op);
- clear(op);
+ (void) clear(op);
+ if (PyErr_Occurred()) {
+ PySys_WriteStderr("Exception ignored in tp_clear of "
+ "%.50s\n", Py_TYPE(op)->tp_name);
+ PyErr_WriteUnraisable(NULL);
+ }
Py_DECREF(op);
}
}
@@ -974,6 +987,7 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
if (PyDTrace_GC_DONE_ENABLED())
PyDTrace_GC_DONE(n+m);
+ assert(!PyErr_Occurred());
return n+m;
}
@@ -987,11 +1001,12 @@ invoke_gc_callback(const char *phase, int generation,
Py_ssize_t i;
PyObject *info = NULL;
+ assert(!PyErr_Occurred());
/* we may get called very early */
if (_PyRuntime.gc.callbacks == NULL)
return;
/* The local variable cannot be rebound, check it for sanity */
- assert(_PyRuntime.gc.callbacks != NULL && PyList_CheckExact(_PyRuntime.gc.callbacks));
+ assert(PyList_CheckExact(_PyRuntime.gc.callbacks));
if (PyList_GET_SIZE(_PyRuntime.gc.callbacks) != 0) {
info = Py_BuildValue("{sisnsn}",
"generation", generation,
@@ -1015,6 +1030,7 @@ invoke_gc_callback(const char *phase, int generation,
Py_DECREF(cb);
}
Py_XDECREF(info);
+ assert(!PyErr_Occurred());
}
/* Perform garbage collection of a generation and invoke
@@ -1024,9 +1040,11 @@ static Py_ssize_t
collect_with_callback(int generation)
{
Py_ssize_t result, collected, uncollectable;
+ assert(!PyErr_Occurred());
invoke_gc_callback("start", generation, 0, 0);
result = collect(generation, &collected, &uncollectable, 0);
invoke_gc_callback("stop", generation, collected, uncollectable);
+ assert(!PyErr_Occurred());
return result;
}
@@ -1592,6 +1610,7 @@ _PyGC_CollectNoFail(void)
{
Py_ssize_t n;
+ assert(!PyErr_Occurred());
/* Ideally, this function is only called on interpreter shutdown,
and therefore not recursively. Unfortunately, when there are daemon
threads, a daemon thread can start a cyclic garbage collection