mirror of
https://github.com/python/cpython.git
synced 2025-11-02 19:12:55 +00:00
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).
This commit is contained in:
parent
a9cab433bb
commit
c4653c9bf1
1 changed files with 23 additions and 4 deletions
|
|
@ -654,6 +654,7 @@ handle_legacy_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
|
||||||
{
|
{
|
||||||
PyGC_Head *gc = finalizers->gc.gc_next;
|
PyGC_Head *gc = finalizers->gc.gc_next;
|
||||||
|
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
if (_PyRuntime.gc.garbage == NULL) {
|
if (_PyRuntime.gc.garbage == NULL) {
|
||||||
_PyRuntime.gc.garbage = PyList_New(0);
|
_PyRuntime.gc.garbage = PyList_New(0);
|
||||||
if (_PyRuntime.gc.garbage == NULL)
|
if (_PyRuntime.gc.garbage == NULL)
|
||||||
|
|
@ -663,8 +664,10 @@ handle_legacy_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
|
||||||
PyObject *op = FROM_GC(gc);
|
PyObject *op = FROM_GC(gc);
|
||||||
|
|
||||||
if ((_PyRuntime.gc.debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) {
|
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;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -701,6 +704,7 @@ finalize_garbage(PyGC_Head *collectable)
|
||||||
_PyGCHead_SET_FINALIZED(gc, 1);
|
_PyGCHead_SET_FINALIZED(gc, 1);
|
||||||
Py_INCREF(op);
|
Py_INCREF(op);
|
||||||
finalize(op);
|
finalize(op);
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
Py_DECREF(op);
|
Py_DECREF(op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -748,17 +752,26 @@ delete_garbage(PyGC_Head *collectable, PyGC_Head *old)
|
||||||
{
|
{
|
||||||
inquiry clear;
|
inquiry clear;
|
||||||
|
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
while (!gc_list_is_empty(collectable)) {
|
while (!gc_list_is_empty(collectable)) {
|
||||||
PyGC_Head *gc = collectable->gc.gc_next;
|
PyGC_Head *gc = collectable->gc.gc_next;
|
||||||
PyObject *op = FROM_GC(gc);
|
PyObject *op = FROM_GC(gc);
|
||||||
|
|
||||||
if (_PyRuntime.gc.debug & DEBUG_SAVEALL) {
|
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 {
|
else {
|
||||||
if ((clear = Py_TYPE(op)->tp_clear) != NULL) {
|
if ((clear = Py_TYPE(op)->tp_clear) != NULL) {
|
||||||
Py_INCREF(op);
|
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);
|
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())
|
if (PyDTrace_GC_DONE_ENABLED())
|
||||||
PyDTrace_GC_DONE(n+m);
|
PyDTrace_GC_DONE(n+m);
|
||||||
|
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
return n+m;
|
return n+m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -987,11 +1001,12 @@ invoke_gc_callback(const char *phase, int generation,
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
PyObject *info = NULL;
|
PyObject *info = NULL;
|
||||||
|
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
/* we may get called very early */
|
/* we may get called very early */
|
||||||
if (_PyRuntime.gc.callbacks == NULL)
|
if (_PyRuntime.gc.callbacks == NULL)
|
||||||
return;
|
return;
|
||||||
/* The local variable cannot be rebound, check it for sanity */
|
/* 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) {
|
if (PyList_GET_SIZE(_PyRuntime.gc.callbacks) != 0) {
|
||||||
info = Py_BuildValue("{sisnsn}",
|
info = Py_BuildValue("{sisnsn}",
|
||||||
"generation", generation,
|
"generation", generation,
|
||||||
|
|
@ -1015,6 +1030,7 @@ invoke_gc_callback(const char *phase, int generation,
|
||||||
Py_DECREF(cb);
|
Py_DECREF(cb);
|
||||||
}
|
}
|
||||||
Py_XDECREF(info);
|
Py_XDECREF(info);
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform garbage collection of a generation and invoke
|
/* Perform garbage collection of a generation and invoke
|
||||||
|
|
@ -1024,9 +1040,11 @@ static Py_ssize_t
|
||||||
collect_with_callback(int generation)
|
collect_with_callback(int generation)
|
||||||
{
|
{
|
||||||
Py_ssize_t result, collected, uncollectable;
|
Py_ssize_t result, collected, uncollectable;
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
invoke_gc_callback("start", generation, 0, 0);
|
invoke_gc_callback("start", generation, 0, 0);
|
||||||
result = collect(generation, &collected, &uncollectable, 0);
|
result = collect(generation, &collected, &uncollectable, 0);
|
||||||
invoke_gc_callback("stop", generation, collected, uncollectable);
|
invoke_gc_callback("stop", generation, collected, uncollectable);
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1592,6 +1610,7 @@ _PyGC_CollectNoFail(void)
|
||||||
{
|
{
|
||||||
Py_ssize_t n;
|
Py_ssize_t n;
|
||||||
|
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
/* Ideally, this function is only called on interpreter shutdown,
|
/* Ideally, this function is only called on interpreter shutdown,
|
||||||
and therefore not recursively. Unfortunately, when there are daemon
|
and therefore not recursively. Unfortunately, when there are daemon
|
||||||
threads, a daemon thread can start a cyclic garbage collection
|
threads, a daemon thread can start a cyclic garbage collection
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue