{"abstract":"Self-assignment or storing a child of the old value frees the object being stored.","category":"Garbage collector invariants","checks":7,"contract":"Objects carry a strong count and a weak count. new id k: strong 1 (the creating reference), k null fields. drop id: release one strong reference. store src i dst: retain dst, then write, then release the old value. When the strong count reaches 0 the object is destroyed (recorded in freed, its fields released recursively in field order) and, if no weak references remain, its control block is deallocated too; unweak deallocates a destroyed object's block when the last weak reference goes. upgrade id succeeds (and adds a strong reference) only while the strong count is positive. Touching a deallocated block reports \"use-after-free\".","evaluation_group":"w2-garbage-collector-invariants-strong-weak-refcounts","failed_approach":"Special-casing identical references fixes self-assignment but still frees a new target reachable only through the old value.","family":"w2-garbage-collector-invariants-strong-weak-refcounts-retain-before-release","id":"FA-90366","implementations":{"attempt":{"sha256":"df50e3894ea7f91d2229693ede090edfe9aa305a93603daf818cf5d2d013d624","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(events):\n    objs = {}\n    freed = []\n    dealloc = []\n    out = []\n    def release(o):\n        if o is None:\n            return\n        b = objs[o]\n        b['rc'] -= 1\n        if b['rc'] == 0:\n            freed.append(o)\n            kids, b['fields'] = b['fields'], []\n            if b['weak'] == 0:\n                dealloc.append(o)\n                del objs[o]\n            for c in kids:\n                release(c)\n    try:\n        for ev in events:\n            op = ev[0]\n            if op == 'new':\n                objs[ev[1]] = {'rc': 1, 'weak': 0, 'fields': [None] * ev[2]}\n            elif op == 'drop':\n                release(ev[1])\n            elif op == 'store':\n                _, src, field, dst = ev\n                old = objs[src]['fields'][field]\n                if old is not dst:\n                    release(old)\n                    if dst is not None:\n                        objs[dst]['rc'] += 1\n                objs[src]['fields'][field] = dst\n            elif op == 'weak':\n                objs[ev[1]]['weak'] += 1\n            elif op == 'unweak':\n                b = objs[ev[1]]\n                b['weak'] -= 1\n                if b['weak'] == 0 and b['rc'] == 0:\n                    dealloc.append(ev[1])\n                    del objs[ev[1]]\n            else:\n                b = objs[ev[1]]\n                if b['rc'] > 0:\n                    b['rc'] += 1\n                    out.append(True)\n                else:\n                    out.append(False)\n    except (KeyError, IndexError):\n        out.append('use-after-free')\n    return {'out': out, 'freed': freed, 'dealloc': dealloc,\n            'rc': {str(k): [v['rc'], v['weak']] for k, v in sorted(objs.items())}}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression: overwrite with a child of the old value',\n   ([['new', 11, 1],\n     ['new', 12, 1],\n     ['new', 13, 0],\n     ['store', 12, 0, 13],\n     ['drop', 13],\n     ['store', 11, 0, 12],\n     ['drop', 12],\n     ['store', 11, 0, 13]],),\n   {'dealloc': [12], 'freed': [12], 'out': [], 'rc': {'11': [1, 0], '13': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 11, 1],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['drop', 12],\n     ['store', 11, 0, 12],\n     ['upgrade', 12]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'11': [1, 0], '12': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 11, 2],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['store', 11, 1, 12],\n     ['drop', 12],\n     ['drop', 11]],),\n   {'dealloc': [11, 12], 'freed': [11, 12], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 11, 0], ['weak', 11], ['drop', 11], ['upgrade', 11], ['unweak', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 11, 1],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['weak', 11],\n     ['drop', 11],\n     ['upgrade', 11],\n     ['unweak', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [False], 'rc': {'12': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 11, 0], ['weak', 11], ['unweak', 11], ['upgrade', 11], ['drop', 11], ['drop', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 11, 1],\n     ['new', 12, 1],\n     ['new', 13, 0],\n     ['store', 11, 0, 12],\n     ['store', 12, 0, 13],\n     ['drop', 12],\n     ['drop', 13],\n     ['drop', 11]],),\n   {'dealloc': [11, 12, 13], 'freed': [11, 12, 13], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 21, 1],\n     ['new', 22, 1],\n     ['new', 23, 0],\n     ['store', 22, 0, 23],\n     ['drop', 23],\n     ['store', 21, 0, 22],\n     ['drop', 22],\n     ['store', 21, 0, 23]],),\n   {'dealloc': [22], 'freed': [22], 'out': [], 'rc': {'21': [1, 0], '23': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 21, 1],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['drop', 22],\n     ['store', 21, 0, 22],\n     ['upgrade', 22]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'21': [1, 0], '22': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 21, 2],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['store', 21, 1, 22],\n     ['drop', 22],\n     ['drop', 21]],),\n   {'dealloc': [21, 22], 'freed': [21, 22], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 21, 0], ['weak', 21], ['drop', 21], ['upgrade', 21], ['unweak', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 21, 1],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['weak', 21],\n     ['drop', 21],\n     ['upgrade', 21],\n     ['unweak', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [False], 'rc': {'22': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 21, 0], ['weak', 21], ['unweak', 21], ['upgrade', 21], ['drop', 21], ['drop', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 21, 1],\n     ['new', 22, 1],\n     ['new', 23, 0],\n     ['store', 21, 0, 22],\n     ['store', 22, 0, 23],\n     ['drop', 22],\n     ['drop', 23],\n     ['drop', 21]],),\n   {'dealloc': [21, 22, 23], 'freed': [21, 22, 23], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 31, 1],\n     ['new', 32, 1],\n     ['new', 33, 0],\n     ['store', 32, 0, 33],\n     ['drop', 33],\n     ['store', 31, 0, 32],\n     ['drop', 32],\n     ['store', 31, 0, 33]],),\n   {'dealloc': [32], 'freed': [32], 'out': [], 'rc': {'31': [1, 0], '33': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 31, 1],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['drop', 32],\n     ['store', 31, 0, 32],\n     ['upgrade', 32]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'31': [1, 0], '32': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 31, 2],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['store', 31, 1, 32],\n     ['drop', 32],\n     ['drop', 31]],),\n   {'dealloc': [31, 32], 'freed': [31, 32], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 31, 0], ['weak', 31], ['drop', 31], ['upgrade', 31], ['unweak', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 31, 1],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['weak', 31],\n     ['drop', 31],\n     ['upgrade', 31],\n     ['unweak', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [False], 'rc': {'32': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 31, 0], ['weak', 31], ['unweak', 31], ['upgrade', 31], ['drop', 31], ['drop', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 31, 1],\n     ['new', 32, 1],\n     ['new', 33, 0],\n     ['store', 31, 0, 32],\n     ['store', 32, 0, 33],\n     ['drop', 32],\n     ['drop', 33],\n     ['drop', 31]],),\n   {'dealloc': [31, 32, 33], 'freed': [31, 32, 33], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 41, 1],\n     ['new', 42, 1],\n     ['new', 43, 0],\n     ['store', 42, 0, 43],\n     ['drop', 43],\n     ['store', 41, 0, 42],\n     ['drop', 42],\n     ['store', 41, 0, 43]],),\n   {'dealloc': [42], 'freed': [42], 'out': [], 'rc': {'41': [1, 0], '43': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 41, 1],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['drop', 42],\n     ['store', 41, 0, 42],\n     ['upgrade', 42]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'41': [1, 0], '42': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 41, 2],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['store', 41, 1, 42],\n     ['drop', 42],\n     ['drop', 41]],),\n   {'dealloc': [41, 42], 'freed': [41, 42], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 41, 0], ['weak', 41], ['drop', 41], ['upgrade', 41], ['unweak', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 41, 1],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['weak', 41],\n     ['drop', 41],\n     ['upgrade', 41],\n     ['unweak', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [False], 'rc': {'42': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 41, 0], ['weak', 41], ['unweak', 41], ['upgrade', 41], ['drop', 41], ['drop', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 41, 1],\n     ['new', 42, 1],\n     ['new', 43, 0],\n     ['store', 41, 0, 42],\n     ['store', 42, 0, 43],\n     ['drop', 42],\n     ['drop', 43],\n     ['drop', 41]],),\n   {'dealloc': [41, 42, 43], 'freed': [41, 42, 43], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 51, 1],\n     ['new', 52, 1],\n     ['new', 53, 0],\n     ['store', 52, 0, 53],\n     ['drop', 53],\n     ['store', 51, 0, 52],\n     ['drop', 52],\n     ['store', 51, 0, 53]],),\n   {'dealloc': [52], 'freed': [52], 'out': [], 'rc': {'51': [1, 0], '53': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 51, 1],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['drop', 52],\n     ['store', 51, 0, 52],\n     ['upgrade', 52]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'51': [1, 0], '52': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 51, 2],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['store', 51, 1, 52],\n     ['drop', 52],\n     ['drop', 51]],),\n   {'dealloc': [51, 52], 'freed': [51, 52], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 51, 0], ['weak', 51], ['drop', 51], ['upgrade', 51], ['unweak', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 51, 1],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['weak', 51],\n     ['drop', 51],\n     ['upgrade', 51],\n     ['unweak', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [False], 'rc': {'52': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 51, 0], ['weak', 51], ['unweak', 51], ['upgrade', 51], ['drop', 51], ['drop', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 51, 1],\n     ['new', 52, 1],\n     ['new', 53, 0],\n     ['store', 51, 0, 52],\n     ['store', 52, 0, 53],\n     ['drop', 52],\n     ['drop', 53],\n     ['drop', 51]],),\n   {'dealloc': [51, 52, 53], 'freed': [51, 52, 53], 'out': [], 'rc': {}})]]\nfor label, args, expected in cases[N - 1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"742ba234f800810d9477fe02c77a8a8e5227a85d806ed3633ddef254b9597ee1","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(events):\n    objs = {}\n    freed = []\n    dealloc = []\n    out = []\n    def release(o):\n        if o is None:\n            return\n        b = objs[o]\n        b['rc'] -= 1\n        if b['rc'] == 0:\n            freed.append(o)\n            kids, b['fields'] = b['fields'], []\n            if b['weak'] == 0:\n                dealloc.append(o)\n                del objs[o]\n            for c in kids:\n                release(c)\n    try:\n        for ev in events:\n            op = ev[0]\n            if op == 'new':\n                objs[ev[1]] = {'rc': 1, 'weak': 0, 'fields': [None] * ev[2]}\n            elif op == 'drop':\n                release(ev[1])\n            elif op == 'store':\n                _, src, field, dst = ev\n                old = objs[src]['fields'][field]\n                release(old)\n                if dst is not None:\n                    objs[dst]['rc'] += 1\n                objs[src]['fields'][field] = dst\n            elif op == 'weak':\n                objs[ev[1]]['weak'] += 1\n            elif op == 'unweak':\n                b = objs[ev[1]]\n                b['weak'] -= 1\n                if b['weak'] == 0 and b['rc'] == 0:\n                    dealloc.append(ev[1])\n                    del objs[ev[1]]\n            else:\n                b = objs[ev[1]]\n                if b['rc'] > 0:\n                    b['rc'] += 1\n                    out.append(True)\n                else:\n                    out.append(False)\n    except (KeyError, IndexError):\n        out.append('use-after-free')\n    return {'out': out, 'freed': freed, 'dealloc': dealloc,\n            'rc': {str(k): [v['rc'], v['weak']] for k, v in sorted(objs.items())}}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression: overwrite with a child of the old value',\n   ([['new', 11, 1],\n     ['new', 12, 1],\n     ['new', 13, 0],\n     ['store', 12, 0, 13],\n     ['drop', 13],\n     ['store', 11, 0, 12],\n     ['drop', 12],\n     ['store', 11, 0, 13]],),\n   {'dealloc': [12], 'freed': [12], 'out': [], 'rc': {'11': [1, 0], '13': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 11, 1],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['drop', 12],\n     ['store', 11, 0, 12],\n     ['upgrade', 12]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'11': [1, 0], '12': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 11, 2],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['store', 11, 1, 12],\n     ['drop', 12],\n     ['drop', 11]],),\n   {'dealloc': [11, 12], 'freed': [11, 12], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 11, 0], ['weak', 11], ['drop', 11], ['upgrade', 11], ['unweak', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 11, 1],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['weak', 11],\n     ['drop', 11],\n     ['upgrade', 11],\n     ['unweak', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [False], 'rc': {'12': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 11, 0], ['weak', 11], ['unweak', 11], ['upgrade', 11], ['drop', 11], ['drop', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 11, 1],\n     ['new', 12, 1],\n     ['new', 13, 0],\n     ['store', 11, 0, 12],\n     ['store', 12, 0, 13],\n     ['drop', 12],\n     ['drop', 13],\n     ['drop', 11]],),\n   {'dealloc': [11, 12, 13], 'freed': [11, 12, 13], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 21, 1],\n     ['new', 22, 1],\n     ['new', 23, 0],\n     ['store', 22, 0, 23],\n     ['drop', 23],\n     ['store', 21, 0, 22],\n     ['drop', 22],\n     ['store', 21, 0, 23]],),\n   {'dealloc': [22], 'freed': [22], 'out': [], 'rc': {'21': [1, 0], '23': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 21, 1],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['drop', 22],\n     ['store', 21, 0, 22],\n     ['upgrade', 22]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'21': [1, 0], '22': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 21, 2],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['store', 21, 1, 22],\n     ['drop', 22],\n     ['drop', 21]],),\n   {'dealloc': [21, 22], 'freed': [21, 22], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 21, 0], ['weak', 21], ['drop', 21], ['upgrade', 21], ['unweak', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 21, 1],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['weak', 21],\n     ['drop', 21],\n     ['upgrade', 21],\n     ['unweak', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [False], 'rc': {'22': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 21, 0], ['weak', 21], ['unweak', 21], ['upgrade', 21], ['drop', 21], ['drop', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 21, 1],\n     ['new', 22, 1],\n     ['new', 23, 0],\n     ['store', 21, 0, 22],\n     ['store', 22, 0, 23],\n     ['drop', 22],\n     ['drop', 23],\n     ['drop', 21]],),\n   {'dealloc': [21, 22, 23], 'freed': [21, 22, 23], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 31, 1],\n     ['new', 32, 1],\n     ['new', 33, 0],\n     ['store', 32, 0, 33],\n     ['drop', 33],\n     ['store', 31, 0, 32],\n     ['drop', 32],\n     ['store', 31, 0, 33]],),\n   {'dealloc': [32], 'freed': [32], 'out': [], 'rc': {'31': [1, 0], '33': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 31, 1],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['drop', 32],\n     ['store', 31, 0, 32],\n     ['upgrade', 32]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'31': [1, 0], '32': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 31, 2],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['store', 31, 1, 32],\n     ['drop', 32],\n     ['drop', 31]],),\n   {'dealloc': [31, 32], 'freed': [31, 32], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 31, 0], ['weak', 31], ['drop', 31], ['upgrade', 31], ['unweak', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 31, 1],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['weak', 31],\n     ['drop', 31],\n     ['upgrade', 31],\n     ['unweak', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [False], 'rc': {'32': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 31, 0], ['weak', 31], ['unweak', 31], ['upgrade', 31], ['drop', 31], ['drop', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 31, 1],\n     ['new', 32, 1],\n     ['new', 33, 0],\n     ['store', 31, 0, 32],\n     ['store', 32, 0, 33],\n     ['drop', 32],\n     ['drop', 33],\n     ['drop', 31]],),\n   {'dealloc': [31, 32, 33], 'freed': [31, 32, 33], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 41, 1],\n     ['new', 42, 1],\n     ['new', 43, 0],\n     ['store', 42, 0, 43],\n     ['drop', 43],\n     ['store', 41, 0, 42],\n     ['drop', 42],\n     ['store', 41, 0, 43]],),\n   {'dealloc': [42], 'freed': [42], 'out': [], 'rc': {'41': [1, 0], '43': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 41, 1],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['drop', 42],\n     ['store', 41, 0, 42],\n     ['upgrade', 42]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'41': [1, 0], '42': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 41, 2],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['store', 41, 1, 42],\n     ['drop', 42],\n     ['drop', 41]],),\n   {'dealloc': [41, 42], 'freed': [41, 42], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 41, 0], ['weak', 41], ['drop', 41], ['upgrade', 41], ['unweak', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 41, 1],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['weak', 41],\n     ['drop', 41],\n     ['upgrade', 41],\n     ['unweak', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [False], 'rc': {'42': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 41, 0], ['weak', 41], ['unweak', 41], ['upgrade', 41], ['drop', 41], ['drop', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 41, 1],\n     ['new', 42, 1],\n     ['new', 43, 0],\n     ['store', 41, 0, 42],\n     ['store', 42, 0, 43],\n     ['drop', 42],\n     ['drop', 43],\n     ['drop', 41]],),\n   {'dealloc': [41, 42, 43], 'freed': [41, 42, 43], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 51, 1],\n     ['new', 52, 1],\n     ['new', 53, 0],\n     ['store', 52, 0, 53],\n     ['drop', 53],\n     ['store', 51, 0, 52],\n     ['drop', 52],\n     ['store', 51, 0, 53]],),\n   {'dealloc': [52], 'freed': [52], 'out': [], 'rc': {'51': [1, 0], '53': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 51, 1],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['drop', 52],\n     ['store', 51, 0, 52],\n     ['upgrade', 52]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'51': [1, 0], '52': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 51, 2],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['store', 51, 1, 52],\n     ['drop', 52],\n     ['drop', 51]],),\n   {'dealloc': [51, 52], 'freed': [51, 52], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 51, 0], ['weak', 51], ['drop', 51], ['upgrade', 51], ['unweak', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 51, 1],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['weak', 51],\n     ['drop', 51],\n     ['upgrade', 51],\n     ['unweak', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [False], 'rc': {'52': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 51, 0], ['weak', 51], ['unweak', 51], ['upgrade', 51], ['drop', 51], ['drop', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 51, 1],\n     ['new', 52, 1],\n     ['new', 53, 0],\n     ['store', 51, 0, 52],\n     ['store', 52, 0, 53],\n     ['drop', 52],\n     ['drop', 53],\n     ['drop', 51]],),\n   {'dealloc': [51, 52, 53], 'freed': [51, 52, 53], 'out': [], 'rc': {}})]]\nfor label, args, expected in cases[N - 1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"bb0a242343e9a77d89dc0d20b2d39e1043b2ec3079fa8c8f2860209e66e25442","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(events):\n    objs = {}\n    freed = []\n    dealloc = []\n    out = []\n    def release(o):\n        if o is None:\n            return\n        b = objs[o]\n        b['rc'] -= 1\n        if b['rc'] == 0:\n            freed.append(o)\n            kids, b['fields'] = b['fields'], []\n            if b['weak'] == 0:\n                dealloc.append(o)\n                del objs[o]\n            for c in kids:\n                release(c)\n    try:\n        for ev in events:\n            op = ev[0]\n            if op == 'new':\n                objs[ev[1]] = {'rc': 1, 'weak': 0, 'fields': [None] * ev[2]}\n            elif op == 'drop':\n                release(ev[1])\n            elif op == 'store':\n                _, src, field, dst = ev\n                if dst is not None:\n                    objs[dst]['rc'] += 1\n                old = objs[src]['fields'][field]\n                objs[src]['fields'][field] = dst\n                release(old)\n            elif op == 'weak':\n                objs[ev[1]]['weak'] += 1\n            elif op == 'unweak':\n                b = objs[ev[1]]\n                b['weak'] -= 1\n                if b['weak'] == 0 and b['rc'] == 0:\n                    dealloc.append(ev[1])\n                    del objs[ev[1]]\n            else:\n                b = objs[ev[1]]\n                if b['rc'] > 0:\n                    b['rc'] += 1\n                    out.append(True)\n                else:\n                    out.append(False)\n    except (KeyError, IndexError):\n        out.append('use-after-free')\n    return {'out': out, 'freed': freed, 'dealloc': dealloc,\n            'rc': {str(k): [v['rc'], v['weak']] for k, v in sorted(objs.items())}}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression: overwrite with a child of the old value',\n   ([['new', 11, 1],\n     ['new', 12, 1],\n     ['new', 13, 0],\n     ['store', 12, 0, 13],\n     ['drop', 13],\n     ['store', 11, 0, 12],\n     ['drop', 12],\n     ['store', 11, 0, 13]],),\n   {'dealloc': [12], 'freed': [12], 'out': [], 'rc': {'11': [1, 0], '13': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 11, 1],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['drop', 12],\n     ['store', 11, 0, 12],\n     ['upgrade', 12]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'11': [1, 0], '12': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 11, 2],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['store', 11, 1, 12],\n     ['drop', 12],\n     ['drop', 11]],),\n   {'dealloc': [11, 12], 'freed': [11, 12], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 11, 0], ['weak', 11], ['drop', 11], ['upgrade', 11], ['unweak', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 11, 1],\n     ['new', 12, 0],\n     ['store', 11, 0, 12],\n     ['weak', 11],\n     ['drop', 11],\n     ['upgrade', 11],\n     ['unweak', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [False], 'rc': {'12': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 11, 0], ['weak', 11], ['unweak', 11], ['upgrade', 11], ['drop', 11], ['drop', 11]],),\n   {'dealloc': [11], 'freed': [11], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 11, 1],\n     ['new', 12, 1],\n     ['new', 13, 0],\n     ['store', 11, 0, 12],\n     ['store', 12, 0, 13],\n     ['drop', 12],\n     ['drop', 13],\n     ['drop', 11]],),\n   {'dealloc': [11, 12, 13], 'freed': [11, 12, 13], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 21, 1],\n     ['new', 22, 1],\n     ['new', 23, 0],\n     ['store', 22, 0, 23],\n     ['drop', 23],\n     ['store', 21, 0, 22],\n     ['drop', 22],\n     ['store', 21, 0, 23]],),\n   {'dealloc': [22], 'freed': [22], 'out': [], 'rc': {'21': [1, 0], '23': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 21, 1],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['drop', 22],\n     ['store', 21, 0, 22],\n     ['upgrade', 22]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'21': [1, 0], '22': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 21, 2],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['store', 21, 1, 22],\n     ['drop', 22],\n     ['drop', 21]],),\n   {'dealloc': [21, 22], 'freed': [21, 22], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 21, 0], ['weak', 21], ['drop', 21], ['upgrade', 21], ['unweak', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 21, 1],\n     ['new', 22, 0],\n     ['store', 21, 0, 22],\n     ['weak', 21],\n     ['drop', 21],\n     ['upgrade', 21],\n     ['unweak', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [False], 'rc': {'22': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 21, 0], ['weak', 21], ['unweak', 21], ['upgrade', 21], ['drop', 21], ['drop', 21]],),\n   {'dealloc': [21], 'freed': [21], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 21, 1],\n     ['new', 22, 1],\n     ['new', 23, 0],\n     ['store', 21, 0, 22],\n     ['store', 22, 0, 23],\n     ['drop', 22],\n     ['drop', 23],\n     ['drop', 21]],),\n   {'dealloc': [21, 22, 23], 'freed': [21, 22, 23], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 31, 1],\n     ['new', 32, 1],\n     ['new', 33, 0],\n     ['store', 32, 0, 33],\n     ['drop', 33],\n     ['store', 31, 0, 32],\n     ['drop', 32],\n     ['store', 31, 0, 33]],),\n   {'dealloc': [32], 'freed': [32], 'out': [], 'rc': {'31': [1, 0], '33': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 31, 1],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['drop', 32],\n     ['store', 31, 0, 32],\n     ['upgrade', 32]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'31': [1, 0], '32': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 31, 2],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['store', 31, 1, 32],\n     ['drop', 32],\n     ['drop', 31]],),\n   {'dealloc': [31, 32], 'freed': [31, 32], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 31, 0], ['weak', 31], ['drop', 31], ['upgrade', 31], ['unweak', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 31, 1],\n     ['new', 32, 0],\n     ['store', 31, 0, 32],\n     ['weak', 31],\n     ['drop', 31],\n     ['upgrade', 31],\n     ['unweak', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [False], 'rc': {'32': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 31, 0], ['weak', 31], ['unweak', 31], ['upgrade', 31], ['drop', 31], ['drop', 31]],),\n   {'dealloc': [31], 'freed': [31], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 31, 1],\n     ['new', 32, 1],\n     ['new', 33, 0],\n     ['store', 31, 0, 32],\n     ['store', 32, 0, 33],\n     ['drop', 32],\n     ['drop', 33],\n     ['drop', 31]],),\n   {'dealloc': [31, 32, 33], 'freed': [31, 32, 33], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 41, 1],\n     ['new', 42, 1],\n     ['new', 43, 0],\n     ['store', 42, 0, 43],\n     ['drop', 43],\n     ['store', 41, 0, 42],\n     ['drop', 42],\n     ['store', 41, 0, 43]],),\n   {'dealloc': [42], 'freed': [42], 'out': [], 'rc': {'41': [1, 0], '43': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 41, 1],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['drop', 42],\n     ['store', 41, 0, 42],\n     ['upgrade', 42]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'41': [1, 0], '42': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 41, 2],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['store', 41, 1, 42],\n     ['drop', 42],\n     ['drop', 41]],),\n   {'dealloc': [41, 42], 'freed': [41, 42], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 41, 0], ['weak', 41], ['drop', 41], ['upgrade', 41], ['unweak', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 41, 1],\n     ['new', 42, 0],\n     ['store', 41, 0, 42],\n     ['weak', 41],\n     ['drop', 41],\n     ['upgrade', 41],\n     ['unweak', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [False], 'rc': {'42': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 41, 0], ['weak', 41], ['unweak', 41], ['upgrade', 41], ['drop', 41], ['drop', 41]],),\n   {'dealloc': [41], 'freed': [41], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 41, 1],\n     ['new', 42, 1],\n     ['new', 43, 0],\n     ['store', 41, 0, 42],\n     ['store', 42, 0, 43],\n     ['drop', 42],\n     ['drop', 43],\n     ['drop', 41]],),\n   {'dealloc': [41, 42, 43], 'freed': [41, 42, 43], 'out': [], 'rc': {}})],\n [('regression: overwrite with a child of the old value',\n   ([['new', 51, 1],\n     ['new', 52, 1],\n     ['new', 53, 0],\n     ['store', 52, 0, 53],\n     ['drop', 53],\n     ['store', 51, 0, 52],\n     ['drop', 52],\n     ['store', 51, 0, 53]],),\n   {'dealloc': [52], 'freed': [52], 'out': [], 'rc': {'51': [1, 0], '53': [1, 0]}}),\n  ('self-assignment of the only reference',\n   ([['new', 51, 1],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['drop', 52],\n     ['store', 51, 0, 52],\n     ['upgrade', 52]],),\n   {'dealloc': [], 'freed': [], 'out': [True], 'rc': {'51': [1, 0], '52': [2, 0]}}),\n  ('object referenced twice by one parent',\n   ([['new', 51, 2],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['store', 51, 1, 52],\n     ['drop', 52],\n     ['drop', 51]],),\n   {'dealloc': [51, 52], 'freed': [51, 52], 'out': [], 'rc': {}}),\n  ('upgrade after the last strong reference dies',\n   ([['new', 51, 0], ['weak', 51], ['drop', 51], ['upgrade', 51], ['unweak', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [False], 'rc': {}}),\n  ('weak reference keeps the control block only',\n   ([['new', 51, 1],\n     ['new', 52, 0],\n     ['store', 51, 0, 52],\n     ['weak', 51],\n     ['drop', 51],\n     ['upgrade', 51],\n     ['unweak', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [False], 'rc': {'52': [1, 0]}}),\n  ('dropping a weak reference to a live object',\n   ([['new', 51, 0], ['weak', 51], ['unweak', 51], ['upgrade', 51], ['drop', 51], ['drop', 51]],),\n   {'dealloc': [51], 'freed': [51], 'out': [True], 'rc': {}}),\n  ('control: chain release order',\n   ([['new', 51, 1],\n     ['new', 52, 1],\n     ['new', 53, 0],\n     ['store', 51, 0, 52],\n     ['store', 52, 0, 53],\n     ['drop', 52],\n     ['drop', 53],\n     ['drop', 51]],),\n   {'dealloc': [51, 52, 53], 'freed': [51, 52, 53], 'out': [], 'rc': {}})]]\nfor label, args, expected in cases[N - 1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"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.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-garbage-collector-invariants-strong-weak-refcounts-retain-before-release","generated_at":"2026-09-29T14:51:25.946933+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Reference-counting collectors must order retains and releases and separate destruction from deallocation.","repair":"Retain the new target first, then write, then release the old value.","root_cause":"The store releases the overwritten reference before incrementing the new target.","sha256":"15e4178949196d839391a90ed1a025f2b9ce8fd5a28c344cb083907751588d8b","title":"Reference counting: old value released before the new value is retained · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":42.794,"exit_code":1,"observations":[{"actual":{"dealloc":[12,13],"freed":[12,13],"out":["use-after-free"],"rc":{"11":[1,0]}},"check":"regression: overwrite with a child of the old value","expected":{"dealloc":[12],"freed":[12],"out":[],"rc":{"11":[1,0],"13":[1,0]}},"passed":false},{"actual":{"dealloc":[],"freed":[],"out":[true],"rc":{"11":[1,0],"12":[2,0]}},"check":"self-assignment of the only reference","expected":{"dealloc":[],"freed":[],"out":[true],"rc":{"11":[1,0],"12":[2,0]}},"passed":true},{"actual":{"dealloc":[11,12],"freed":[11,12],"out":[],"rc":{}},"check":"object referenced twice by one parent","expected":{"dealloc":[11,12],"freed":[11,12],"out":[],"rc":{}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[false],"rc":{}},"check":"upgrade after the last strong reference dies","expected":{"dealloc":[11],"freed":[11],"out":[false],"rc":{}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[false],"rc":{"12":[1,0]}},"check":"weak reference keeps the control block only","expected":{"dealloc":[11],"freed":[11],"out":[false],"rc":{"12":[1,0]}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[true],"rc":{}},"check":"dropping a weak reference to a live object","expected":{"dealloc":[11],"freed":[11],"out":[true],"rc":{}},"passed":true},{"actual":{"dealloc":[11,12,13],"freed":[11,12,13],"out":[],"rc":{}},"check":"control: chain release order","expected":{"dealloc":[11,12,13],"freed":[11,12,13],"out":[],"rc":{}},"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: overwrite with a child of the old value\", \"actual\": {\"out\": [\"use-after-free\"], \"freed\": [12, 13], \"dealloc\": [12, 13], \"rc\": {\"11\": [1, 0]}}, \"expected\": {\"dealloc\": [12], \"freed\": [12], \"out\": [], \"rc\": {\"11\": [1, 0], \"13\": [1, 0]}}, \"passed\": false}, {\"check\": \"self-assignment of the only reference\", \"actual\": {\"out\": [true], \"freed\": [], \"dealloc\": [], \"rc\": {\"11\": [1, 0], \"12\": [2, 0]}}, \"expected\": {\"dealloc\": [], \"freed\": [], \"out\": [true], \"rc\": {\"11\": [1, 0], \"12\": [2, 0]}}, \"passed\": true}, {\"check\": \"object referenced twice by one parent\", \"actual\": {\"out\": [], \"freed\": [11, 12], \"dealloc\": [11, 12], \"rc\": {}}, \"expected\": {\"dealloc\": [11, 12], \"freed\": [11, 12], \"out\": [], \"rc\": {}}, \"passed\": true}, {\"check\": \"upgrade after the last strong reference dies\", \"actual\": {\"out\": [false], \"freed\": [11], \"dealloc\": [11], \"rc\": {}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [false], \"rc\": {}}, \"passed\": true}, {\"check\": \"weak reference keeps the control block only\", \"actual\": {\"out\": [false], \"freed\": [11], \"dealloc\": [11], \"rc\": {\"12\": [1, 0]}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [false], \"rc\": {\"12\": [1, 0]}}, \"passed\": true}, {\"check\": \"dropping a weak reference to a live object\", \"actual\": {\"out\": [true], \"freed\": [11], \"dealloc\": [11], \"rc\": {}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [true], \"rc\": {}}, \"passed\": true}, {\"check\": \"control: chain release order\", \"actual\": {\"out\": [], \"freed\": [11, 12, 13], \"dealloc\": [11, 12, 13], \"rc\": {}}, \"expected\": {\"dealloc\": [11, 12, 13], \"freed\": [11, 12, 13], \"out\": [], \"rc\": {}}, \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":42.26,"exit_code":1,"observations":[{"actual":{"dealloc":[12,13],"freed":[12,13],"out":["use-after-free"],"rc":{"11":[1,0]}},"check":"regression: overwrite with a child of the old value","expected":{"dealloc":[12],"freed":[12],"out":[],"rc":{"11":[1,0],"13":[1,0]}},"passed":false},{"actual":{"dealloc":[12],"freed":[12],"out":["use-after-free"],"rc":{"11":[1,0]}},"check":"self-assignment of the only reference","expected":{"dealloc":[],"freed":[],"out":[true],"rc":{"11":[1,0],"12":[2,0]}},"passed":false},{"actual":{"dealloc":[11,12],"freed":[11,12],"out":[],"rc":{}},"check":"object referenced twice by one parent","expected":{"dealloc":[11,12],"freed":[11,12],"out":[],"rc":{}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[false],"rc":{}},"check":"upgrade after the last strong reference dies","expected":{"dealloc":[11],"freed":[11],"out":[false],"rc":{}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[false],"rc":{"12":[1,0]}},"check":"weak reference keeps the control block only","expected":{"dealloc":[11],"freed":[11],"out":[false],"rc":{"12":[1,0]}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[true],"rc":{}},"check":"dropping a weak reference to a live object","expected":{"dealloc":[11],"freed":[11],"out":[true],"rc":{}},"passed":true},{"actual":{"dealloc":[11,12,13],"freed":[11,12,13],"out":[],"rc":{}},"check":"control: chain release order","expected":{"dealloc":[11,12,13],"freed":[11,12,13],"out":[],"rc":{}},"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: overwrite with a child of the old value\", \"actual\": {\"out\": [\"use-after-free\"], \"freed\": [12, 13], \"dealloc\": [12, 13], \"rc\": {\"11\": [1, 0]}}, \"expected\": {\"dealloc\": [12], \"freed\": [12], \"out\": [], \"rc\": {\"11\": [1, 0], \"13\": [1, 0]}}, \"passed\": false}, {\"check\": \"self-assignment of the only reference\", \"actual\": {\"out\": [\"use-after-free\"], \"freed\": [12], \"dealloc\": [12], \"rc\": {\"11\": [1, 0]}}, \"expected\": {\"dealloc\": [], \"freed\": [], \"out\": [true], \"rc\": {\"11\": [1, 0], \"12\": [2, 0]}}, \"passed\": false}, {\"check\": \"object referenced twice by one parent\", \"actual\": {\"out\": [], \"freed\": [11, 12], \"dealloc\": [11, 12], \"rc\": {}}, \"expected\": {\"dealloc\": [11, 12], \"freed\": [11, 12], \"out\": [], \"rc\": {}}, \"passed\": true}, {\"check\": \"upgrade after the last strong reference dies\", \"actual\": {\"out\": [false], \"freed\": [11], \"dealloc\": [11], \"rc\": {}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [false], \"rc\": {}}, \"passed\": true}, {\"check\": \"weak reference keeps the control block only\", \"actual\": {\"out\": [false], \"freed\": [11], \"dealloc\": [11], \"rc\": {\"12\": [1, 0]}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [false], \"rc\": {\"12\": [1, 0]}}, \"passed\": true}, {\"check\": \"dropping a weak reference to a live object\", \"actual\": {\"out\": [true], \"freed\": [11], \"dealloc\": [11], \"rc\": {}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [true], \"rc\": {}}, \"passed\": true}, {\"check\": \"control: chain release order\", \"actual\": {\"out\": [], \"freed\": [11, 12, 13], \"dealloc\": [11, 12, 13], \"rc\": {}}, \"expected\": {\"dealloc\": [11, 12, 13], \"freed\": [11, 12, 13], \"out\": [], \"rc\": {}}, \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":42.38,"exit_code":0,"observations":[{"actual":{"dealloc":[12],"freed":[12],"out":[],"rc":{"11":[1,0],"13":[1,0]}},"check":"regression: overwrite with a child of the old value","expected":{"dealloc":[12],"freed":[12],"out":[],"rc":{"11":[1,0],"13":[1,0]}},"passed":true},{"actual":{"dealloc":[],"freed":[],"out":[true],"rc":{"11":[1,0],"12":[2,0]}},"check":"self-assignment of the only reference","expected":{"dealloc":[],"freed":[],"out":[true],"rc":{"11":[1,0],"12":[2,0]}},"passed":true},{"actual":{"dealloc":[11,12],"freed":[11,12],"out":[],"rc":{}},"check":"object referenced twice by one parent","expected":{"dealloc":[11,12],"freed":[11,12],"out":[],"rc":{}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[false],"rc":{}},"check":"upgrade after the last strong reference dies","expected":{"dealloc":[11],"freed":[11],"out":[false],"rc":{}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[false],"rc":{"12":[1,0]}},"check":"weak reference keeps the control block only","expected":{"dealloc":[11],"freed":[11],"out":[false],"rc":{"12":[1,0]}},"passed":true},{"actual":{"dealloc":[11],"freed":[11],"out":[true],"rc":{}},"check":"dropping a weak reference to a live object","expected":{"dealloc":[11],"freed":[11],"out":[true],"rc":{}},"passed":true},{"actual":{"dealloc":[11,12,13],"freed":[11,12,13],"out":[],"rc":{}},"check":"control: chain release order","expected":{"dealloc":[11,12,13],"freed":[11,12,13],"out":[],"rc":{}},"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: overwrite with a child of the old value\", \"actual\": {\"out\": [], \"freed\": [12], \"dealloc\": [12], \"rc\": {\"11\": [1, 0], \"13\": [1, 0]}}, \"expected\": {\"dealloc\": [12], \"freed\": [12], \"out\": [], \"rc\": {\"11\": [1, 0], \"13\": [1, 0]}}, \"passed\": true}, {\"check\": \"self-assignment of the only reference\", \"actual\": {\"out\": [true], \"freed\": [], \"dealloc\": [], \"rc\": {\"11\": [1, 0], \"12\": [2, 0]}}, \"expected\": {\"dealloc\": [], \"freed\": [], \"out\": [true], \"rc\": {\"11\": [1, 0], \"12\": [2, 0]}}, \"passed\": true}, {\"check\": \"object referenced twice by one parent\", \"actual\": {\"out\": [], \"freed\": [11, 12], \"dealloc\": [11, 12], \"rc\": {}}, \"expected\": {\"dealloc\": [11, 12], \"freed\": [11, 12], \"out\": [], \"rc\": {}}, \"passed\": true}, {\"check\": \"upgrade after the last strong reference dies\", \"actual\": {\"out\": [false], \"freed\": [11], \"dealloc\": [11], \"rc\": {}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [false], \"rc\": {}}, \"passed\": true}, {\"check\": \"weak reference keeps the control block only\", \"actual\": {\"out\": [false], \"freed\": [11], \"dealloc\": [11], \"rc\": {\"12\": [1, 0]}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [false], \"rc\": {\"12\": [1, 0]}}, \"passed\": true}, {\"check\": \"dropping a weak reference to a live object\", \"actual\": {\"out\": [true], \"freed\": [11], \"dealloc\": [11], \"rc\": {}}, \"expected\": {\"dealloc\": [11], \"freed\": [11], \"out\": [true], \"rc\": {}}, \"passed\": true}, {\"check\": \"control: chain release order\", \"actual\": {\"out\": [], \"freed\": [11, 12, 13], \"dealloc\": [11, 12, 13], \"rc\": {}}, \"expected\": {\"dealloc\": [11, 12, 13], \"freed\": [11, 12, 13], \"out\": [], \"rc\": {}}, \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}