Skip to content

Commit 6f8de0b

Browse files
committed
bpo-36556: trashcan should not cause duplicated __del__
1 parent fd83a82 commit 6f8de0b

3 files changed

Lines changed: 28 additions & 0 deletions

File tree

Lib/test/test_gc.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,24 @@ def __del__(self):
307307
v = {1: v, 2: Ouch()}
308308
gc.disable()
309309

310+
def test_no_double_del(self):
311+
# bpo-36556: instances of heap types should be deallocated once,
312+
# even if the trashcan and __del__ are involved
313+
class ObjectCounter(object):
314+
count = 0
315+
def __init__(self):
316+
type(self).count += 1
317+
def __del__(self):
318+
# create temporary involving self, whose deallocation
319+
# uses the trashcan
320+
L = [self]
321+
type(self).count -= 1
322+
L = None
323+
for i in range(10000):
324+
L = (L, ObjectCounter())
325+
del L
326+
self.assertEqual(ObjectCounter.count, 0)
327+
310328
@unittest.skipUnless(threading, "test meaningless on builds without threads")
311329
def test_trashcan_threads(self):
312330
# Issue #13992: trashcan mechanism should be thread-safe
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
When deleting highly nested objects (where the trashcan mechanism is
2+
involved), it is less likely that ``__del__`` is called multiple times.

Objects/typeobject.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,14 @@ subtype_clear(PyObject *self)
917917
return 0;
918918
}
919919

920+
/* bpo-36556: lower the trashcan recursion limit for heap types: this gives
921+
* __del__ 10 additional stack frames to work with. This makes it less likely
922+
* that the trashcan is used in __del__. Otherwise, an object might seemingly
923+
* be resurrected by __del__ when it's still referenced by an object in the
924+
* trashcan. */
925+
#undef PyTrash_UNWIND_LEVEL
926+
#define PyTrash_UNWIND_LEVEL 40
927+
920928
static void
921929
subtype_dealloc(PyObject *self)
922930
{

0 commit comments

Comments
 (0)