1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
"""
Initial cleanup and 'calibration':
>>> _ = gc.collect()
>>> old_unreachable = len(gc.garbage)
Test:
>>> x = SimpleGarbage()
SimpleGarbage(1) __cinit__
>>> del x
SimpleGarbage(1) __dealloc__
Collector.__dealloc__
Make sure nothing changed in the environment:
>>> new_unreachable = get_new_unreachable()
>>> new_unreachable == old_unreachable or (old_unreachable, new_unreachable)
True
"""
import gc
cdef Py_ssize_t new_unreachable = 0
def get_new_unreachable():
return new_unreachable
cdef int counter = 0
cdef int next_counter():
global counter
counter += 1
return counter
cdef class Collector:
# Indirectly trigger garbage collection in SimpleGarbage deallocation.
# The __dealloc__ method of SimpleGarbage won't trigger the bug as the
# refcount is artificially inflated for the duration of that function.
def __dealloc__(self):
print "Collector.__dealloc__"
global new_unreachable
gc.collect()
new_unreachable = len(gc.garbage)
cdef class SimpleGarbage:
cdef Collector c # to participate in garbage collection
cdef int index
cdef bint deallocated
def __cinit__(self):
self.index = next_counter()
self.c = Collector()
print self, "__cinit__"
def __dealloc__(self):
print self, "__dealloc__"
if self.deallocated:
print "Double dealloc!"
self.deallocated = True
gc.collect()
def __str__(self):
return "SimpleGarbage(%s)" % self.index
def __repr__(self):
return "SimpleGarbage(%s)" % self.index
|