FA-44191 / Borrow checking / Open access
Generic instantiation silently ignores excess lifetime arguments · case 01
Generic instantiation silently ignores excess lifetime arguments.
ROOT CAUSE
The static analyzer mishandles lifetime arity: generic instantiation silently ignores excess lifetime arguments.
VERIFIED REPAIR
Apply the specified transfer or inference rule at this site: if len(d['params'])!=len(d['args']): errors.append('lifetime-arity').
Unsuccessful approach: The partial repair uses if len(d['params'])>len(d['args']): errors.append('lifetime-arity'), which still violates the stipulated analysis contract.
Case contract
Check generic borrow-summary instantiation. Generic lifetime arguments match parameter arity; parameter substitution is positional; repeated occurrences substitute consistently; recursive instantiation uses each callee actual mapping; static lifetime is not substituted; inferred anonymous lifetimes are fresh per call; where-outlives obligations instantiated in declared direction; associated lifetime applications include all type arguments; recursive summary fixed point cannot be accepted while new obligations remain; monomorphized reference types retain lifetime proof metadata. 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 False: errors.append('lifetime-arity')
if d['expected_mapping']!=d['actual_mapping']: errors.append('positional-substitution')
if any(len(set(xs))>1 for xs in d['occurrences'].values()): errors.append('repeated-substitution')
if d['recursive_expected']!=d['recursive_actual']: errors.append('recursive-actual-map')
if d['static_before']!=d['static_after']: errors.append('static-preservation')
if len(d['anonymous_calls'])==len(d['anonymous_ids']) and len(set(d['anonymous_ids']))!=len(d['anonymous_ids']): errors.append('anonymous-freshness')
if set(map(tuple,d['expected_outlives']))!=set(map(tuple,d['actual_outlives'])): errors.append('where-direction')
if d['associated_args']!=d['recorded_args']: errors.append('associated-arguments')
if d['accepted'] and bool(d['pending']): errors.append('summary-fixed-point')
if not set(d['reference_types'])<=set(d['proof_metadata']): errors.append('erased-proof-metadata')
return errors
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
base={'params': [], 'args': [], 'expected_mapping': {}, 'actual_mapping': {}, 'occurrences': {}, 'recursive_expected': {}, 'recursive_actual': {}, 'static_before': None, 'static_after': None, 'anonymous_calls': [], 'anonymous_ids': [], 'expected_outlives': [], 'actual_outlives': [], 'associated_args': [], 'recorded_args': [], 'pending': [], 'accepted': False, 'reference_types': [], 'proof_metadata': []}
check('well formed empty obligations',solve(base),[])
check('lifetime-arity regression 0', solve(dict(base, **({'params':['a'],'args':['x','y']}))), ['lifetime-arity'])
check('lifetime-arity regression 1', solve(dict(base, **({'params':[N],'args':[N,N+1]}))), ['lifetime-arity'])
check('positional-substitution regression 0', solve(dict(base, **({'expected_mapping':{'a':'x','b':'y'},'actual_mapping':{'a':'y','b':'x'}}))), ['positional-substitution'])
check('positional-substitution regression 1', solve(dict(base, **({'expected_mapping':{'a':N,'b':N+1},'actual_mapping':{'a':N+1,'b':N}}))), ['positional-substitution'])
check('repeated-substitution regression 0', solve(dict(base, **({'occurrences':{'a':['x','y']}}))), ['repeated-substitution'])
check('repeated-substitution regression 1', solve(dict(base, **({'occurrences':{'a':[N,N+1]}}))), ['repeated-substitution'])
check('recursive-actual-map regression 0', solve(dict(base, **({'recursive_expected':{'call':'b'},'recursive_actual':{'call':'a'}}))), ['recursive-actual-map'])
check('recursive-actual-map regression 1', solve(dict(base, **({'recursive_expected':{'call':N+1},'recursive_actual':{'call':N}}))), ['recursive-actual-map'])
check('static-preservation regression 0', solve(dict(base, **({'static_before':'static','static_after':'a'}))), ['static-preservation'])
check('static-preservation regression 1', solve(dict(base, **({'static_before':'static','static_after':N}))), ['static-preservation'])
check('anonymous-freshness regression 0', solve(dict(base, **({'anonymous_calls':['c1','c2'],'anonymous_ids':['r','r']}))), ['anonymous-freshness'])
check('anonymous-freshness regression 1', solve(dict(base, **({'anonymous_calls':[N,N+1],'anonymous_ids':[0,0]}))), ['anonymous-freshness'])
check('where-direction regression 0', solve(dict(base, **({'expected_outlives':[('a','b')],'actual_outlives':[('b','a')]}))), ['where-direction'])
check('where-direction regression 1', solve(dict(base, **({'expected_outlives':[(N,N+1)],'actual_outlives':[(N+1,N)]}))), ['where-direction'])
check('associated-arguments regression 0', solve(dict(base, **({'associated_args':['a','b'],'recorded_args':['b','a']}))), ['associated-arguments'])
check('associated-arguments regression 1', solve(dict(base, **({'associated_args':[N,N+1],'recorded_args':[N+1,N]}))), ['associated-arguments'])
check('summary-fixed-point regression 0', solve(dict(base, **({'accepted':True,'pending':['a']}))), ['summary-fixed-point'])
check('summary-fixed-point regression 1', solve(dict(base, **({'accepted':True,'pending':[N]}))), ['summary-fixed-point'])
check('erased-proof-metadata regression 0', solve(dict(base, **({'reference_types':['a','b'],'proof_metadata':['a']}))), ['erased-proof-metadata'])
check('erased-proof-metadata regression 1', solve(dict(base, **({'reference_types':[N,N+1],'proof_metadata':[N]}))), ['erased-proof-metadata'])
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 |
| lifetime-arity regression 0 | [] | ['lifetime-arity'] | Failed |
| lifetime-arity regression 1 | [] | ['lifetime-arity'] | Failed |
| positional-substitution regression 0 | ['positional-substitution'] | ['positional-substitution'] | Passed |
| positional-substitution regression 1 | ['positional-substitution'] | ['positional-substitution'] | Passed |
| repeated-substitution regression 0 | ['repeated-substitution'] | ['repeated-substitution'] | Passed |
| repeated-substitution regression 1 | ['repeated-substitution'] | ['repeated-substitution'] | Passed |
| recursive-actual-map regression 0 | ['recursive-actual-map'] | ['recursive-actual-map'] | Passed |
| recursive-actual-map regression 1 | ['recursive-actual-map'] | ['recursive-actual-map'] | Passed |
| static-preservation regression 0 | ['static-preservation'] | ['static-preservation'] | Passed |
| static-preservation regression 1 | ['static-preservation'] | ['static-preservation'] | Passed |
| anonymous-freshness regression 0 | ['anonymous-freshness'] | ['anonymous-freshness'] | Passed |
| anonymous-freshness regression 1 | ['anonymous-freshness'] | ['anonymous-freshness'] | Passed |
| where-direction regression 0 | ['where-direction'] | ['where-direction'] | Passed |
| where-direction regression 1 | ['where-direction'] | ['where-direction'] | Passed |
| associated-arguments regression 0 | ['associated-arguments'] | ['associated-arguments'] | Passed |
| associated-arguments regression 1 | ['associated-arguments'] | ['associated-arguments'] | Passed |
| summary-fixed-point regression 0 | ['summary-fixed-point'] | ['summary-fixed-point'] | Passed |
| summary-fixed-point regression 1 | ['summary-fixed-point'] | ['summary-fixed-point'] | Passed |
| erased-proof-metadata regression 0 | ['erased-proof-metadata'] | ['erased-proof-metadata'] | Passed |
| erased-proof-metadata regression 1 | ['erased-proof-metadata'] | ['erased-proof-metadata'] | Passed |
SHA-256 / ef680187f63a303064a5ba6c623e7a6f27ba873397973a725fb1a8c949ac9c7e
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(d):
errors=[]
if len(d['params'])>len(d['args']): errors.append('lifetime-arity')
if d['expected_mapping']!=d['actual_mapping']: errors.append('positional-substitution')
if any(len(set(xs))>1 for xs in d['occurrences'].values()): errors.append('repeated-substitution')
if d['recursive_expected']!=d['recursive_actual']: errors.append('recursive-actual-map')
if d['static_before']!=d['static_after']: errors.append('static-preservation')
if len(d['anonymous_calls'])==len(d['anonymous_ids']) and len(set(d['anonymous_ids']))!=len(d['anonymous_ids']): errors.append('anonymous-freshness')
if set(map(tuple,d['expected_outlives']))!=set(map(tuple,d['actual_outlives'])): errors.append('where-direction')
if d['associated_args']!=d['recorded_args']: errors.append('associated-arguments')
if d['accepted'] and bool(d['pending']): errors.append('summary-fixed-point')
if not set(d['reference_types'])<=set(d['proof_metadata']): errors.append('erased-proof-metadata')
return errors
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
base={'params': [], 'args': [], 'expected_mapping': {}, 'actual_mapping': {}, 'occurrences': {}, 'recursive_expected': {}, 'recursive_actual': {}, 'static_before': None, 'static_after': None, 'anonymous_calls': [], 'anonymous_ids': [], 'expected_outlives': [], 'actual_outlives': [], 'associated_args': [], 'recorded_args': [], 'pending': [], 'accepted': False, 'reference_types': [], 'proof_metadata': []}
check('well formed empty obligations',solve(base),[])
check('lifetime-arity regression 0', solve(dict(base, **({'params':['a'],'args':['x','y']}))), ['lifetime-arity'])
check('lifetime-arity regression 1', solve(dict(base, **({'params':[N],'args':[N,N+1]}))), ['lifetime-arity'])
check('positional-substitution regression 0', solve(dict(base, **({'expected_mapping':{'a':'x','b':'y'},'actual_mapping':{'a':'y','b':'x'}}))), ['positional-substitution'])
check('positional-substitution regression 1', solve(dict(base, **({'expected_mapping':{'a':N,'b':N+1},'actual_mapping':{'a':N+1,'b':N}}))), ['positional-substitution'])
check('repeated-substitution regression 0', solve(dict(base, **({'occurrences':{'a':['x','y']}}))), ['repeated-substitution'])
check('repeated-substitution regression 1', solve(dict(base, **({'occurrences':{'a':[N,N+1]}}))), ['repeated-substitution'])
check('recursive-actual-map regression 0', solve(dict(base, **({'recursive_expected':{'call':'b'},'recursive_actual':{'call':'a'}}))), ['recursive-actual-map'])
check('recursive-actual-map regression 1', solve(dict(base, **({'recursive_expected':{'call':N+1},'recursive_actual':{'call':N}}))), ['recursive-actual-map'])
check('static-preservation regression 0', solve(dict(base, **({'static_before':'static','static_after':'a'}))), ['static-preservation'])
check('static-preservation regression 1', solve(dict(base, **({'static_before':'static','static_after':N}))), ['static-preservation'])
check('anonymous-freshness regression 0', solve(dict(base, **({'anonymous_calls':['c1','c2'],'anonymous_ids':['r','r']}))), ['anonymous-freshness'])
check('anonymous-freshness regression 1', solve(dict(base, **({'anonymous_calls':[N,N+1],'anonymous_ids':[0,0]}))), ['anonymous-freshness'])
check('where-direction regression 0', solve(dict(base, **({'expected_outlives':[('a','b')],'actual_outlives':[('b','a')]}))), ['where-direction'])
check('where-direction regression 1', solve(dict(base, **({'expected_outlives':[(N,N+1)],'actual_outlives':[(N+1,N)]}))), ['where-direction'])
check('associated-arguments regression 0', solve(dict(base, **({'associated_args':['a','b'],'recorded_args':['b','a']}))), ['associated-arguments'])
check('associated-arguments regression 1', solve(dict(base, **({'associated_args':[N,N+1],'recorded_args':[N+1,N]}))), ['associated-arguments'])
check('summary-fixed-point regression 0', solve(dict(base, **({'accepted':True,'pending':['a']}))), ['summary-fixed-point'])
check('summary-fixed-point regression 1', solve(dict(base, **({'accepted':True,'pending':[N]}))), ['summary-fixed-point'])
check('erased-proof-metadata regression 0', solve(dict(base, **({'reference_types':['a','b'],'proof_metadata':['a']}))), ['erased-proof-metadata'])
check('erased-proof-metadata regression 1', solve(dict(base, **({'reference_types':[N,N+1],'proof_metadata':[N]}))), ['erased-proof-metadata'])
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 |
| lifetime-arity regression 0 | [] | ['lifetime-arity'] | Failed |
| lifetime-arity regression 1 | [] | ['lifetime-arity'] | Failed |
| positional-substitution regression 0 | ['positional-substitution'] | ['positional-substitution'] | Passed |
| positional-substitution regression 1 | ['positional-substitution'] | ['positional-substitution'] | Passed |
| repeated-substitution regression 0 | ['repeated-substitution'] | ['repeated-substitution'] | Passed |
| repeated-substitution regression 1 | ['repeated-substitution'] | ['repeated-substitution'] | Passed |
| recursive-actual-map regression 0 | ['recursive-actual-map'] | ['recursive-actual-map'] | Passed |
| recursive-actual-map regression 1 | ['recursive-actual-map'] | ['recursive-actual-map'] | Passed |
| static-preservation regression 0 | ['static-preservation'] | ['static-preservation'] | Passed |
| static-preservation regression 1 | ['static-preservation'] | ['static-preservation'] | Passed |
| anonymous-freshness regression 0 | ['anonymous-freshness'] | ['anonymous-freshness'] | Passed |
| anonymous-freshness regression 1 | ['anonymous-freshness'] | ['anonymous-freshness'] | Passed |
| where-direction regression 0 | ['where-direction'] | ['where-direction'] | Passed |
| where-direction regression 1 | ['where-direction'] | ['where-direction'] | Passed |
| associated-arguments regression 0 | ['associated-arguments'] | ['associated-arguments'] | Passed |
| associated-arguments regression 1 | ['associated-arguments'] | ['associated-arguments'] | Passed |
| summary-fixed-point regression 0 | ['summary-fixed-point'] | ['summary-fixed-point'] | Passed |
| summary-fixed-point regression 1 | ['summary-fixed-point'] | ['summary-fixed-point'] | Passed |
| erased-proof-metadata regression 0 | ['erased-proof-metadata'] | ['erased-proof-metadata'] | Passed |
| erased-proof-metadata regression 1 | ['erased-proof-metadata'] | ['erased-proof-metadata'] | Passed |
SHA-256 / 73f16afddfd09435b6bed353b2b411a6c8d2df33fa4afc80a8a5bf84a718ec6a
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(d):
errors=[]
if len(d['params'])!=len(d['args']): errors.append('lifetime-arity')
if d['expected_mapping']!=d['actual_mapping']: errors.append('positional-substitution')
if any(len(set(xs))>1 for xs in d['occurrences'].values()): errors.append('repeated-substitution')
if d['recursive_expected']!=d['recursive_actual']: errors.append('recursive-actual-map')
if d['static_before']!=d['static_after']: errors.append('static-preservation')
if len(d['anonymous_calls'])==len(d['anonymous_ids']) and len(set(d['anonymous_ids']))!=len(d['anonymous_ids']): errors.append('anonymous-freshness')
if set(map(tuple,d['expected_outlives']))!=set(map(tuple,d['actual_outlives'])): errors.append('where-direction')
if d['associated_args']!=d['recorded_args']: errors.append('associated-arguments')
if d['accepted'] and bool(d['pending']): errors.append('summary-fixed-point')
if not set(d['reference_types'])<=set(d['proof_metadata']): errors.append('erased-proof-metadata')
return errors
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
base={'params': [], 'args': [], 'expected_mapping': {}, 'actual_mapping': {}, 'occurrences': {}, 'recursive_expected': {}, 'recursive_actual': {}, 'static_before': None, 'static_after': None, 'anonymous_calls': [], 'anonymous_ids': [], 'expected_outlives': [], 'actual_outlives': [], 'associated_args': [], 'recorded_args': [], 'pending': [], 'accepted': False, 'reference_types': [], 'proof_metadata': []}
check('well formed empty obligations',solve(base),[])
check('lifetime-arity regression 0', solve(dict(base, **({'params':['a'],'args':['x','y']}))), ['lifetime-arity'])
check('lifetime-arity regression 1', solve(dict(base, **({'params':[N],'args':[N,N+1]}))), ['lifetime-arity'])
check('positional-substitution regression 0', solve(dict(base, **({'expected_mapping':{'a':'x','b':'y'},'actual_mapping':{'a':'y','b':'x'}}))), ['positional-substitution'])
check('positional-substitution regression 1', solve(dict(base, **({'expected_mapping':{'a':N,'b':N+1},'actual_mapping':{'a':N+1,'b':N}}))), ['positional-substitution'])
check('repeated-substitution regression 0', solve(dict(base, **({'occurrences':{'a':['x','y']}}))), ['repeated-substitution'])
check('repeated-substitution regression 1', solve(dict(base, **({'occurrences':{'a':[N,N+1]}}))), ['repeated-substitution'])
check('recursive-actual-map regression 0', solve(dict(base, **({'recursive_expected':{'call':'b'},'recursive_actual':{'call':'a'}}))), ['recursive-actual-map'])
check('recursive-actual-map regression 1', solve(dict(base, **({'recursive_expected':{'call':N+1},'recursive_actual':{'call':N}}))), ['recursive-actual-map'])
check('static-preservation regression 0', solve(dict(base, **({'static_before':'static','static_after':'a'}))), ['static-preservation'])
check('static-preservation regression 1', solve(dict(base, **({'static_before':'static','static_after':N}))), ['static-preservation'])
check('anonymous-freshness regression 0', solve(dict(base, **({'anonymous_calls':['c1','c2'],'anonymous_ids':['r','r']}))), ['anonymous-freshness'])
check('anonymous-freshness regression 1', solve(dict(base, **({'anonymous_calls':[N,N+1],'anonymous_ids':[0,0]}))), ['anonymous-freshness'])
check('where-direction regression 0', solve(dict(base, **({'expected_outlives':[('a','b')],'actual_outlives':[('b','a')]}))), ['where-direction'])
check('where-direction regression 1', solve(dict(base, **({'expected_outlives':[(N,N+1)],'actual_outlives':[(N+1,N)]}))), ['where-direction'])
check('associated-arguments regression 0', solve(dict(base, **({'associated_args':['a','b'],'recorded_args':['b','a']}))), ['associated-arguments'])
check('associated-arguments regression 1', solve(dict(base, **({'associated_args':[N,N+1],'recorded_args':[N+1,N]}))), ['associated-arguments'])
check('summary-fixed-point regression 0', solve(dict(base, **({'accepted':True,'pending':['a']}))), ['summary-fixed-point'])
check('summary-fixed-point regression 1', solve(dict(base, **({'accepted':True,'pending':[N]}))), ['summary-fixed-point'])
check('erased-proof-metadata regression 0', solve(dict(base, **({'reference_types':['a','b'],'proof_metadata':['a']}))), ['erased-proof-metadata'])
check('erased-proof-metadata regression 1', solve(dict(base, **({'reference_types':[N,N+1],'proof_metadata':[N]}))), ['erased-proof-metadata'])
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 |
| lifetime-arity regression 0 | ['lifetime-arity'] | ['lifetime-arity'] | Passed |
| lifetime-arity regression 1 | ['lifetime-arity'] | ['lifetime-arity'] | Passed |
| positional-substitution regression 0 | ['positional-substitution'] | ['positional-substitution'] | Passed |
| positional-substitution regression 1 | ['positional-substitution'] | ['positional-substitution'] | Passed |
| repeated-substitution regression 0 | ['repeated-substitution'] | ['repeated-substitution'] | Passed |
| repeated-substitution regression 1 | ['repeated-substitution'] | ['repeated-substitution'] | Passed |
| recursive-actual-map regression 0 | ['recursive-actual-map'] | ['recursive-actual-map'] | Passed |
| recursive-actual-map regression 1 | ['recursive-actual-map'] | ['recursive-actual-map'] | Passed |
| static-preservation regression 0 | ['static-preservation'] | ['static-preservation'] | Passed |
| static-preservation regression 1 | ['static-preservation'] | ['static-preservation'] | Passed |
| anonymous-freshness regression 0 | ['anonymous-freshness'] | ['anonymous-freshness'] | Passed |
| anonymous-freshness regression 1 | ['anonymous-freshness'] | ['anonymous-freshness'] | Passed |
| where-direction regression 0 | ['where-direction'] | ['where-direction'] | Passed |
| where-direction regression 1 | ['where-direction'] | ['where-direction'] | Passed |
| associated-arguments regression 0 | ['associated-arguments'] | ['associated-arguments'] | Passed |
| associated-arguments regression 1 | ['associated-arguments'] | ['associated-arguments'] | Passed |
| summary-fixed-point regression 0 | ['summary-fixed-point'] | ['summary-fixed-point'] | Passed |
| summary-fixed-point regression 1 | ['summary-fixed-point'] | ['summary-fixed-point'] | Passed |
| erased-proof-metadata regression 0 | ['erased-proof-metadata'] | ['erased-proof-metadata'] | Passed |
| erased-proof-metadata regression 1 | ['erased-proof-metadata'] | ['erased-proof-metadata'] | Passed |
SHA-256 / cad9ef22ae66e85a0cf9ece541118c28b4ea5b071f000a75cf09c4de239d4263
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:44:09.701054+00:00.
Case digest / 6add82722c8022e2ce48a4cd401b26074d08ceb4372a80ea82f7ae87c6d5dadf