MCPcopy Index your code
hub / github.com/python/cpython / test_bug1055820c

Method test_bug1055820c

Lib/test/test_gc.py:1453–1526  ·  view source on GitHub ↗
(self)

Source from the content-addressed store, hash-verified

1451
1452 @unittest.skipIf(Py_GIL_DISABLED, "requires GC generations or increments")
1453 def test_bug1055820c(self):
1454 # Corresponds to temp2c.py in the bug report. This is pretty
1455 # elaborate.
1456
1457 c0 = C1055820(0)
1458 # Move c0 into generation 2.
1459 gc.collect()
1460
1461 c1 = C1055820(1)
1462 c1.keep_c0_alive = c0
1463 del c0.loop # now only c1 keeps c0 alive
1464
1465 c2 = C1055820(2)
1466 c2wr = weakref.ref(c2) # no callback!
1467
1468 ouch = []
1469 def callback(ignored):
1470 ouch[:] = [c2wr()]
1471
1472 # The callback gets associated with a wr on an object in generation 2.
1473 c0wr = weakref.ref(c0, callback)
1474
1475 c0 = c1 = c2 = None
1476
1477 # What we've set up: c0, c1, and c2 are all trash now. c0 is in
1478 # generation 2. The only thing keeping it alive is that c1 points to
1479 # it. c1 and c2 are in generation 0, and are in self-loops. There's a
1480 # global weakref to c2 (c2wr), but that weakref has no callback.
1481 # There's also a global weakref to c0 (c0wr), and that does have a
1482 # callback, and that callback references c2 via c2wr().
1483 #
1484 # c0 has a wr with callback, which references c2wr
1485 # ^
1486 # |
1487 # | Generation 2 above dots
1488 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
1489 # | Generation 0 below dots
1490 # |
1491 # |
1492 # ^->c1 ^->c2 has a wr but no callback
1493 # | | | |
1494 # <--v <--v
1495 #
1496 # So this is the nightmare: when generation 0 gets collected, we see
1497 # that c2 has a callback-free weakref, and c1 doesn't even have a
1498 # weakref. Collecting generation 0 doesn't see c0 at all, and c0 is
1499 # the only object that has a weakref with a callback. gc clears c1
1500 # and c2. Clearing c1 has the side effect of dropping the refcount on
1501 # c0 to 0, so c0 goes away (despite that it's in an older generation)
1502 # and c0's wr callback triggers. That in turn materializes a reference
1503 # to c2 via c2wr(), but c2 gets cleared anyway by gc.
1504
1505 # We want to let gc happen "naturally", to preserve the distinction
1506 # between generations.
1507 junk = []
1508 i = 0
1509 detector = GC_Detector()
1510 if Py_GIL_DISABLED:

Callers

nothing calls this directly

Calls 6

C1055820Class · 0.85
GC_DetectorClass · 0.85
collectMethod · 0.45
failMethod · 0.45
assertEqualMethod · 0.45
appendMethod · 0.45

Tested by

no test coverage detected