Formal verification of skiplist algorithms Student: Trinh Cong Quy Supervisor: Bengt Jonsson Reviewer: Parosh Abdulla Outline • Motivation • Methodology • Results and Future Work Motivation How do we verify skiplist algorithms? Why? Why: • Skiplists are important data structures, eg in databases, distributed systems • Verifying is complicated because skiplists are multi-pointers structures • There is no previous work that formally verify skiplists algorithms Our Motivation: • Employ transitive closure logic to handle multi-pointers data structures • Introduce a method to discover and verify quantified invariants for multi-pointers programs • Apply such method to skiplist algorithms. Skiplist Skiplist is a list with a number of sorted single linked lists, each linked list is located at a layer head tail s m -∞ s m 5 m 10 +∞ Properties: Every single linked list at any layer is sorted accorrding to node’s key values List at higer layer is a sublist of list at lower layer Example Add(8) s sPred = s 8 head m m sSucc = mSucc s tail s mPred m -∞ m 5 m 10 +∞ How to verify program invariants Assume that we have the invariant I of program P and we want to verify it. We need to: Annotate program P by computing assertions at program points and then verify I at all assertions Program Assertion Assertion: Assertion at each program point is a conjunction of atomic predicates which are valid in that point and taken from abstract domain Example: P1: (x = y) (y * z) (x * t) Abstract Domain: Set of predicates P = { P1, …, Pn } given by users Each predicate describes relations between program variables Example 1.int insert(x) Abstract Domain 2.{ head →* tail, head = pred head →* tail pred →* x, x →* tail 3. node* pred = head head = pred ˄ head →* tail 4. pred.next := x head = pred ˄ pred →* x 5. x.next := tail ? } How to get assertion for each program point? Compute Post Assertion Let A’ is successor of program point A, then its assertion is obtained as below • For each predicate P from the abstract domain • If it is valid in A' that means if post(A,S) P • Add P to the assertion Here post(A,S) is post-condition which are program states reached from A when we execute the statement S Example Abstract Domain head →* tail, head = pred For each predicate P from the abstract domain pred →* x, x →* tail A.head = pred ˄ pred →* x x.next := tail A’.? } If it is valid in A' that means that if post(A,S) P Add P to the assertion Post(head = pred ˄ pred →* x, x.next := tail ) = head = pred ˄ pred →* x ˄ x → tail head = pred ok pred →* x: ok x →* tail: ok head →* tail: ok Assertion: head = pred ˄ pred →* x ˄ x →* tail ˄ head →* tail Assertion Template for Skiplists • Invariant: u,v (P (u,v) e (u,v)) i i • Assertion form at each program point E u,v (P (u,v) e (u,v)) i i Where ♦ E: conjunction of atomic predicates valid at that point ♦ ei(u,v): an atomic predicate of u and v ♦ Pi(u,v): conjunction of atomic predicates of u and v global variables Example: E u,v (u →m* v u ≤ v) Assertion Inferring • Start with an empty list • Run for a loop to insert and delete nodes randomlly • For each loop iteration Generate environments for program points • When the loop is terminated , take intersection of environments at the same program points. • For each common environment: Find minimal conjunction Pi (u,v) such that Pi (u,v) ei (u,v) Example 1.int insert(x) 2.{ 3.find(x, mPred,sPred, mSucc,sSucc) 1.int insert(x) 2.{ 3.find(x, mPred,sPred, mSucc,sSucc) head = mPred ˄ head = sPred ˄ tail = mSucc ˄ tail = sSucc head →m mPred ˄ head →s sPred ˄ mSucc →m tail ˄ sSucc →s tail 4.node* n := Node(x,2) 5.n.mNext = mPred 6.mPred.mNext := n 7.n.sNext = sPred 8.mPred.mNext := n 4.node* n := Node(x,2) 5.n.mNext = mPred 6.mPred.mNext := n 7.n.sNext = sPred 8.mPred.mNext := n head = mPred ˄ head = sPred ˄ tail = mSucc ˄ tail = sSucc ˄ mPred = sPred ˄ mSucc = sSucc ˄ head m mPred ˄ head s sPred ˄ mSucc m tail ˄ sSucc s tail mPred = sPred ˄ mSucc = sSucc ˄ mPred →m* n ˄ n →m* mSucc ˄ sPred →s* n ˄ n →s* sSucc ˄ mPred < n ˄ n < mSucc ˄ sPred < n ˄ n < sSucc mPred →m* n ˄ n →m* mSucc ˄ sPred →s* n ˄ n →s* sSucc ˄ mPred < n ˄ n < mSucc ˄ sPred < n ˄ n < sSucc 9.return 0 10.} 9.return 0 10.} Example (cont) Common environment at program point 9 head →m* mPred ˄ head →s* sPred ˄ mSucc →m* tail ˄ sSucc →s* tail ˄ mPred = sPred ˄ mSucc = sSucc ˄ mPred →m* n ˄ n →m* mSucc ˄ sPred →s* n ˄ n →s* sSucc ˄ mPred < n ˄ n < mSucc ˄ sPred < n ˄ n < sSucc Invariant: u →s* v u →m* v Inductive Assertion Assertion is inductive Holds at initial program points If it holds at a program point A, it also holds at A’s sucssesor Assertion Verifing A E u,v (P (u,v) e (u,v)) i i S A’ E’ post(u,v (P (u,v) e (u,v))) i i • Is u,v (Pi (u,v) ei (u,v)) valid in A’ ? Assertion Verifing • Check that: E’ u,v post( (Pi (u,v) ei (u,v))) u,v (P (u,v) e (u,v)) i General Form: E’ i X (X) X (Y) Quantifier Instantiation • To prove: E’ X (X) X (Y) Using terms Y1, Y2,…., Yn that appear in E’ Expand as ψ (Y1) … ψ (Yn) ψ (Y) (Y) • If unsatisfiable, then so is quantified formula • The approach is sound, but incomplete Example Assume that the invariant u,v (x →s* y x →m* y) holds in program point 8 of previous insert function. Then we will show how to prove that its preserved in program point 9 1.int insert(x) 2.{ 3.find(x, mPred,sPred,mSucc,sSucc) head = mPred ˄ head = sPred ˄ tail = mSucc ˄ tail = sSucc 4.node* n := Node(x,2) 5.n.mNext = mPred 6.mPred.mNext := n 7.n.sNext = sPred 8.mPred.mNext := n head = mPred ˄ head = sPred ˄ tail = mSucc ˄ tail = sSucc ˄ mPred = sPred ˄ mSucc = sSucc ˄ mPred →m* n ˄ n →m* mSucc ˄ ˄ n < sSucc sPred →s* n ˄ n →s* sSucc ˄ mPred < n ˄ n < mSucc ˄ sPred < n 9.return 0 10.} Example(cont) Program point 8 = u →s* v u →m* v = ˥(u →s* v) ˅ u →m* v After statement: sPred.sNext := n Program point 9 E’ = sPred m* n ˄ ...... = ˥(u →s* v) ˅ (u →s* sPred ˄ n →s* v) ˅ u →m* v Prove: E’ u,y (u,v) u,v (u,v) <-> E’ u,y (u,v) ˄ ˥(u1, v1) is unsastifiable (u1,sPred) = ˥(u1 →s* sPred) ˅ u1 →m* sPred (n, v1) = ˥(n →s* v1) ˅ n →m* v1 (u1, v1) = ˥(u1 →s* v1) ˅ (u1 →s* sPred ˄ n →s* v1) ˅ u →m* v1 ˥(u1, v1) = u1 →s* v1 ˄ ˥(u1 →m* v1) E ˄ (u1, v1) ˄ ˥(u1, v1) ˄ (u1,sPred) ˄ (n, v1) = u1 →m* sPred ˄ sPred →m* n ˄ n →m* v1 ˄ ˥(u1 →m* v1) ˄ (u1 →s* sPred ˄ n →s* v1) contradiction Results • New method to infer and verify quantidied invariants of multi-pointers structures • Apply such method to skiplist algorithms, manually infer and verify the invariant of the skiplist algorithm in the paper: A Simple Optimistic skip-list Algorithm http://www.cs.brown.edu/~levyossi/Pubs/LazySkipList.p df when we simplify it to two layers skiplist algorithm. x,y(x →s* y x →m* y) (x →m* y x ≠ y x< y) • This algorithm is concurrent, so we use thread modular technique compute assertions but its not too important in this thesis Future Work • Implement the framework • Develop methods to refine abstract domain automatically Thank You