FAILURE MAP
← Case archive

FA-90531 / Garbage collector invariants / Open access

Reference processing: weak references survive finalization resurrection · case 01

A weak reference still returns an object that is about to be finalized.

Verified by executionVariant 1 · 6 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Weak references are tested against reachability after finalizable objects were resurrected.

THE FAILURE

Weak references are tested against reachability after finalizable objects were resurrected.

Unsuccessful approach: Exempting objects queued for finalization keeps exactly those weak references alive.

Case contract

Each cycle: trace strong reachability from roots (weak and phantom references are not traced); weak references whose referent is not strongly reachable are cleared; pending finalizable objects that are not strongly reachable are queued for finalization once and resurrected together with everything they reach for this cycle; phantom references are enqueued only when their referent is not reachable even through the resurrected set; everything else is freed. Return per cycle the cleared weak refs, finalized objects, enqueued phantoms and freed objects.

Why this case matters

Reference-processing order decides whether code can observe resurrected or half-dead objects.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(heap, roots, weak, finalizable, phantom, cycles):
    heap = {k: list(v) for k, v in heap.items()}
    weak = {r: t for r, t in weak}
    phantom = {r: t for r, t in phantom}
    pending = set(finalizable)
    out = []
    def trace(starts, seen):
        stack = list(starts)
        while stack:
            o = stack.pop()
            if o is None or o in seen or o not in heap:
                continue
            seen.add(o)
            stack.extend(heap[o])
        return seen
    for _ in range(cycles):
        strong = trace(roots, set())
        to_final = sorted(o for o in pending if o not in strong and o in heap)
        reach = trace(to_final, set(strong))
        cleared = sorted(r for r, t in weak.items() if t is not None and t not in reach)
        for r in cleared:
            weak[r] = None
        pending -= set(to_final)
        enq = sorted(r for r, t in phantom.items() if t is not None and t not in reach)
        for r in enq:
            phantom[r] = None
        freed = sorted(o for o in heap if o not in reach)
        for o in freed:
            del heap[o]
        out.append({'weak': cleared, 'finalize': to_final, 'phantom': enq, 'freed': freed})
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression: finalizable object over two cycles',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []},
    [11],
    [['w1', 13], ['w2', 12]],
    [13],
    [['p1', 14], ['p2', 16]],
    2),
   [{'finalize': [13], 'freed': [16], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []}, [11], [['w1', 13]], [13], [], 1),
   [{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []}, [11], [], [13], [], 3),
   [{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [13, 14, 15], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []}, [11], [], [13], [['p1', 15]], 1),
   [{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []}, [11], [], [13], [['p1', 14]], 2),
   [{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []},
    [11, 13, 16],
    [['w1', 13], ['w2', 12]],
    [13],
    [['p1', 14], ['p2', 16]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])],
 [('regression: finalizable object over two cycles',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []},
    [21],
    [['w1', 23], ['w2', 22]],
    [23],
    [['p1', 24], ['p2', 26]],
    2),
   [{'finalize': [23], 'freed': [26], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [23, 24, 25], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []}, [21], [['w1', 23]], [23], [], 1),
   [{'finalize': [23], 'freed': [26], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []}, [21], [], [23], [], 3),
   [{'finalize': [23], 'freed': [26], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [23, 24, 25], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []}, [21], [], [23], [['p1', 25]], 1),
   [{'finalize': [23], 'freed': [26], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []}, [21], [], [23], [['p1', 24]], 2),
   [{'finalize': [23], 'freed': [26], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [23, 24, 25], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []},
    [21, 23, 26],
    [['w1', 23], ['w2', 22]],
    [23],
    [['p1', 24], ['p2', 26]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])],
 [('regression: finalizable object over two cycles',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []},
    [31],
    [['w1', 33], ['w2', 32]],
    [33],
    [['p1', 34], ['p2', 36]],
    2),
   [{'finalize': [33], 'freed': [36], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [33, 34, 35], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []}, [31], [['w1', 33]], [33], [], 1),
   [{'finalize': [33], 'freed': [36], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []}, [31], [], [33], [], 3),
   [{'finalize': [33], 'freed': [36], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [33, 34, 35], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []}, [31], [], [33], [['p1', 35]], 1),
   [{'finalize': [33], 'freed': [36], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []}, [31], [], [33], [['p1', 34]], 2),
   [{'finalize': [33], 'freed': [36], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [33, 34, 35], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []},
    [31, 33, 36],
    [['w1', 33], ['w2', 32]],
    [33],
    [['p1', 34], ['p2', 36]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])],
 [('regression: finalizable object over two cycles',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []},
    [41],
    [['w1', 43], ['w2', 42]],
    [43],
    [['p1', 44], ['p2', 46]],
    2),
   [{'finalize': [43], 'freed': [46], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [43, 44, 45], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []}, [41], [['w1', 43]], [43], [], 1),
   [{'finalize': [43], 'freed': [46], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []}, [41], [], [43], [], 3),
   [{'finalize': [43], 'freed': [46], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [43, 44, 45], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []}, [41], [], [43], [['p1', 45]], 1),
   [{'finalize': [43], 'freed': [46], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []}, [41], [], [43], [['p1', 44]], 2),
   [{'finalize': [43], 'freed': [46], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [43, 44, 45], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []},
    [41, 43, 46],
    [['w1', 43], ['w2', 42]],
    [43],
    [['p1', 44], ['p2', 46]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])],
 [('regression: finalizable object over two cycles',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []},
    [51],
    [['w1', 53], ['w2', 52]],
    [53],
    [['p1', 54], ['p2', 56]],
    2),
   [{'finalize': [53], 'freed': [56], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [53, 54, 55], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []}, [51], [['w1', 53]], [53], [], 1),
   [{'finalize': [53], 'freed': [56], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []}, [51], [], [53], [], 3),
   [{'finalize': [53], 'freed': [56], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [53, 54, 55], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []}, [51], [], [53], [['p1', 55]], 1),
   [{'finalize': [53], 'freed': [56], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []}, [51], [], [53], [['p1', 54]], 2),
   [{'finalize': [53], 'freed': [56], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [53, 54, 55], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []},
    [51, 53, 56],
    [['w1', 53], ['w2', 52]],
    [53],
    [['p1', 54], ['p2', 56]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])]]
for label, args, expected in cases[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: finalizable object over two cycles[{'finalize': [13], 'freed': [16], 'phantom': ['p2'], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': ['w1']}][{'finalize': [13], 'freed': [16], 'phantom': ['p2'], 'weak': ['w1']}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}]Failed
weak reference to a resurrected object[{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}][{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': ['w1']}]Failed
finalizer runs only once[{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}][{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]Passed
children of a finalizable object stay alive[{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}][{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}]Passed
phantom of an object only reachable from a finalizable one[{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}][{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}]Passed
control: all strongly reachable[{'finalize': [], 'freed': [], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}][{'finalize': [], 'freed': [], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]Passed

SHA-256 / 68d7f3c79b24589ef5f46687c651345631554724dc701ec7f212debda174be26

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(heap, roots, weak, finalizable, phantom, cycles):
    heap = {k: list(v) for k, v in heap.items()}
    weak = {r: t for r, t in weak}
    phantom = {r: t for r, t in phantom}
    pending = set(finalizable)
    out = []
    def trace(starts, seen):
        stack = list(starts)
        while stack:
            o = stack.pop()
            if o is None or o in seen or o not in heap:
                continue
            seen.add(o)
            stack.extend(heap[o])
        return seen
    for _ in range(cycles):
        strong = trace(roots, set())
        to_final = sorted(o for o in pending if o not in strong and o in heap)
        reach = trace(to_final, set(strong))
        cleared = sorted(r for r, t in weak.items() if t is not None and t not in strong and t not in to_final)
        for r in cleared:
            weak[r] = None
        pending -= set(to_final)
        enq = sorted(r for r, t in phantom.items() if t is not None and t not in reach)
        for r in enq:
            phantom[r] = None
        freed = sorted(o for o in heap if o not in reach)
        for o in freed:
            del heap[o]
        out.append({'weak': cleared, 'finalize': to_final, 'phantom': enq, 'freed': freed})
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression: finalizable object over two cycles',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []},
    [11],
    [['w1', 13], ['w2', 12]],
    [13],
    [['p1', 14], ['p2', 16]],
    2),
   [{'finalize': [13], 'freed': [16], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []}, [11], [['w1', 13]], [13], [], 1),
   [{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []}, [11], [], [13], [], 3),
   [{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [13, 14, 15], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []}, [11], [], [13], [['p1', 15]], 1),
   [{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []}, [11], [], [13], [['p1', 14]], 2),
   [{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({11: [12], 12: [], 13: [14], 14: [15], 15: [], 16: []},
    [11, 13, 16],
    [['w1', 13], ['w2', 12]],
    [13],
    [['p1', 14], ['p2', 16]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])],
 [('regression: finalizable object over two cycles',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []},
    [21],
    [['w1', 23], ['w2', 22]],
    [23],
    [['p1', 24], ['p2', 26]],
    2),
   [{'finalize': [23], 'freed': [26], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [23, 24, 25], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []}, [21], [['w1', 23]], [23], [], 1),
   [{'finalize': [23], 'freed': [26], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []}, [21], [], [23], [], 3),
   [{'finalize': [23], 'freed': [26], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [23, 24, 25], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []}, [21], [], [23], [['p1', 25]], 1),
   [{'finalize': [23], 'freed': [26], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []}, [21], [], [23], [['p1', 24]], 2),
   [{'finalize': [23], 'freed': [26], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [23, 24, 25], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({21: [22], 22: [], 23: [24], 24: [25], 25: [], 26: []},
    [21, 23, 26],
    [['w1', 23], ['w2', 22]],
    [23],
    [['p1', 24], ['p2', 26]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])],
 [('regression: finalizable object over two cycles',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []},
    [31],
    [['w1', 33], ['w2', 32]],
    [33],
    [['p1', 34], ['p2', 36]],
    2),
   [{'finalize': [33], 'freed': [36], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [33, 34, 35], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []}, [31], [['w1', 33]], [33], [], 1),
   [{'finalize': [33], 'freed': [36], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []}, [31], [], [33], [], 3),
   [{'finalize': [33], 'freed': [36], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [33, 34, 35], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []}, [31], [], [33], [['p1', 35]], 1),
   [{'finalize': [33], 'freed': [36], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []}, [31], [], [33], [['p1', 34]], 2),
   [{'finalize': [33], 'freed': [36], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [33, 34, 35], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({31: [32], 32: [], 33: [34], 34: [35], 35: [], 36: []},
    [31, 33, 36],
    [['w1', 33], ['w2', 32]],
    [33],
    [['p1', 34], ['p2', 36]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])],
 [('regression: finalizable object over two cycles',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []},
    [41],
    [['w1', 43], ['w2', 42]],
    [43],
    [['p1', 44], ['p2', 46]],
    2),
   [{'finalize': [43], 'freed': [46], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [43, 44, 45], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []}, [41], [['w1', 43]], [43], [], 1),
   [{'finalize': [43], 'freed': [46], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []}, [41], [], [43], [], 3),
   [{'finalize': [43], 'freed': [46], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [43, 44, 45], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []}, [41], [], [43], [['p1', 45]], 1),
   [{'finalize': [43], 'freed': [46], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []}, [41], [], [43], [['p1', 44]], 2),
   [{'finalize': [43], 'freed': [46], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [43, 44, 45], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({41: [42], 42: [], 43: [44], 44: [45], 45: [], 46: []},
    [41, 43, 46],
    [['w1', 43], ['w2', 42]],
    [43],
    [['p1', 44], ['p2', 46]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])],
 [('regression: finalizable object over two cycles',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []},
    [51],
    [['w1', 53], ['w2', 52]],
    [53],
    [['p1', 54], ['p2', 56]],
    2),
   [{'finalize': [53], 'freed': [56], 'phantom': ['p2'], 'weak': ['w1']},
    {'finalize': [], 'freed': [53, 54, 55], 'phantom': ['p1'], 'weak': []}]),
  ('weak reference to a resurrected object',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []}, [51], [['w1', 53]], [53], [], 1),
   [{'finalize': [53], 'freed': [56], 'phantom': [], 'weak': ['w1']}]),
  ('finalizer runs only once',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []}, [51], [], [53], [], 3),
   [{'finalize': [53], 'freed': [56], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [53, 54, 55], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]),
  ('children of a finalizable object stay alive',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []}, [51], [], [53], [['p1', 55]], 1),
   [{'finalize': [53], 'freed': [56], 'phantom': [], 'weak': []}]),
  ('phantom of an object only reachable from a finalizable one',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []}, [51], [], [53], [['p1', 54]], 2),
   [{'finalize': [53], 'freed': [56], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [53, 54, 55], 'phantom': ['p1'], 'weak': []}]),
  ('control: all strongly reachable',
   ({51: [52], 52: [], 53: [54], 54: [55], 55: [], 56: []},
    [51, 53, 56],
    [['w1', 53], ['w2', 52]],
    [53],
    [['p1', 54], ['p2', 56]],
    2),
   [{'finalize': [], 'freed': [], 'phantom': [], 'weak': []},
    {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}])]]
for label, args, expected in cases[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: finalizable object over two cycles[{'finalize': [13], 'freed': [16], 'phantom': ['p2'], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': ['w1']}][{'finalize': [13], 'freed': [16], 'phantom': ['p2'], 'weak': ['w1']}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}]Failed
weak reference to a resurrected object[{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}][{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': ['w1']}]Failed
finalizer runs only once[{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}][{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]Passed
children of a finalizable object stay alive[{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}][{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}]Passed
phantom of an object only reachable from a finalizable one[{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}][{'finalize': [13], 'freed': [16], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [13, 14, 15], 'phantom': ['p1'], 'weak': []}]Passed
control: all strongly reachable[{'finalize': [], 'freed': [], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}][{'finalize': [], 'freed': [], 'phantom': [], 'weak': []}, {'finalize': [], 'freed': [], 'phantom': [], 'weak': []}]Passed

SHA-256 / 454d269adffceeb490efef38d3bc25eee7cd266262661660c46f87ff1dccb539

HELD IN THE MEMBER ARCHIVE

The verified repair and its recorded checks are member-only.

This mechanism has 6 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.

Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.

Member access is invitation-based. Sign in with your invited account to inspect the repair.

Sign in to the archive ↗

Verification & scope

A deterministic, bounded teaching model of one garbage-collector mechanism with stipulated rules; it is not a production collector and claims no conformance to any particular runtime. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:51:27.743441+00:00.

Case digest / fb000bec443db737026e8f42ef805c46f8b1dbd72981926ebc57abf92805f05f