Leak-class branch drop: heap-capturing closure param leaks (soundness-over-completeness) #67

Open
opened 2026-06-02 15:51:18 +02:00 by Brummel · 0 comments
Owner

Recorded from the #63 leg-3 audit (spec docs/specs/0068, contract design/contracts/0008-memory-model.md "Leak-class branch-param drop").

The leak-class branch-param drop (emit_leakclass_branch_param_drops, crates/ailang-codegen/src/lib.rs) carries a heap-RC-ADT type precondition: it fires only when field_drop_call resolves to a real per-type drop fn (!= ailang_rc_dec), excluding Type::Fn / static-Str / Type::Var params (the bare ailang_rc_dec route underflows on a static closure-pair / static-Str .rodata constant with no rc-header).

Consequence (accepted, exotic): a HEAP-capturing closure param consumed on one branch and live on a sibling is SKIPPED -> its env slab leaks one allocation instead of being freed. Soundness over completeness: an underflow would be worse, and the existing closure-drop machinery cannot free a heap closure env correctly either (Type::Fn routes to a shallow rc_dec; captured env leaks per the 18c.4 carve-out in crates/ailang-codegen/src/drop.rs).

Not reproduced by any shipping fixture (std_either/list/poly_rec_capture pass STATIC closure refs, which allocate nothing). Filed so the known-leak is recorded, not silent.

depends on: a typed closure descriptor / runtime null-env guard letting a closure-pair drop discriminate static vs heap env at runtime.
context: deferred from #63 leg 3; closing #63 did not require it.

Recorded from the #63 leg-3 audit (spec docs/specs/0068, contract design/contracts/0008-memory-model.md "Leak-class branch-param drop"). The leak-class branch-param drop (emit_leakclass_branch_param_drops, crates/ailang-codegen/src/lib.rs) carries a heap-RC-ADT type precondition: it fires only when field_drop_call resolves to a real per-type drop fn (!= ailang_rc_dec), excluding Type::Fn / static-Str / Type::Var params (the bare ailang_rc_dec route underflows on a static closure-pair / static-Str .rodata constant with no rc-header). Consequence (accepted, exotic): a HEAP-capturing closure param consumed on one branch and live on a sibling is SKIPPED -> its env slab leaks one allocation instead of being freed. Soundness over completeness: an underflow would be worse, and the existing closure-drop machinery cannot free a heap closure env correctly either (Type::Fn routes to a shallow rc_dec; captured env leaks per the 18c.4 carve-out in crates/ailang-codegen/src/drop.rs). Not reproduced by any shipping fixture (std_either/list/poly_rec_capture pass STATIC closure refs, which allocate nothing). Filed so the known-leak is recorded, not silent. depends on: a typed closure descriptor / runtime null-env guard letting a closure-pair drop discriminate static vs heap env at runtime. context: deferred from #63 leg 3; closing #63 did not require it.
Brummel added the idea label 2026-06-02 15:51:18 +02:00
Sign in to join this conversation.