Skip to content

Commit 25518f5

Browse files
sergey-miryanovfxeqxmulfxkumaraditya303nascheme
authored
GH-135552: Add tests to check weakref clearing (GH-136304)
These are tests to ensure behaviour introduced by GH-136189 is working as expected. Co-authored-by: Mikhail Borisov <43937008+fxeqxmulfx@users.noreply.github.com> Co-authored-by: Kumar Aditya <kumaraditya@python.org> Co-authored-by: Neil Schemenauer <nas-github@arctrix.com>
1 parent 37b5a0d commit 25518f5

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

Lib/test/test_gc.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff 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

11591190
class IncrementalGCTests(unittest.TestCase):
11601191
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")

Lib/test/test_weakref.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff 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

10481074
class SubclassableWeakrefTestCase(TestBase):
10491075

0 commit comments

Comments
 (0)