Flow Interfaces Compositional Abstractions of Concurrent Data Structures Siddharth Krishna, Dennis Shasha, and Thomas Wies
Background Verifying programs, separation logic, inductive predicates
Verifying Data Structures procedure delete(x: Node) { if (x!= null) { var y := x.next; delete(y); free(x); } } x y null
Inductive Predicates ls x x = null emp y. x y ls y ls x y. x y ls y y, z. x y y z ls z y, z, w. y, z, w. y, z, w. x y y z z w ls(w) x y y z z w w = null emp x y y z z null x y z null
Proof by SL ls(x) procedure delete(x: Node) { if (x!= null) { var y := x.next; delete(y); free(x); } } emp P C Q P F C Q F ls x x null x y ls(y) x y emp emp
Background The Trouble with Inductive Predicates Concurrent data structures are complex
Harris' Non-blocking List mh 3 6 8 9 Z Z 8
Harris' Non-blocking List mh 3 6 8 9 Z Z fh 2 5 8 Z Z
Limitations of Inductive Predicates Traversals need to visit each node exactly once. ls mh, null ls fh, null mh 3 6 8 9 fh 2 5 Overlays
Limitations of Inductive Predicates Traversals need to visit each node exactly once. harris mh, fh, null... harris( ) mh 3 6 8 9 fh 2 5 4 Unbounded sharing
Limitations of Inductive Predicates harris mh, fh, null ls(mh, null) mh 3 6 8 9 fh 2 5 Threads can enter main list at arbitrary points
Other Approaches Iterated separating conjunction: E G φ(x) mh 3 6 8 9 fh 2 5 Can t do better than closed set of nodes Every node reachable memory leaks
Other Approaches Overlapping conjunction: mh 3 6 8 9 fh 2 5 Potentially cyclic complex predicate Updates: ramifications, reason about
The Problem An abstraction mechanism that can handle data structures like the Harris list? (i.e. handle overlays, sharing, arbitrary traversals & have easy reasoning)
Background The Trouble with Inductive Predicates Flow Interfaces A new abstraction for concurrent data structures
The Idea Inductive predicates: Pro: inductive properties Con: fixed traversals Iterated : E G φ(x) Pro: easy reasoning Con: only local properties Best of both? Inductive properties local conditions But allow dependence on inductive quantity: flow
Local Data Structure Invariants with Flows root Path counting! Can we express the property that root points to a tree as a local condition of each node in the graph?
Flows Step : Define the graph root 0 Graph G = (N, e) N finite set of nodes e: N N D D is a flow domain For example: D = N { } Label each edge in the graph with.
Flows Step 2: Calculate the flow root 0 Given an inflow in: N D 0 0 0 Here in n = ITE(n =root,, 0) 0 0 0
Flows Step 2: Calculate the flow root 0 0 Start with flow(n) = in(n) 0 0 0 0 0 0 0 0 0 0 0 0 And iterate until fixpoint flow n = in n + flow n Y e(n Y, n) \Y
Flows Step 2: Calculate the flow root 0 0 Different inflows result in different flows 0 0 0 0 0 0 0 0
Flows Step 3: Define invariant on flow root If every node satisfies the good condition γ^ flow(in, G) n = 0 0 for in n = ITE(n = root,, 0) 0 0 then G is a tree rooted at root
Flows Step 3: Define invariant on flow root 0 For lists, enforce at most outgoing edge γ` flow in, G n = (e \ = { n, n Y } e \ = ε) e \ : edge function restricted to nonzero edges leaving n 0
Flows Alternate view Flow graph G = (N, E) Viewing E as a matrix, E c \\Y = d E \d E d\y = number of 2-length paths from n to n E ` \\Y = number of l-length paths from n to n Capacity C = I + E + E c + (converges if D is a flow domain) cap G n, n Y C \\Y = the number of paths from n to n flow in, G (n) in n Y cap(g)(n Y, n) \Y
Data Invariants 3 root 3 3 Flow domain: ω-cpo & positive semiring (D,,, +,, 0, ) Another Example: lower-bound domain (Z {, },, min, min, max,, ) 53 73 5 5 7 95 65 Label each edge with value of souce node Use in n = ITE(n = root,, ) flow in, G n = max value in some path from root to n These paths are sorted if γ s flow in, G where a is value at n n a
Stacking Flows (0, ) root (0, ) (, ) (0, ) (, 5) (, 5) 3 (, ) (, 3) (, 3) 5 7 (,3) (,3) 9 6 (,5) (,5) (0, ) Want shape & data invariants? Flow of product is product of flows! Example: min-heap Use product of path-counting and lowerbound domain Use in n = ITE(n = root, (, ), (0, )) And good condition γ u flow in, G where a is value at n n =, l l a
Stacking Flows (, 5) (0, ) (,5) (, 3) (,3) root (, ) (, ) (, 3) (0, ) (0, ) (, 5) (,5) (,3) (0, ) Data invariants are decoupled from shape invariants Min-heap γ u flow in, G Sorted list γ s` flow in, G (e \ = { n, n Y n =, l l a n =, l l a } e \ = ε)
Harris List We can now describe Harris List Flow domain: two path-counting flows One from mh and one from fh Every node is on at least one of these lists Nodes labelled: marked/unmarked All nodes in free list are marked mh 3 6 8 9 fh 2 5
Expressivity of Flows Flows can describe: Lists (singly and doubly linked, cyclic) Trees (n-ary, arbitrary arity) Nested combinations Sorted lists, binary heaps, BSTs Overlaid structures (threaded and B-link trees) Irregular structures (DAGs, graphs) Unbounded sharing & irregular traversals (Harris) But inductive predicates easier for: Simple inductive structures/abstractions
Compositional Reasoning Can we reason compositionally about flows and graphs à la SL?
Graph Composition Standard SL Composition (disjoint union) is too weak: r r x * x = x y y y a tree a tree not a tree Need a composition that preserves flow!
Flow Graphs Suppose G satisfies γ flow in, G n 2 root 0 0 0 0 2 0 0 0 2
Flow Graphs Suppose G satisfies γ flow in, G n 2 and we want to reason about a subgraph G root 0 0 0 0 2? that we modify to G. Is G good? New flow? 0 0 0 2
Flow Graphs (in, G) is a flow graph iff G = (N, N o, e) is a partial graph N - set of internal nodes N o - set of sink nodes e: N x (N N o ) D - edge function in: N D is an inflow 0 0 Inflow in specifies rely of G.
Flow Graph Composition (in, G) = (in, G ) (in 2, G 2 ) root in =?, in 2 =? 0 0 2 2 in y n = in n + flow in, G)(n Y e(n Y, n) \ z {
Flow Graph Composition (in, G) = (in, G ) (in 2, G 2 ) root in =?, in 2 =? 0 0 2 2 2 in c n = in n + flow in, G)(n Y e(n Y, n) \ z { ~
Flow Graph Composition H H 2 is commutative: H H 2 = H 2 H associative : (H H 2 ) H 3 = H (H 2 H 3 ) cancelative: H H = H H 2 H = H 2 Flow graphs form a separation algebra. We can use them to give semantics to SL assertions. How do we abstract flow graphs?
Abstracting Flow Graphs What we want from an abstraction:
Modifying the Graph (in, G) = (in, G ) (in 2, G 2 ) (in, G ) (in, G ) (in 2, G 2 ) root 0 2 2 23 Need to preserve the flow into G 2
Modifying the Graph (in, G) = (in, G ) (in 2, G 2 ) (in, G ) = (in, G ) (in 2, G 2 ) root 0 2 2 2 Preserve the number of paths going through G?
Flow Map of a Flow Graph n n o flm in, G n, n G flm in, G n, n = e n, n y e n, n over all paths in G flow in, G n = in n flm in, G (n, n ) \ {
Flow Map: Example
Flow Map: Example Flow map abstracts from internal structure of the graph
Flow Map: Example Flow map abstracts from internal structure of the graph
Flow Map: Example 0 0 Flow map abstracts from internal structure of the graph
Flow Interfaces I = (in, a, f) is a flow interface in: N D is an inflow a A is the abstraction of node labels f: N N o D is a flow map u v w ({u 0, v, w }, _, { v, x, v, y, }) x y z
Flow Interfaces Flow interfaces induce a congruence on flow graphs: H, H Y I H y H c I H y Y H c Y I Lift flow graph composition to interfaces: (Flow Interfaces, ) also a separation algebra!
Reasoning about Modifications congruence can replace G y with any G y Y with same interface u v w u v w x y z x y z Showing equivalence: requires fixpoint reasoning But concurrent algorithms modify small regions
Separation Logic with Flow Interfaces Good graph predicate Gr γ (I) γ: SL predicate that defines good node condition and abstraction of heap onto nodes of flow graph I: flow interface Good node predicate N γ (x, I) like Gr but denotes a single node definable in terms of Gr Dirty region predicate [P] γ,i P: SL predicate denotes heap region that is expected to satisfy interface I but may currently not
(, 3) root (, ) (,3) (, ) Example Sorted Linked List γ x, in, a, f n k, n Y in n =, l a = {k} l k f = ITE(n Y = null, ε, { n, n Y Global invariant: (, k)}) (, 5) Gr I I \ + 0 = {r, } + 0 I Š = ε (,5)
Harris List Global invariant: Φ I. Gr I I \ + 0 = {mh, 0 } + {fh 0, } + 0 I Š = ε
Verifying Programs Hoare-style proofs require proving entailments. Example: but ls x, y ls y, z ls(x, z) sls x, y sls y, z sls x, z Solution: add lower and upper bounds sls(x, y, l, u) sls x, y, l, v sls y, z, w, u v w sls(x, z, l, u) Different composition lemma!
Data-Structure-Agnostic Lemmas Decomposition Gr I x I I y, I c. N x, I y Gr I c I = I y I c Step I = I y I c x, y I y Š I Š = ε y I c Composition Gr I y Gr I c Gr I y I c
Harris: Insert procedure insert() { var l := mh; Φ var r := unmarked(l.next); while (r!= null &&?? ) { l := r; r := unmarked(l.next); } } Gr I mh I \ (Decomp) N l, I` Gr I c I = I` I c Gr I x I I y, I c. N x, I y Gr I c I = I y I c (Decomp)
Harris: Insert procedure insert() { } var l := mh; Φ var r := unmarked(l.next); while (r!= null &&?? ) { l := r; r := unmarked(l.next); } N l, I` Gr I c I = I` I c I = I` I c l, r I`Š I Š = ε (Step), (Decomp) N l, I` N r, I Gr I I = I` I I I = I y I c x, y I y Š I Š = ε y I c (Step) Gr I x I I y, I c. N x, I y Gr I c I = I y I c (Decomp)
Harris: Insert procedure insert() { } var l := mh; var r := unmarked(l.next); while (r!= null &&?? ) { } l := r; Φ r := unmarked(l.next); N l, I` Gr I c I = I` I c N l, I` N r, I Gr I I = I` I I (Comp) N r, I Gr I I = I I Gr I y Gr I c Gr I y I c (Comp)
Harris: Insert procedure insert() { var l := mh; Φ var r := unmarked(l.next); while (r!= null &&?? ) { l := r; r := unmarked(l.next); } } N l, I` Gr I c I = I` I c N l, I` Gr I I = I` I and so on
Flow Interfaces Data structure abstractions that can handle unbounded sharing and overlays treat structural and data constraints uniformly do not encode specific traversal strategies provide data-structure-agnostic composition and decomposition rules remain within general theory of separation logic
Background The Trouble with Inductive Predicates Flow Interfaces Concurrent Dictionaries A memory-safe, linearizable, abstract template
Concurrent Dictionaries Dictionary: key-value store Examples: sorted linked lists, BSTs, B-trees, hash maps, With flows: generic template + proof
Inset Flows root 6 {v v < 6} {v v > 6} 3 8 KS: the set of all search keys e.g. KS = Int Inset flow domain: (2,,,,,, KS) {v v < 3} {v v > 3} {v v > 8} 4 9 Label each edge with the set of keys that follow that edge in a search (edgeset).
Inset Flows root KS {v v < 6} {v v > 6} KS: the set of all search keys e.g. KS = Int Inset flow domain: (2,,,,,, KS) {v v < 3} {v v > 3} {v v > 8} Set inflow in of root to KS and to for all other nodes.
Inset Flows root {v v < 6} KS {v v > 6} I = {v 3 < v} I 2 = {v 3 < v < 6} {v v < 3} {v v > 3} {v v > 8} I 3 = {v 8 < v} I I 2 I 3 flow(in, G)(n) is the inset of node n, i.e., the set of keys k such that a search for k will traverse node n.
From Insets to Keysets outset(g) n = ž e(n, n Y ) \ Ÿ v v < 5 v } 5 {5} 7 {v v > 5} keyset(in, G) n = inset(in, G) n outset(g)(n) 3 v < v < 5} keyset(in, G)(n) is the set of keys that could be in n
Verifying Concurrent Dictionaries Good state conditions edgesets are disjoint for each n: {e(n,n')} n' N are disjoint keyset of each n covers n's contents: C(G)(n) keyset(in, G)(n) Keyset Theorem [Shasha and Goodman, 988] If all ops preserve good state, and methods search/insert/delete k at node s.t. k keyset(n) The implementation is linearizable
Encoding Using Flows Description of good node Description of locked node Contents are in keyset Edgesets leaving node are disjoint Global invariant:
Give-up Template
Actions
Keyset Theorem with Flows Theorem: An implementation of the template with appropriate γ, γ that satisfy the spec below (with some side conditions) is memory safe and linearizable.
Background The Trouble with Inductive Predicates Flow Interfaces Concurrent Dictionaries Conclusion A new way to reason about data structures
Conclusion Radically new approach for building compositional abstractions of data structures. Fits in existing (concurrent) separation logics. Enables simple correctness proofs of concurrent data structure algorithms. Proofs can abstract from the details of the specific data structure implementation. Siddharth Krishna, Dennis Shasha, and Thomas Wies. Go with the Flow: Compositional Abstractions for Concurrent Data Structures. POPL 208.
Dirty Regions Problems with flow graphs as state: Commands need to be local modifying an edge is not Programs may temporarily violate γ Actual programs operate on heaps Solution: State: (heap, flow graph) φ describes region where (heap, graph ) φ and graph I
Dirty Regions Commands need to be local Basic commands modify only heap sync(i) updates graph when flow map preserved Programs may temporarily violate γ heap portion can be ahead of graph portion Actual programs operate on heaps γ ties each graph node to its heap representation Graph portion is ghost state
Proof by Hand-Waving { x }... null x = null procedure delete(x: Node) { { x } if (x!= null) { x... y null var y := x.next; { x } null delete(y); { } y free(x); } } { } {... } Slides courtesy of Thomas Wies
Proof by Hand-Waving { x } null procedure delete(x: Node) { if (x!= null) { var y := x.next; delete(y); free(x); } } { }
Separation Logic by Example Points-to predicate x! y x y Stack x 0 y 42 Heap 0 42 42? A partial heap consisting of one allocated cell
Separation Logic by Example Points-to predicate x! y x y Points-to predicate expresses permission to access (i.e. read/write/deallocate) heap location x and nothing else! SL assertions describe the part of the heap that a program is allowed to work with.
Separation Logic by Example Points-to predicate y! x x y Stack x 0 y 42 Heap 0? 42 0 A partial heap consisting of one allocated cell
Separation Logic by Example Separating conjunction x! y y! x x y Stack x 0 y 42 Heap 0 42 42 0 Composition of disjoint partial heaps
Separation Logic by Example Equalities x! y x = z x,z y Stack x 0 y 42 z 0 Heap 0 42 42? Equalities only constrain the stack
Separation Logic by Example Separating conjunction x! y x! z unsatisfiable? Subheaps must be disjoint (x can't be at two different places at once)
Separation Logic by Example Classical conjunction x! y y! x x,y?
Separation Logic by Example Separating conjunction x! z y! z 2 x = y still unsatisfiable? Convention: has higher precedence than