# Crashes due to func tp_clear call import gc import xx import weakref def dummy(): print('running dummy function') class CF(list): __slots__ = [] def __del__(self): print('running __del__ for CF', self) def callback(self, wr, dummy=dummy): # if this runs, it can do bad things: cause crashes, revive 'self' print('oops, should not run', repr(self)) dummy() class A: def __del__(self): print('running __del__ for A') ct = xx.new() # type does not implement tp_traverse ct.a = A() # gc will not find 'a' due to missing tp_traverse cf = CF() cf.append(ct) cf.append(cf) # create cycle # create cycle for dummy function, so it gets tp_clear called on it dummy.dummy = dummy # second trash cycle containing weakref, created so it outlives cf cycle wr = [weakref.ref(ct.a, cf.callback)] wr.append(wr) del ct, A, CF gc.collect() del cf, wr, dummy # At this point the following is true: # - cf, ct and the weakref are cyclic trash # - 'a' is not yet trash (it actually is but the GC doesn't know because of # the missing tp_traverse method). It will be freed when cf is cleared # - callback for 'a' will run when cf or ct is cleared because reference to # 'a' is removed gc.set_debug(gc.DEBUG_COLLECTABLE) print('running collect') print(gc.collect()) gc.set_debug(0)