Iron: Managing Obligations in Higher-Order Concurrent Separation Logic s Bizjak 1 Daniel Gratzer 1 Aleˇ Robbert Krebbers 2 Lars Birkedal 1 1 Aarhus University 2 Delft University of Technology January 17, 2019 POPL 2019 https://iris-project.org/iron/ 0
The Problem Resources we use in programs impose obligations: • Memory must be properly freed. • File handles must be closed after use. • Locks must be acquired and released properly. 1
Example let ℓ = ref ( None ) in fork { ( rec go () = match ! ℓ with | None ⇒ go () | Some ( x ) ⇒ free ( x ); free ( ℓ ) end end ) () } ; ℓ ← Some ( ref ( 1 )) 2
Example Channel let ℓ = ref ( None ) in fork { ( rec go () = match ! ℓ with | None ⇒ go () | Some ( x ) ⇒ free ( x ); free ( ℓ ) end end ) () } ; ℓ ← Some ( ref ( 1 )) 2
Example Channel let ℓ = ref ( None ) in fork { ( rec go () = match ! ℓ with Wait... | None ⇒ go () | Some ( x ) ⇒ free ( x ); free ( ℓ ) end end ) () } ; ℓ ← Some ( ref ( 1 )) 2
Example Channel let ℓ = ref ( None ) in fork { ( rec go () = match ! ℓ with Wait... | None ⇒ go () | Some ( x ) ⇒ free ( x ); free ( ℓ ) end end ) () } ; Signal the ℓ ← Some ( ref ( 1 )) thread 2
Example Channel let ℓ = ref ( None ) in fork { ( rec go () = match ! ℓ with Wait... | None ⇒ go () | Some ( x ) ⇒ free ( x ); free ( ℓ ) ...then clean up end end ) () } ; Signal the ℓ ← Some ( ref ( 1 )) thread 2
Wish list We want a concurrent separation logic to prove these properties: • Has thread-local reasoning • Can express complex and modular specifications • Handles complicated language features (especially fork) • Is amenable to mechanization • Can prove leak-freedom 3
Wish list We want a concurrent separation logic to prove these properties: • Has thread-local reasoning • Can express complex and modular specifications • Handles complicated language features (especially fork) • Is amenable to mechanization • Can prove leak-freedom Iris (a state of the art concurrent separation logic) gives us the first 4. 3
Our Contribution Trackable resources : a general mechanism for managing obligations and Iron : a separation logic implementing it: • Includes all proof techniques of Iris (ghost state, impredicative invariants, updates, etc...) • Supports all the language features of Iris • Fully mechanized in Coq 4
Other Approaches: Iris Iris and other affine logics gives us safety (and correctness): Theorem If { True } e { True } holds then e does not get stuck. We wish to strengthen this to ensure leak-freedom. 5
Other Approaches: CSL O’Hearn [2007] and Brookes [2007] ensured leak-freedom through linearity for statically scoped concurrency : Γ ⊢ { Emp } ref ( v ) { ℓ. ℓ �→ v } Γ ⊢ { ℓ �→ w } free ( ℓ ) { Emp } Γ ⊢ { P 1 } e 1 { Q 1 } Γ ⊢ { P 2 } e 2 { Q 2 } Γ ⊢ { P 1 ∗ P 2 } e 1 || e 2 { Q 1 ∗ Q 2 } 6
Other Approaches: CSL O’Hearn [2007] and Brookes [2007] ensured leak-freedom through linearity for statically scoped concurrency : Γ ⊢ { Emp } ref ( v ) { ℓ. ℓ �→ v } Γ ⊢ { ℓ �→ w } free ( ℓ ) { Emp } Γ ⊢ { P 1 } e 1 { Q 1 } Γ ⊢ { P 2 } e 2 { Q 2 } Our heap view Γ ⊢ { P 1 ∗ P 2 } e 1 || e 2 { Q 1 ∗ Q 2 } is empty 6
Other Approaches: CSL O’Hearn [2007] and Brookes [2007] ensured leak-freedom through linearity for statically scoped concurrency : Γ ⊢ { Emp } ref ( v ) { ℓ. ℓ �→ v } Γ ⊢ { ℓ �→ w } free ( ℓ ) { Emp } Γ ⊢ { P 1 } e 1 { Q 1 } Γ ⊢ { P 2 } e 2 { Q 2 } Our heap view Γ ⊢ { P 1 ∗ P 2 } e 1 || e 2 { Q 1 ∗ Q 2 } is empty Does not share memory 6
Scoped Invariants With only parallel composition scoped invariants are sufficient: Γ , r : R ⊢ { P } e { Q } Γ ⊢ { P ∗ R } resource r in e { Q ∗ R } Scoped invariants are insufficient for the “unscoped concurrency”: let ℓ = ref ( 1 ) in resource r in fork { with r do ! ℓ } ; free ( ℓ ) 7
Unscoped Invariants With fork we need unscoped invariants: N } e { v . Q } { P ∗ R { P ∗ R } e { v . Q } • Invariants persist forever and can be duplicated freely. • There is no deallocation rule; it must be encoded. 8
Unscoped Invariants With fork we need unscoped invariants: N } e { v . Q } { P ∗ R { P ∗ R } e { v . Q } • Invariants persist forever and can be duplicated freely. • There is no deallocation rule; it must be encoded. We can always put resources in an invariant and forget them – no linearity! 8
Resolving This Tension • Scoped tracks obligations but does not handle fork. • Unscoped handles fork but does not track obligations. • Invariants are complex to prove sound; we prefer not to modify them. We will modify �→ instead so that unscoped invariants are suitable. 9
Crucial Idea: Trackable Resources We keep the affine logic so Iris’s implementation of invariants can be reused. • Index ℓ �→ π v with π ∈ ( 0 , 1 ] • Add a new proposition e π with π ∈ ( 0 , 1 ] π indicates how much of the heap we know about through the proposition. 10
Intuition for Fractions If we own... • ℓ �→ 1 v then the only thing the heap contains is ℓ �→ v . • e 1 the heap contains nothing at all. • ℓ �→ π v and π < 1 the heap may contain other locations. • ℓ 1 �→ 1 / 2 v and ℓ 2 �→ 1 / 2 w the heap contains just ℓ 1 and ℓ 2 . We can prove leak-freedom by owning e 1 . 11
Intuition for Fractions If we own... • ℓ �→ 1 v then the only thing the heap contains is ℓ �→ v . • e 1 the heap contains nothing at all. • ℓ �→ π v and π < 1 the heap may contain other locations. • ℓ 1 �→ 1 / 2 v and ℓ 2 �→ 1 / 2 w the heap contains just ℓ 1 and ℓ 2 . We can prove leak-freedom by owning e 1 . 11
Intuition for Fractions If we own... • ℓ �→ 1 v then the only thing the heap contains is ℓ �→ v . • e 1 the heap contains nothing at all. • ℓ �→ π v and π < 1 the heap may contain other locations. • ℓ 1 �→ 1 / 2 v and ℓ 2 �→ 1 / 2 w the heap contains just ℓ 1 and ℓ 2 . We can prove leak-freedom by owning e 1 . 11
Intuition for Fractions If we own... • ℓ �→ 1 v then the only thing the heap contains is ℓ �→ v . • e 1 the heap contains nothing at all. • ℓ �→ π v and π < 1 the heap may contain other locations. • ℓ 1 �→ 1 / 2 v and ℓ 2 �→ 1 / 2 w the heap contains just ℓ 1 and ℓ 2 . We can prove leak-freedom by owning e 1 . 11
Fractional Permissions? What does ℓ �→ π v mean? • With fractional permissions we own π of the location . • With Iron we own π of the entire heap . Crucial difference: we can write to ℓ �→ 1 / 2 v in Iron but not in Boyland [2003]. 12
Working with Fractions in Programs: The Heap The program logic adapts to handle these fractions as follows: { e π } ref ( v ) { ℓ. ℓ �→ π v } { ℓ �→ π w } free ( ℓ ) { e π } { ℓ �→ π v } ! ℓ { w . w = v ∧ ℓ �→ π v } { ℓ �→ π w } ℓ ← v { ℓ �→ π v } e π 1 ∗ e π 2 ⊣⊢ e π 1 + π 2 ( ℓ �→ π 1 v ) ∗ e π 2 ⊣⊢ ℓ �→ π 1 + π 2 v 13
Working with Fractions in Programs: Concurrency The standard rule for fork holds: { P } e { True } { P } fork { e } { v . v = () } This rule is insufficient if the forked-off thread outlives its parent: fork { let ℓ = ref ( 1 ) in free ( ℓ ) } ; 1 + 1 14
Working with Fractions in Programs: Concurrency We must also allow the forked-off thread to terminate with e π : { P } e { True } { P } e { e π } { P } fork { e } { v . v = () } { P } fork { e } { v . v = () ∗ e π } 15
Adequacy Iron provides us with strong guarantees about programs: Theorem If { e π } e { e π } : 1. e does not get stuck 2. If ( e , h ) �→ ∗ ([ v , v 0 , ..., v n ] , h ′ ) then h = h ′ . � �� � thread results 16
Adequacy Iron provides us with strong guarantees about programs: Theorem If { e π } e { e π } : 1. e does not get stuck 2. If ( e , h ) �→ ∗ ([ v , v 0 , ..., v n ] , h ′ ) then h = h ′ . � �� � thread results If we forget part of e π then we cannot apply our adequacy theorem; the triple won’t hold! 16
Taking Stock At this point, Iron is already useful! 17
Taking Stock At this point, Iron is already useful! But it isn’t easy; there’s boilerplate with fractions everywhere: { ( π 1 + π 2 = 1 ) ∗ ( ℓ 1 �→ π 1 v 1 ) ∗ ( ℓ 2 �→ π 2 / 2 v 2 ) ∗ ( ℓ 3 �→ π 2 / 2 v 3 ) } free ( ℓ 1 ); free ( ℓ 2 ); free ( ℓ 3 ) { e 1 } 17
The Lifted Logic We can lift the operators of BI to functions, [ 0 , 1 ] → iProp . ( P ∗ Q )( π ) � ∃ π 1 , π 2 . π 1 + π 2 = π ∧ P ( π 1 ) ∗ Q ( π 2 ) �→ v )( π ) � π > 0 ∧ ℓ �→ π v ( ℓ � Emp ( π ) � π = 0 Other operations are lifted point-wise. 18
The Lifted Logic We can lift the operators of BI to functions, [ 0 , 1 ] → iProp . ( P ∗ Q )( π ) � ∃ π 1 , π 2 . π 1 + π 2 = π ∧ P ( π 1 ) ∗ Q ( π 2 ) �→ v )( π ) � π > 0 ∧ ℓ �→ π v ( ℓ � Emp ( π ) � π = 0 Other operations are lifted point-wise. The lifted logic is really linear! ℓ 1 � �→ v 1 ∗ ℓ 2 � �→ v 2 �⊢ ℓ 1 � �→ v 1 18
Recommend
More recommend