(self)
| 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: |
nothing calls this directly
no test coverage detected