Skip to content

Commit 5eb8bff

Browse files
authored
bpo-38631: Replace Py_FatalError() with _PyObject_ASSERT_FAILED_MSG() (GH-18258)
Replace Py_FatalError() with _PyObject_ASSERT_FAILED_MSG() in object.c and typeobject.c to also dump the involved Python object on a fatal error. It should ease debug when such fatal error occurs. If the double linked list is inconsistent, _Py_ForgetReference() no longer dumps previous and next objects in the fatal error, it now only dumps the current object. It ensures that the error message is displayed even if dumping the object does crash Python. Enhance _Py_ForgetReference() error messages; _PyObject_ASSERT_FAILED_MSG() logs the "_Py_ForgetReference" function name.
1 parent 188bb5b commit 5eb8bff

File tree

2 files changed

+32
-32
lines changed

2 files changed

+32
-32
lines changed

Objects/object.c

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -315,30 +315,30 @@ PyObject_CallFinalizer(PyObject *self)
315315
int
316316
PyObject_CallFinalizerFromDealloc(PyObject *self)
317317
{
318-
Py_ssize_t refcnt;
319-
320-
/* Temporarily resurrect the object. */
321318
if (self->ob_refcnt != 0) {
322-
Py_FatalError("PyObject_CallFinalizerFromDealloc called on "
323-
"object with a non-zero refcount");
319+
_PyObject_ASSERT_FAILED_MSG(self,
320+
"PyObject_CallFinalizerFromDealloc called "
321+
"on object with a non-zero refcount");
324322
}
323+
324+
/* Temporarily resurrect the object. */
325325
self->ob_refcnt = 1;
326326

327327
PyObject_CallFinalizer(self);
328328

329-
/* Undo the temporary resurrection; can't use DECREF here, it would
330-
* cause a recursive call.
331-
*/
332329
_PyObject_ASSERT_WITH_MSG(self,
333330
self->ob_refcnt > 0,
334331
"refcount is too small");
335-
if (--self->ob_refcnt == 0)
332+
333+
/* Undo the temporary resurrection; can't use DECREF here, it would
334+
* cause a recursive call. */
335+
if (--self->ob_refcnt == 0) {
336336
return 0; /* this is the normal path out */
337+
}
337338

338339
/* tp_finalize resurrected it! Make it look like the original Py_DECREF
339-
* never happened.
340-
*/
341-
refcnt = self->ob_refcnt;
340+
* never happened. */
341+
Py_ssize_t refcnt = self->ob_refcnt;
342342
_Py_NewReference(self);
343343
self->ob_refcnt = refcnt;
344344

@@ -352,8 +352,7 @@ PyObject_CallFinalizerFromDealloc(PyObject *self)
352352
* chain, so no more to do there.
353353
* If COUNT_ALLOCS, the original decref bumped tp_frees, and
354354
* _Py_NewReference bumped tp_allocs: both of those need to be
355-
* undone.
356-
*/
355+
* undone. */
357356
#ifdef COUNT_ALLOCS
358357
--Py_TYPE(self)->tp_frees;
359358
--Py_TYPE(self)->tp_allocs;
@@ -1938,29 +1937,30 @@ _Py_NewReference(PyObject *op)
19381937
void
19391938
_Py_ForgetReference(PyObject *op)
19401939
{
1941-
#ifdef SLOW_UNREF_CHECK
1942-
PyObject *p;
1943-
#endif
1944-
if (op->ob_refcnt < 0)
1945-
Py_FatalError("UNREF negative refcnt");
1940+
if (op->ob_refcnt < 0) {
1941+
_PyObject_ASSERT_FAILED_MSG(op, "negative refcnt");
1942+
}
1943+
19461944
if (op == &refchain ||
1947-
op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) {
1948-
fprintf(stderr, "* ob\n");
1949-
_PyObject_Dump(op);
1950-
fprintf(stderr, "* op->_ob_prev->_ob_next\n");
1951-
_PyObject_Dump(op->_ob_prev->_ob_next);
1952-
fprintf(stderr, "* op->_ob_next->_ob_prev\n");
1953-
_PyObject_Dump(op->_ob_next->_ob_prev);
1954-
Py_FatalError("UNREF invalid object");
1945+
op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op)
1946+
{
1947+
_PyObject_ASSERT_FAILED_MSG(op, "invalid object chain");
19551948
}
1949+
19561950
#ifdef SLOW_UNREF_CHECK
1951+
PyObject *p;
19571952
for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) {
1958-
if (p == op)
1953+
if (p == op) {
19591954
break;
1955+
}
1956+
}
1957+
if (p == &refchain) {
1958+
/* Not found */
1959+
_PyObject_ASSERT_FAILED_MSG(op,
1960+
"object not found in the objects list");
19601961
}
1961-
if (p == &refchain) /* Not found */
1962-
Py_FatalError("UNREF unknown object");
19631962
#endif
1963+
19641964
op->_ob_next->_ob_prev = op->_ob_prev;
19651965
op->_ob_prev->_ob_next = op->_ob_next;
19661966
op->_ob_next = op->_ob_prev = NULL;

Objects/typeobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3570,9 +3570,9 @@ type_traverse(PyTypeObject *type, visitproc visit, void *arg)
35703570
for heaptypes. */
35713571
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
35723572
char msg[200];
3573-
sprintf(msg, "type_traverse() called for non-heap type '%.100s'",
3573+
sprintf(msg, "type_traverse() called on non-heap type '%.100s'",
35743574
type->tp_name);
3575-
Py_FatalError(msg);
3575+
_PyObject_ASSERT_FAILED_MSG((PyObject *)type, msg);
35763576
}
35773577

35783578
Py_VISIT(type->tp_dict);

0 commit comments

Comments
 (0)