@@ -262,9 +262,11 @@ class Cyclic(tuple):
262262 # finalizer.
263263 def __del__(self):
264264
265- # 5. Create a weakref to `func` now. If we had created
266- # it earlier, it would have been cleared by the
267- # garbage collector before calling the finalizers.
265+ # 5. Create a weakref to `func` now. In previous
266+ # versions of Python, this would avoid having it
267+ # cleared by the garbage collector before calling
268+ # the finalizers. Now, weakrefs get cleared after
269+ # calling finalizers.
268270 self[1].ref = weakref.ref(self[0])
269271
270272 # 6. Drop the global reference to `latefin`. The only
@@ -293,14 +295,18 @@ def func():
293295 # which will find `cyc` and `func` as garbage.
294296 gc.collect()
295297
296- # 9. Previously, this would crash because `func_qualname`
297- # had been NULL-ed out by func_clear().
298+ # 9. Previously, this would crash because the weakref
299+ # created in the finalizer revealed the function after
300+ # `tp_clear` was called and `func_qualname`
301+ # had been NULL-ed out by func_clear(). Now, we clear
302+ # weakrefs to unreachable objects before calling `tp_clear`
303+ # but after calling finalizers.
298304 print(f"{func=}")
299305 """
300- # We're mostly just checking that this doesn't crash.
301306 rc , stdout , stderr = assert_python_ok ("-c" , code )
302307 self .assertEqual (rc , 0 )
303- self .assertRegex (stdout , rb"""\A\s*func=<function at \S+>\s*\z""" )
308+ # The `func` global is None because the weakref was cleared.
309+ self .assertRegex (stdout , rb"""\A\s*func=None""" )
304310 self .assertFalse (stderr )
305311
306312 @refcount_test
@@ -652,9 +658,11 @@ def callback(ignored):
652658 gc .collect ()
653659 self .assertEqual (len (ouch ), 2 ) # else the callbacks didn't run
654660 for x in ouch :
655- # If the callback resurrected one of these guys, the instance
656- # would be damaged, with an empty __dict__.
657- self .assertEqual (x , None )
661+ # In previous versions of Python, the weakrefs are cleared
662+ # before calling finalizers. Now they are cleared after.
663+ # So when the object is resurrected, the weakref is not
664+ # cleared since it is no longer unreachable.
665+ self .assertIsInstance (x , C1055820 )
658666
659667 def test_bug21435 (self ):
660668 # This is a poor test - its only virtue is that it happened to
@@ -1041,8 +1049,8 @@ class Z:
10411049 # release references and create trash
10421050 del a , wr_cycle
10431051 gc .collect ()
1044- # if called, it means there is a bug in the GC. The weakref should be
1045- # cleared before Z dies .
1052+ # In older versions of Python, the weakref was cleared by the
1053+ # gc. Now it is not cleared and so the callback is run .
10461054 callback .assert_not_called ()
10471055 gc .enable ()
10481056
@@ -1324,6 +1332,7 @@ def setUp(self):
13241332 def tearDown (self ):
13251333 gc .disable ()
13261334
1335+ @unittest .skipIf (Py_GIL_DISABLED , "requires GC generations or increments" )
13271336 def test_bug1055820c (self ):
13281337 # Corresponds to temp2c.py in the bug report. This is pretty
13291338 # elaborate.
@@ -1399,6 +1408,7 @@ def callback(ignored):
13991408 self .assertEqual (x , None )
14001409
14011410 @gc_threshold (1000 , 0 , 0 )
1411+ @unittest .skipIf (Py_GIL_DISABLED , "requires GC generations or increments" )
14021412 def test_bug1055820d (self ):
14031413 # Corresponds to temp2d.py in the bug report. This is very much like
14041414 # test_bug1055820c, but uses a __del__ method instead of a weakref
0 commit comments