File tree Expand file tree Collapse file tree 2 files changed +57
-0
lines changed Expand file tree Collapse file tree 2 files changed +57
-0
lines changed Original file line number Diff line number Diff line change @@ -1155,6 +1155,37 @@ def test_something(self):
11551155 """ )
11561156 assert_python_ok ("-c" , source )
11571157
1158+ def test_do_not_cleanup_type_subclasses_before_finalization (self ):
1159+ # See https://github.com/python/cpython/issues/135552
1160+ # If we cleanup weakrefs for tp_subclasses before calling
1161+ # the finalizer (__del__) then the line `fail = BaseNode.next.next`
1162+ # should fail because we are trying to access a subclass
1163+ # attribute. But subclass type cache was not properly invalidated.
1164+ code = """
1165+ class BaseNode:
1166+ def __del__(self):
1167+ BaseNode.next = BaseNode.next.next
1168+ fail = BaseNode.next.next
1169+
1170+ class Node(BaseNode):
1171+ pass
1172+
1173+ BaseNode.next = Node()
1174+ BaseNode.next.next = Node()
1175+ """
1176+ # this test checks garbage collection while interp
1177+ # finalization
1178+ assert_python_ok ("-c" , textwrap .dedent (code ))
1179+
1180+ code_inside_function = textwrap .dedent (F"""
1181+ def test():
1182+ { textwrap .indent (code , ' ' )}
1183+
1184+ test()
1185+ """ )
1186+ # this test checks regular garbage collection
1187+ assert_python_ok ("-c" , code_inside_function )
1188+
11581189
11591190class IncrementalGCTests (unittest .TestCase ):
11601191 @unittest .skipIf (_testinternalcapi is None , "requires _testinternalcapi" )
Original file line number Diff line number Diff line change @@ -1044,6 +1044,32 @@ def callback(obj):
10441044 stderr = res .err .decode ("ascii" , "backslashreplace" )
10451045 self .assertNotRegex (stderr , "_Py_Dealloc: Deallocator of type 'TestObj'" )
10461046
1047+ def test_clearing_weakrefs_in_gc (self ):
1048+ # This test checks that when finalizers are called:
1049+ # 1. weakrefs with callbacks have been cleared
1050+ # 2. weakrefs without callbacks have not been cleared
1051+ errors = []
1052+ def test ():
1053+ class Class :
1054+ def __init__ (self ):
1055+ self ._self = self
1056+ self .wr1 = weakref .ref (Class , lambda x : None )
1057+ self .wr2 = weakref .ref (Class )
1058+
1059+ def __del__ (self ):
1060+ # we can't use assert* here, because gc will swallow
1061+ # exceptions
1062+ if self .wr1 () is not None :
1063+ errors .append ("weakref with callback as cleared" )
1064+ if self .wr2 () is not Class :
1065+ errors .append ("weakref without callback was cleared" )
1066+
1067+ Class ()
1068+
1069+ test ()
1070+ gc .collect ()
1071+ self .assertEqual (errors , [])
1072+
10471073
10481074class SubclassableWeakrefTestCase (TestBase ):
10491075
You can’t perform that action at this time.
0 commit comments