Skip to content

Commit 8a1841f

Browse files
committed
Don't double-finalize immortal objects.
1 parent a855d8d commit 8a1841f

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

Include/internal/pycore_interp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ typedef struct _rare_events {
9090
typedef struct _Py_immortal {
9191
PyObject *object;
9292
int gc_tracked;
93+
int finalized;
9394
} _Py_immortal;
9495

9596

Objects/object.c

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -523,21 +523,57 @@ _PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
523523
return op;
524524
}
525525

526+
Py_ssize_t _Py_FindUserDefinedImmortal(PyObject *op);
527+
528+
int
529+
_PyObject_IsFinalized(PyObject *op, _Py_immortal **immortal_ptr)
530+
{
531+
// TODO: Make this thread safe
532+
if (_PyType_IS_GC(Py_TYPE(op)))
533+
{
534+
return _PyGC_FINALIZED(op);
535+
}
536+
else {
537+
Py_ssize_t index = _Py_FindUserDefinedImmortal(op);
538+
if (index == -1)
539+
{
540+
return 0;
541+
}
542+
PyInterpreterState *interp = _PyInterpreterState_GET();
543+
_Py_immortal *immortal = interp->runtime_immortals.values[index];
544+
*immortal_ptr = immortal;
545+
return immortal->finalized;
546+
}
547+
}
548+
549+
void
550+
_PyObject_SetFinalized(PyObject *op, _Py_immortal *immortal)
551+
{
552+
if (immortal == NULL)
553+
{
554+
assert(_PyType_IS_GC(Py_TYPE(op)));
555+
_PyGC_SET_FINALIZED(op);
556+
}
557+
else {
558+
immortal->finalized = 1;
559+
}
560+
}
561+
526562
void
527563
PyObject_CallFinalizer(PyObject *self)
528564
{
529565
PyTypeObject *tp = Py_TYPE(self);
530566

531567
if (tp->tp_finalize == NULL)
532568
return;
569+
570+
_Py_immortal *immortal = NULL;
533571
/* tp_finalize should only be called once. */
534-
if (_PyType_IS_GC(tp) && _PyGC_FINALIZED(self))
572+
if (_PyObject_IsFinalized(self, &immortal))
535573
return;
536574

537575
tp->tp_finalize(self);
538-
if (_PyType_IS_GC(tp)) {
539-
_PyGC_SET_FINALIZED(self);
540-
}
576+
_PyObject_SetFinalized(self, immortal);
541577
}
542578

543579
int
@@ -2482,12 +2518,14 @@ _Py_NewReferenceNoTotal(PyObject *op)
24822518
Py_ssize_t
24832519
_Py_FindUserDefinedImmortal(PyObject *op)
24842520
{
2485-
if (!_Py_IsImmortal(op))
2521+
if (!_Py_IsImmortal(op)) {
24862522
return -1;
2523+
}
24872524

24882525
PyInterpreterState *interp = _PyInterpreterState_GET();
2489-
if (interp->runtime_immortals.values == NULL)
2526+
if (interp->runtime_immortals.values == NULL) {
24902527
return -1;
2528+
}
24912529

24922530
for (Py_ssize_t i = 0; i < interp->runtime_immortals.capacity; ++i)
24932531
{

0 commit comments

Comments
 (0)