FA-43236 / Borrow checking / Open access
A variant-specific suspension loan is treated as live in every frame state · case 01
A variant-specific suspension loan is treated as live in every frame state.
ROOT CAUSE
The static analyzer mishandles variant separation: a variant-specific suspension loan is treated as live in every frame state.
VERIFIED REPAIR
Apply the specified transfer or inference rule at this site: if any(v!=d['active_variant'] and bool(set(ls)&set(d['common_loans'])) for v,ls in d['variant_loans'].items()): errors.append('variant-separation').
Unsuccessful approach: The partial repair uses if any(v!=d['active_variant'] and len(set(ls)&set(d['common_loans']))>1 for v,ls in d['variant_loans'].items()): errors.append('variant-separation'), which still violates the stipulated analysis contract.
Case contract
Validate static generator suspension descriptors. Live borrowed stack origins must be stored in the frame; movable frames cannot retain self references; pinned self references require pinned projection; a saved unique loan cannot have external aliases; suspension-disallowed guards cannot cross yield; resumed references must survive every resume point; cancellation drop order releases borrowers before owners; references returned by a completed generator cannot target its frame; loans killed before yield must not be saved; mutually exclusive variants require variant-specific frame loans. Input is a fully explicit descriptor of the stated toy IR. Return rule identifiers in declaration order; absent optional obligations use the provided neutral defaults. No rule is an assertion about a production language.
Why this case matters
A finite offline static-analysis model of ownership and borrowing; it does not execute the analyzed program.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(d):
errors=[]
if not set(d['live_origins'])<=set(d['frame_slots']): errors.append('frame-promotion')
if d['movable'] and bool(d['self_refs']): errors.append('self-move')
if not set(d['self_refs'])<=set(d['pinned']): errors.append('pin-projection')
if bool(set(d['unique_saved'])&set(d['external_aliases'])): errors.append('suspended-unique-alias')
if bool(set(d['guards'])&set(d['suspend_disallowed'])): errors.append('guard-yield')
if not set(d['resume'])<=set(d['valid']): errors.append('resume-lifetime')
if any(d['drop_order'].index(b)>d['drop_order'].index(o) for b,o in d['dependencies']): errors.append('cancel-drop-order')
if d['completed'] and bool(set(d['returned'])&set(d['frame_slots'])): errors.append('completed-frame-return')
if bool(set(d['saved'])&set(d['killed'])): errors.append('dead-loan-spill')
if False: errors.append('variant-separation')
return errors
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
base={'live_origins': [], 'frame_slots': [], 'self_refs': [], 'movable': False, 'pinned': [], 'unique_saved': [], 'external_aliases': [], 'guards': [], 'suspend_disallowed': [], 'resume': [], 'valid': [], 'drop_order': [], 'dependencies': [], 'returned': [], 'completed': False, 'saved': [], 'killed': [], 'variant_loans': {}, 'active_variant': None, 'common_loans': []}
check('well formed empty obligations',solve(base),[])
check('frame-promotion regression 0', solve(dict(base, **({'live_origins':['a','b'],'frame_slots':['a']}))), ['frame-promotion'])
check('frame-promotion regression 1', solve(dict(base, **({'live_origins':['a',N],'frame_slots':['a']}))), ['frame-promotion'])
check('self-move regression 0', solve(dict(base, **({'movable':True,'self_refs':['r'],'pinned':['r']}))), ['self-move'])
check('self-move regression 1', solve(dict(base, **({'movable':True,'self_refs':[N],'pinned':[N]}))), ['self-move'])
check('pin-projection regression 0', solve(dict(base, **({'self_refs':['a','b'],'pinned':['a']}))), ['pin-projection'])
check('pin-projection regression 1', solve(dict(base, **({'self_refs':[N],'pinned':[N+1]}))), ['pin-projection'])
check('suspended-unique-alias regression 0', solve(dict(base, **({'unique_saved':['a'],'external_aliases':['a']}))), ['suspended-unique-alias'])
check('suspended-unique-alias regression 1', solve(dict(base, **({'unique_saved':[N],'external_aliases':[N]}))), ['suspended-unique-alias'])
check('guard-yield regression 0', solve(dict(base, **({'guards':['a','b'],'suspend_disallowed':['b']}))), ['guard-yield'])
check('guard-yield regression 1', solve(dict(base, **({'guards':['a',N],'suspend_disallowed':[N]}))), ['guard-yield'])
check('resume-lifetime regression 0', solve(dict(base, **({'resume':[N],'valid':[N+1]}))), ['resume-lifetime'])
check('resume-lifetime regression 1', solve(dict(base, **({'resume':[N,N+1],'valid':[N+1,N+2]}))), ['resume-lifetime'])
check('cancel-drop-order regression 0', solve(dict(base, **({'drop_order':['o','b'],'dependencies':[('b','o')]}))), ['cancel-drop-order'])
check('cancel-drop-order regression 1', solve(dict(base, **({'drop_order':['x','o','b'],'dependencies':[('b','o')]}))), ['cancel-drop-order'])
check('completed-frame-return regression 0', solve(dict(base, **({'completed':True,'returned':['x','r'],'frame_slots':['r']}))), ['completed-frame-return'])
check('completed-frame-return regression 1', solve(dict(base, **({'completed':True,'returned':['x',N],'frame_slots':[N]}))), ['completed-frame-return'])
check('dead-loan-spill regression 0', solve(dict(base, **({'saved':['a','b'],'killed':['b']}))), ['dead-loan-spill'])
check('dead-loan-spill regression 1', solve(dict(base, **({'saved':[N,N+1],'killed':[N+1]}))), ['dead-loan-spill'])
check('variant-separation regression 0', solve(dict(base, **({'active_variant':'a','variant_loans':{'b':['r']},'common_loans':['r']}))), ['variant-separation'])
check('variant-separation regression 1', solve(dict(base, **({'active_variant':N,'variant_loans':{N+1:['r']},'common_loans':['r']}))), ['variant-separation'])
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| well formed empty obligations | [] | [] | Passed |
| frame-promotion regression 0 | ['frame-promotion'] | ['frame-promotion'] | Passed |
| frame-promotion regression 1 | ['frame-promotion'] | ['frame-promotion'] | Passed |
| self-move regression 0 | ['self-move'] | ['self-move'] | Passed |
| self-move regression 1 | ['self-move'] | ['self-move'] | Passed |
| pin-projection regression 0 | ['pin-projection'] | ['pin-projection'] | Passed |
| pin-projection regression 1 | ['pin-projection'] | ['pin-projection'] | Passed |
| suspended-unique-alias regression 0 | ['suspended-unique-alias'] | ['suspended-unique-alias'] | Passed |
| suspended-unique-alias regression 1 | ['suspended-unique-alias'] | ['suspended-unique-alias'] | Passed |
| guard-yield regression 0 | ['guard-yield'] | ['guard-yield'] | Passed |
| guard-yield regression 1 | ['guard-yield'] | ['guard-yield'] | Passed |
| resume-lifetime regression 0 | ['resume-lifetime'] | ['resume-lifetime'] | Passed |
| resume-lifetime regression 1 | ['resume-lifetime'] | ['resume-lifetime'] | Passed |
| cancel-drop-order regression 0 | ['cancel-drop-order'] | ['cancel-drop-order'] | Passed |
| cancel-drop-order regression 1 | ['cancel-drop-order'] | ['cancel-drop-order'] | Passed |
| completed-frame-return regression 0 | ['completed-frame-return'] | ['completed-frame-return'] | Passed |
| completed-frame-return regression 1 | ['completed-frame-return'] | ['completed-frame-return'] | Passed |
| dead-loan-spill regression 0 | ['dead-loan-spill'] | ['dead-loan-spill'] | Passed |
| dead-loan-spill regression 1 | ['dead-loan-spill'] | ['dead-loan-spill'] | Passed |
| variant-separation regression 0 | [] | ['variant-separation'] | Failed |
| variant-separation regression 1 | [] | ['variant-separation'] | Failed |
SHA-256 / 39bc6b0e140cca680e5bb473dc87e947fc15b0f8f28e898dcbe9cf7980cadc93
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(d):
errors=[]
if not set(d['live_origins'])<=set(d['frame_slots']): errors.append('frame-promotion')
if d['movable'] and bool(d['self_refs']): errors.append('self-move')
if not set(d['self_refs'])<=set(d['pinned']): errors.append('pin-projection')
if bool(set(d['unique_saved'])&set(d['external_aliases'])): errors.append('suspended-unique-alias')
if bool(set(d['guards'])&set(d['suspend_disallowed'])): errors.append('guard-yield')
if not set(d['resume'])<=set(d['valid']): errors.append('resume-lifetime')
if any(d['drop_order'].index(b)>d['drop_order'].index(o) for b,o in d['dependencies']): errors.append('cancel-drop-order')
if d['completed'] and bool(set(d['returned'])&set(d['frame_slots'])): errors.append('completed-frame-return')
if bool(set(d['saved'])&set(d['killed'])): errors.append('dead-loan-spill')
if any(v!=d['active_variant'] and len(set(ls)&set(d['common_loans']))>1 for v,ls in d['variant_loans'].items()): errors.append('variant-separation')
return errors
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
base={'live_origins': [], 'frame_slots': [], 'self_refs': [], 'movable': False, 'pinned': [], 'unique_saved': [], 'external_aliases': [], 'guards': [], 'suspend_disallowed': [], 'resume': [], 'valid': [], 'drop_order': [], 'dependencies': [], 'returned': [], 'completed': False, 'saved': [], 'killed': [], 'variant_loans': {}, 'active_variant': None, 'common_loans': []}
check('well formed empty obligations',solve(base),[])
check('frame-promotion regression 0', solve(dict(base, **({'live_origins':['a','b'],'frame_slots':['a']}))), ['frame-promotion'])
check('frame-promotion regression 1', solve(dict(base, **({'live_origins':['a',N],'frame_slots':['a']}))), ['frame-promotion'])
check('self-move regression 0', solve(dict(base, **({'movable':True,'self_refs':['r'],'pinned':['r']}))), ['self-move'])
check('self-move regression 1', solve(dict(base, **({'movable':True,'self_refs':[N],'pinned':[N]}))), ['self-move'])
check('pin-projection regression 0', solve(dict(base, **({'self_refs':['a','b'],'pinned':['a']}))), ['pin-projection'])
check('pin-projection regression 1', solve(dict(base, **({'self_refs':[N],'pinned':[N+1]}))), ['pin-projection'])
check('suspended-unique-alias regression 0', solve(dict(base, **({'unique_saved':['a'],'external_aliases':['a']}))), ['suspended-unique-alias'])
check('suspended-unique-alias regression 1', solve(dict(base, **({'unique_saved':[N],'external_aliases':[N]}))), ['suspended-unique-alias'])
check('guard-yield regression 0', solve(dict(base, **({'guards':['a','b'],'suspend_disallowed':['b']}))), ['guard-yield'])
check('guard-yield regression 1', solve(dict(base, **({'guards':['a',N],'suspend_disallowed':[N]}))), ['guard-yield'])
check('resume-lifetime regression 0', solve(dict(base, **({'resume':[N],'valid':[N+1]}))), ['resume-lifetime'])
check('resume-lifetime regression 1', solve(dict(base, **({'resume':[N,N+1],'valid':[N+1,N+2]}))), ['resume-lifetime'])
check('cancel-drop-order regression 0', solve(dict(base, **({'drop_order':['o','b'],'dependencies':[('b','o')]}))), ['cancel-drop-order'])
check('cancel-drop-order regression 1', solve(dict(base, **({'drop_order':['x','o','b'],'dependencies':[('b','o')]}))), ['cancel-drop-order'])
check('completed-frame-return regression 0', solve(dict(base, **({'completed':True,'returned':['x','r'],'frame_slots':['r']}))), ['completed-frame-return'])
check('completed-frame-return regression 1', solve(dict(base, **({'completed':True,'returned':['x',N],'frame_slots':[N]}))), ['completed-frame-return'])
check('dead-loan-spill regression 0', solve(dict(base, **({'saved':['a','b'],'killed':['b']}))), ['dead-loan-spill'])
check('dead-loan-spill regression 1', solve(dict(base, **({'saved':[N,N+1],'killed':[N+1]}))), ['dead-loan-spill'])
check('variant-separation regression 0', solve(dict(base, **({'active_variant':'a','variant_loans':{'b':['r']},'common_loans':['r']}))), ['variant-separation'])
check('variant-separation regression 1', solve(dict(base, **({'active_variant':N,'variant_loans':{N+1:['r']},'common_loans':['r']}))), ['variant-separation'])
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| well formed empty obligations | [] | [] | Passed |
| frame-promotion regression 0 | ['frame-promotion'] | ['frame-promotion'] | Passed |
| frame-promotion regression 1 | ['frame-promotion'] | ['frame-promotion'] | Passed |
| self-move regression 0 | ['self-move'] | ['self-move'] | Passed |
| self-move regression 1 | ['self-move'] | ['self-move'] | Passed |
| pin-projection regression 0 | ['pin-projection'] | ['pin-projection'] | Passed |
| pin-projection regression 1 | ['pin-projection'] | ['pin-projection'] | Passed |
| suspended-unique-alias regression 0 | ['suspended-unique-alias'] | ['suspended-unique-alias'] | Passed |
| suspended-unique-alias regression 1 | ['suspended-unique-alias'] | ['suspended-unique-alias'] | Passed |
| guard-yield regression 0 | ['guard-yield'] | ['guard-yield'] | Passed |
| guard-yield regression 1 | ['guard-yield'] | ['guard-yield'] | Passed |
| resume-lifetime regression 0 | ['resume-lifetime'] | ['resume-lifetime'] | Passed |
| resume-lifetime regression 1 | ['resume-lifetime'] | ['resume-lifetime'] | Passed |
| cancel-drop-order regression 0 | ['cancel-drop-order'] | ['cancel-drop-order'] | Passed |
| cancel-drop-order regression 1 | ['cancel-drop-order'] | ['cancel-drop-order'] | Passed |
| completed-frame-return regression 0 | ['completed-frame-return'] | ['completed-frame-return'] | Passed |
| completed-frame-return regression 1 | ['completed-frame-return'] | ['completed-frame-return'] | Passed |
| dead-loan-spill regression 0 | ['dead-loan-spill'] | ['dead-loan-spill'] | Passed |
| dead-loan-spill regression 1 | ['dead-loan-spill'] | ['dead-loan-spill'] | Passed |
| variant-separation regression 0 | [] | ['variant-separation'] | Failed |
| variant-separation regression 1 | [] | ['variant-separation'] | Failed |
SHA-256 / 66e7ad3ad679caebf2ce9ddc055123e564828ff7d5fcccf5be47e9ebcad57c1c
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(d):
errors=[]
if not set(d['live_origins'])<=set(d['frame_slots']): errors.append('frame-promotion')
if d['movable'] and bool(d['self_refs']): errors.append('self-move')
if not set(d['self_refs'])<=set(d['pinned']): errors.append('pin-projection')
if bool(set(d['unique_saved'])&set(d['external_aliases'])): errors.append('suspended-unique-alias')
if bool(set(d['guards'])&set(d['suspend_disallowed'])): errors.append('guard-yield')
if not set(d['resume'])<=set(d['valid']): errors.append('resume-lifetime')
if any(d['drop_order'].index(b)>d['drop_order'].index(o) for b,o in d['dependencies']): errors.append('cancel-drop-order')
if d['completed'] and bool(set(d['returned'])&set(d['frame_slots'])): errors.append('completed-frame-return')
if bool(set(d['saved'])&set(d['killed'])): errors.append('dead-loan-spill')
if any(v!=d['active_variant'] and bool(set(ls)&set(d['common_loans'])) for v,ls in d['variant_loans'].items()): errors.append('variant-separation')
return errors
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
base={'live_origins': [], 'frame_slots': [], 'self_refs': [], 'movable': False, 'pinned': [], 'unique_saved': [], 'external_aliases': [], 'guards': [], 'suspend_disallowed': [], 'resume': [], 'valid': [], 'drop_order': [], 'dependencies': [], 'returned': [], 'completed': False, 'saved': [], 'killed': [], 'variant_loans': {}, 'active_variant': None, 'common_loans': []}
check('well formed empty obligations',solve(base),[])
check('frame-promotion regression 0', solve(dict(base, **({'live_origins':['a','b'],'frame_slots':['a']}))), ['frame-promotion'])
check('frame-promotion regression 1', solve(dict(base, **({'live_origins':['a',N],'frame_slots':['a']}))), ['frame-promotion'])
check('self-move regression 0', solve(dict(base, **({'movable':True,'self_refs':['r'],'pinned':['r']}))), ['self-move'])
check('self-move regression 1', solve(dict(base, **({'movable':True,'self_refs':[N],'pinned':[N]}))), ['self-move'])
check('pin-projection regression 0', solve(dict(base, **({'self_refs':['a','b'],'pinned':['a']}))), ['pin-projection'])
check('pin-projection regression 1', solve(dict(base, **({'self_refs':[N],'pinned':[N+1]}))), ['pin-projection'])
check('suspended-unique-alias regression 0', solve(dict(base, **({'unique_saved':['a'],'external_aliases':['a']}))), ['suspended-unique-alias'])
check('suspended-unique-alias regression 1', solve(dict(base, **({'unique_saved':[N],'external_aliases':[N]}))), ['suspended-unique-alias'])
check('guard-yield regression 0', solve(dict(base, **({'guards':['a','b'],'suspend_disallowed':['b']}))), ['guard-yield'])
check('guard-yield regression 1', solve(dict(base, **({'guards':['a',N],'suspend_disallowed':[N]}))), ['guard-yield'])
check('resume-lifetime regression 0', solve(dict(base, **({'resume':[N],'valid':[N+1]}))), ['resume-lifetime'])
check('resume-lifetime regression 1', solve(dict(base, **({'resume':[N,N+1],'valid':[N+1,N+2]}))), ['resume-lifetime'])
check('cancel-drop-order regression 0', solve(dict(base, **({'drop_order':['o','b'],'dependencies':[('b','o')]}))), ['cancel-drop-order'])
check('cancel-drop-order regression 1', solve(dict(base, **({'drop_order':['x','o','b'],'dependencies':[('b','o')]}))), ['cancel-drop-order'])
check('completed-frame-return regression 0', solve(dict(base, **({'completed':True,'returned':['x','r'],'frame_slots':['r']}))), ['completed-frame-return'])
check('completed-frame-return regression 1', solve(dict(base, **({'completed':True,'returned':['x',N],'frame_slots':[N]}))), ['completed-frame-return'])
check('dead-loan-spill regression 0', solve(dict(base, **({'saved':['a','b'],'killed':['b']}))), ['dead-loan-spill'])
check('dead-loan-spill regression 1', solve(dict(base, **({'saved':[N,N+1],'killed':[N+1]}))), ['dead-loan-spill'])
check('variant-separation regression 0', solve(dict(base, **({'active_variant':'a','variant_loans':{'b':['r']},'common_loans':['r']}))), ['variant-separation'])
check('variant-separation regression 1', solve(dict(base, **({'active_variant':N,'variant_loans':{N+1:['r']},'common_loans':['r']}))), ['variant-separation'])
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| well formed empty obligations | [] | [] | Passed |
| frame-promotion regression 0 | ['frame-promotion'] | ['frame-promotion'] | Passed |
| frame-promotion regression 1 | ['frame-promotion'] | ['frame-promotion'] | Passed |
| self-move regression 0 | ['self-move'] | ['self-move'] | Passed |
| self-move regression 1 | ['self-move'] | ['self-move'] | Passed |
| pin-projection regression 0 | ['pin-projection'] | ['pin-projection'] | Passed |
| pin-projection regression 1 | ['pin-projection'] | ['pin-projection'] | Passed |
| suspended-unique-alias regression 0 | ['suspended-unique-alias'] | ['suspended-unique-alias'] | Passed |
| suspended-unique-alias regression 1 | ['suspended-unique-alias'] | ['suspended-unique-alias'] | Passed |
| guard-yield regression 0 | ['guard-yield'] | ['guard-yield'] | Passed |
| guard-yield regression 1 | ['guard-yield'] | ['guard-yield'] | Passed |
| resume-lifetime regression 0 | ['resume-lifetime'] | ['resume-lifetime'] | Passed |
| resume-lifetime regression 1 | ['resume-lifetime'] | ['resume-lifetime'] | Passed |
| cancel-drop-order regression 0 | ['cancel-drop-order'] | ['cancel-drop-order'] | Passed |
| cancel-drop-order regression 1 | ['cancel-drop-order'] | ['cancel-drop-order'] | Passed |
| completed-frame-return regression 0 | ['completed-frame-return'] | ['completed-frame-return'] | Passed |
| completed-frame-return regression 1 | ['completed-frame-return'] | ['completed-frame-return'] | Passed |
| dead-loan-spill regression 0 | ['dead-loan-spill'] | ['dead-loan-spill'] | Passed |
| dead-loan-spill regression 1 | ['dead-loan-spill'] | ['dead-loan-spill'] | Passed |
| variant-separation regression 0 | ['variant-separation'] | ['variant-separation'] | Passed |
| variant-separation regression 1 | ['variant-separation'] | ['variant-separation'] | Passed |
SHA-256 / 684d3fc28a8f7e28246833cdfe2fd0838ad7fbcf930d67ade0a7b02e8d3d2abb
Verification & scope
The explicitly stated toy language is the complete scope; this is not a production compiler or a claim about Rust semantics. 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:43:59.796072+00:00.
Case digest / 20615f60b390078a2304df3f318b1fff901f1b96208d16ab1a6ff89da4410c8c