aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Objects/typeobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/typeobject.c')
-rw-r--r--Objects/typeobject.c74
1 files changed, 2 insertions, 72 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index b28f494962e..bfbd320b1f5 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1120,7 +1120,6 @@ subtype_dealloc(PyObject *self)
{
PyTypeObject *type, *base;
destructor basedealloc;
- PyThreadState *tstate = _PyThreadState_GET();
int has_finalizer;
/* Extract the type; we expect it to be a heap type */
@@ -1174,11 +1173,7 @@ subtype_dealloc(PyObject *self)
/* UnTrack and re-Track around the trashcan macro, alas */
/* See explanation at end of function for full disclosure */
PyObject_GC_UnTrack(self);
- ++_PyRuntime.gc.trash_delete_nesting;
- ++ tstate->trash_delete_nesting;
- Py_TRASHCAN_SAFE_BEGIN(self);
- --_PyRuntime.gc.trash_delete_nesting;
- -- tstate->trash_delete_nesting;
+ Py_TRASHCAN_BEGIN(self, subtype_dealloc);
/* Find the nearest base with a different tp_dealloc */
base = type;
@@ -1271,11 +1266,7 @@ subtype_dealloc(PyObject *self)
Py_DECREF(type);
endlabel:
- ++_PyRuntime.gc.trash_delete_nesting;
- ++ tstate->trash_delete_nesting;
- Py_TRASHCAN_SAFE_END(self);
- --_PyRuntime.gc.trash_delete_nesting;
- -- tstate->trash_delete_nesting;
+ Py_TRASHCAN_END
/* Explanation of the weirdness around the trashcan macros:
@@ -1312,67 +1303,6 @@ subtype_dealloc(PyObject *self)
looks like trash to gc too, and gc also tries to delete self
then. But we're already deleting self. Double deallocation is
a subtle disaster.
-
- Q. Why the bizarre (net-zero) manipulation of
- _PyRuntime.trash_delete_nesting around the trashcan macros?
-
- A. Some base classes (e.g. list) also use the trashcan mechanism.
- The following scenario used to be possible:
-
- - suppose the trashcan level is one below the trashcan limit
-
- - subtype_dealloc() is called
-
- - the trashcan limit is not yet reached, so the trashcan level
- is incremented and the code between trashcan begin and end is
- executed
-
- - this destroys much of the object's contents, including its
- slots and __dict__
-
- - basedealloc() is called; this is really list_dealloc(), or
- some other type which also uses the trashcan macros
-
- - the trashcan limit is now reached, so the object is put on the
- trashcan's to-be-deleted-later list
-
- - basedealloc() returns
-
- - subtype_dealloc() decrefs the object's type
-
- - subtype_dealloc() returns
-
- - later, the trashcan code starts deleting the objects from its
- to-be-deleted-later list
-
- - subtype_dealloc() is called *AGAIN* for the same object
-
- - at the very least (if the destroyed slots and __dict__ don't
- cause problems) the object's type gets decref'ed a second
- time, which is *BAD*!!!
-
- The remedy is to make sure that if the code between trashcan
- begin and end in subtype_dealloc() is called, the code between
- trashcan begin and end in basedealloc() will also be called.
- This is done by decrementing the level after passing into the
- trashcan block, and incrementing it just before leaving the
- block.
-
- But now it's possible that a chain of objects consisting solely
- of objects whose deallocator is subtype_dealloc() will defeat
- the trashcan mechanism completely: the decremented level means
- that the effective level never reaches the limit. Therefore, we
- *increment* the level *before* entering the trashcan block, and
- matchingly decrement it after leaving. This means the trashcan
- code will trigger a little early, but that's no big deal.
-
- Q. Are there any live examples of code in need of all this
- complexity?
-
- A. Yes. See SF bug 668433 for code that crashed (when Python was
- compiled in debug mode) before the trashcan level manipulations
- were added. For more discussion, see SF patches 581742, 575073
- and bug 574207.
*/
}