Using Coq for Separation Logic and the need for a better IDE Kenneth Roe 6/01/2015 The Johns Hopkins University
Motivation Many bugs can be traced to data structure invariant violations – Heartbleed can be traced to an inconsistency between two length fields No need for a complete program specification – Engineers can simply discover invariants when proving safety properties
Heartbleed bug Logo from heartbleed.com
Heartbleed bug Logo from heartbleed.com
Heartbleed bug Logo from heartbleed.com
Heartbleed bug Logo from heartbleed.com
Heartbleed bug Logo from heartbleed.com
Heartbleed bug Logo from heartbleed.com
Heartbleed bug Taken from heartbleed.com
Research contribution A better understanding of the issues involved with large scale proof development Creation of a new IDE for COQ to address some of these issues
Organization Basic Tree Example Invariants Tactics DPLL algorithm DPLL verification Challenges of large verifications CoqPIE GUI Conclusion
A tree traversal example in C Struct list { t = NULL; struct list *fld_n; } else { struct tree *fld_t; list *tmp = i->n; }; t = i->fld_t; free(l); Struct tree { i = tmp; struct tree *fld_l, *fld_r; } int value; } else if (t->r==NULL) { }; t = t->fld_l; } else if (t->l==NULL) { struct list *p; t = t->fld_r; void build_pre_order(struct tree *r) { } else { struct list *i = NULL, *n, *x; n = i; struct tree *t = r; i = malloc( p = NULL; sizeof(struct list)); while (t) { i->fld_n = n; n = p; x = t->fld_r; p = malloc(sizeof(struct list)); i->fld_t = x; p->fld_t = t;t = t->fld_l; p->fld_n = n; } if (t->fld_l==NULL && t->fld_r==NULL) { } if (i==NULL) {}
What this program does Nil t p i r
What this program does Nil t p i r
What this program does Nil 18 Nil t p i r
What this program does Nil 18 Nil t p i r
What this program does Nil Nil t p i r
What this program does Nil Nil t p i r
What this program does Nil 18 Nil t p i r
What this program does Nil 18 Nil t p i r
What this program does Nil t p i r
What this program does Nil t p i r
What this program does Nil t p i r
What this program does Nil t p i r
What this program does Nil t p i r
Organization Basic Tree Example Invariants Tactics DPLL algorithm DPLL verification Challenges of large verifications CoqPIE GUI Conclusion
Invariants to be formally proven The program maintains two well formed linked lists, the heads of which are pointed to by i and p. – By well formed we mean that memory on the heap is properly allocated for the lists and there are no loops in the data structures. The program maintains a well formed tree pointed to by r. t always points to an element in the tree rooted at r (or is equal to nil). The two lists and the tree do not share any nodes. Other than the memory used for the two lists and the tree, no other heap memory is allocated. The fld_t field of every element in both list structures points to an element in the tree.
Coq basics Proofs organized into trees Goals (or judgments) – What needs to be proven Tactics – A simple program or rule for performing a proof step – May generate subgoals – Primitives also referred to as tactics
Coq Goal { ? } WHILE not (T == 0) DO N := P; NEW P, 2;... { ? }
Program state Environment R=10 I=30 P=40 T=10 Heap e = { R → 10, I → 20, P → 30, T → 10 } h = {10 → 12, 11 → 18, 12 → 14, 13 → 16, 14 → 0, 15 → 0, 16 → 0, 17 → 0, 18 → 20, 19 → 0, 20 → 0, 21 → 0, …}
Program state Environment R=10 I=30 P=40 T=10 Heap e = { R → 10, I → 20, P → 30, T → 10 } h = {10 → 12, 11 → 18, 12 → 14, 13 → 16, 14 → 0, 15 → 0, 16 → 0, 17 → 0, 18 → 20, 19 → 0, 20 → 0, 21 → 0} (e,h) ⊨ ∃ v 0. TREE(R,v 0,2,[0,1]) X v 0 =[10, [12,[14,[0],[0]], [16,[0],[0]]], [18, [20,[0],[0]], [0]]] struct tree { struct tree *left; struct tree * right; }
Separation logic (e,h) ⊨ ∃ v 0 v 1 v 2 TREE(R,v 0,2,[0,1]) * TREE(I,v 1,2,[0]) * TREE(P,v 2,2,[0]) h={10 → 12,11 → 18,12 → 14,13 → 16,14 → 0,15 → 0,16 → 0,17 → 0,18 → 20, 19→ 0,20 → 0,21 → 0,30 → 32,31 → 10,32 → 0,33 → 12,40 → 42,41 → 14, 42 → 44,43 → 12,44 → 0,45 → 10}
Separation logic (e, h) ⊨ s1 ∗ s2 if and only if ∃ h′, h′′. (e,h′) ⊨ s1 ⋀ (e,h′′) ⊨ s2 ⋀ dom(h1)∩dom(h2)= ∅ ⋀ h=h′ ∪ h′′
Data structure relationships (e,h) ⊨ ∃ v 0 v 1 v 2 TREE(R,v 0,2,[0,1]) * TREE(I,v 1,2,[0]) * TREE(P,v 2,2,[0])
Data structure relationships (e,h) ⊨ ∃ v 0 v 1 v 2 TREE(R,v 0,2,[0,1]) * TREE(I,v 1,2[0]) * TREE(P,v 2,2,[0]) * ∀ v 3 ∈ TreeRecords(v 1 ). [nth(find(v 1,v 3 ),2) inTree v 0 ]
Data structure relationships (e,h) ⊨ ∃ v 0 v 1 v 2 TREE(R,v 0,2,[0,1]) * TREE(I,v 1,2[0]) * TREE(P,v 2,2,[0]) * ∀ v 3 ∈ TreeRecords(v 1 ). [nth(find(v 1,v 3 ),2) inTree v 0 ] * ∀ v 3 ∈ TreeRecords(v 2 ). [nth(find(v 2,v 3 ),2) inTree v 0 ]
Data structure relationships (e,h) ⊨ ∃ v 0 v 1 v 2 TREE(R,v 0,2,[0,1]) * TREE(I,v 1,2[0]) * TREE(P,v 2,2,[0]) * ∀ v 3 ∈ TreeRecords(v 1 ). [nth(find(v 1,v 3 ),2) inTree v 0 ] * ∀ v 3 ∈ TreeRecords(v 2 ). [nth(find(v 2,v 3 ),2) inTree v 0 ] * [T = 0 ∨ T inTree v 0 ] T →
Organization Basic Tree Example Invariants Tactics DPLL algorithm DPLL verification Challenges of large verifications CoqPIE GUI Conclusion
Summary of tactics Forward propagation Fold/unfold Merge – Works by pairing off identical pieces Simplify Entailment – Also works by pairing off
Verification of initialization { ∃ v0.TREE(R, v0, 2, [0,1])} T := R; I := 0; P := 0; { ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1).[nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2).[nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]}
Verification of initialization { ∃ v0.TREE(R, v0, 2, [0,1])} T := R; I := 0; P := 0; {?1234} Existential variable—a hole in the proof tree that is filled in as tactics are applied to prove the theorem
Verification of initialization { ∃ v0.TREE(R, v0, 2, [0,1])} T := R; I := 0; P := 0; {?1234}
Verification of initialization { ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R]} I := 0; P := 0; {?1234}
Verification of initialization { ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R]} I := 0; P := 0; {?1234}
Verification of initialization { ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0]} P := 0; {?1234}
Verification of initialization { ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0]} P := 0; {?1234}
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] -> ?1234
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] -> ?1234 ?1234 = ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0]
Verification of initialization ?1234 → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Verification of initialization ∃ v0.TREE(R, v0, 2, [0,1]) * [T=R] * [I = 0] * [P = 0] → ∃ v0. ∃ v1. ∃ v2. TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) ∗ TREE(P, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0] ∗ [T = 0 ∨ T inTree v0]
Unfold example { ∃ v0 ∃ v1 ∃ v2[Tmp l = 0] ∗ [l /= 0] ∗ [tmp r = 0] ∗ [Tmp r = 0 ∨ Tmp r ∈ TreeRecords(v0)] ∗ [nth(nth(find(v0,T)),2),0) = (Tmp r)] ∗ [nth(nth(find(v0, T )), 1), 0) = 0] ∗ [T ∈ TreeRecords(v0)] ∗ P + 0 → N ∗ P + 1 → T ∗ [T /= 0] ∗ TREE(R, v0, 2, [0,1]) ∗ TREE(I, v1, 2, [0]) * TREE(N, v2, 2, [0]) ∗ ∀ v3 ∈ TreeRecords(v1). [nth(find(v1,v3),2) inTree v0] ∗ ∀ v3 ∈ TreeRecords(v2). [nth(find(v2,v3),2) inTree v0]} ∗ T := ∗ (I+1); … {?1234} This is everything we know about the current state at a particular line of code
Unfold example ∃ v0 ∃ v1 ∃ v2 ∃ v3 ∃ v4 I + 1 → v1 ∗ I → nth(v0, 0) ∗ TREE(nth(v0, 0), nth([I, v0, v1], 1), 2, [0]) [Tmp r = 0 ∨ Tmp r ∈ TreeRecords(v0)] ∗ [nth(nth(find(v2,T)),2),0) = (Tmp r)] ∗ [nth(nth(find(v2, T )), 1), 0) = 0] ∗ [T ∈ TreeRecords(v2)] ∗ P+0→N ∗ P+1→ T ∗ [T /= 0] ∗ TREE(I, v1, 2, [0]) * [I + 1 → v1 ∗ I → nth(v0, 0)] ∗ TREE(nth(v0, 0), nth([I, v0, v1], 1), 2, [0]) ∗ TREE(R, v2, 2, [0,1]) ∗ Empty * TREE(N,v4,2,[0]) * ∀ v5 ∈ TreeRecords([I,v0,v1]). [nth(find([I,v0,v1)]),v5),2) inTree v2] ∗ ∀ v5 ∈ TreeRecords(v4). [nth(find(v4,v5),2) inTree v2]} T := ∗ (I+1);... {?1234}
Unfold example ∃ v0 ∃ v1 ∃ v2 ∃ v3 ∃ v4 ∃ v5 [T = v1] ∗ I + 1 → v2 ∗ I → nth(v1, 0) ∗ TREE(nth(v1, 0), nth([I, v1, v2], 1), 2, [0]) ∗ [Tmp r = 0 ∨ Tmp r ∈ TreeRecords(v1)] ∗ [nth(nth(find(v3,T)),2),0) = (Tmp r)] ∗ [nth(nth(find(v3,T )),1), 0) = 0] ∗ [T ∈ TreeRecords(v3)] ∗ P + 0 → N ∗ P + 1 → T ∗ [T ̸= 0] ∗ TREE(R, v3, 2, [0,1]) ∗ Empty ∗ TREE(N, v5, 2, [0]) ∗ ∀ v6 ∈ TreeRecords([I,v1,v2]). [nth(find([I,v1,v2],v6),2) inTree v3] ∗ ∀ v6 ∈ TreeRecords(v5). [nth(find(v5,v6),2) inTree v3]} {?1234}
Simplification Database of programs to simplify state assertions – Simplification algorithm repeatedly tries to apply each program until no further simplifications can be done
Simplification Contextual, consider Tree(R,v0,1,[0,1]) * [R=0] * [not(T inTree v0)] simplifies to: Tree(R,v0,1,[0,1]) * [R=0] * AbsEmpty
Simplification Contextual, consider Tree(R,v0,1,[0,1]) * [R==0] * [not(T inTree v0)] simplifies to: Tree(R,v0,1,[0,1]) * [R==0]
Organization Basic Tree Example Invariants Tactics DPLL algorithm DPLL verification Challenges of large verifications CoqPIE GUI Conclusion
Why Verify DPLL? DPLL (Davis–Putnam–Logemann–Loveland) well suited for studying invariant verification techniques – Invariant quite complex – Program relatively small
/425 Declarative Methods - J. Eisner 66 Basic DLL Procedure (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) slide thanks to Sharad Malik (modified)
/425 Declarative Methods - J. Eisner 67 Basic DLL Procedure (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) a slide thanks to Sharad Malik (modified)
/425 Declarative Methods - J. Eisner 68 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) Decision slide thanks to Sharad Malik (modified) a + Green means “crossed out”
/425 Declarative Methods - J. Eisner 69 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 Decision slide thanks to Sharad Malik (modified) a +
/425 Declarative Methods - J. Eisner 70 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 Decision slide thanks to Sharad Malik (modified) a + c +
/425 Declarative Methods - J. Eisner 71 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 d=1 c=0 (a + c + d) a=0 d=0 (a + c + d’) Conflict! Implication Graph (shows that the problem was caused by a=0 ^ c=0; nothing to do with b) slide thanks to Sharad Malik (modified) a + c + Unit clauses force both d=1 and d=0: contradiction
/425 Declarative Methods - J. Eisner 72 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 Backtrack slide thanks to Sharad Malik (modified) a +
/425 Declarative Methods - J. Eisner 73 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 d=1 c=1 (a + c’ + d) a=0 d=0 (a + c’ + d’) Conflict! 1 Other Decision slide thanks to Sharad Malik (modified) a + c’ +
/425 Declarative Methods - J. Eisner 74 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 1 Backtrack (2 levels) slide thanks to Sharad Malik (modified) a +
/425 Declarative Methods - J. Eisner 75 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c Other Decision slide thanks to Sharad Malik (modified) a + b’ +
/425 Declarative Methods - J. Eisner 76 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 d=1 c=0 (a + c’ + d) a=0 d=0 (a + c’ + d’) Conflict! 1 c 0 1 Decision slide thanks to Sharad Malik (modified) a + c +
/425 Declarative Methods - J. Eisner 77 Basic DLL Procedure a 0 b 0 c 0 1 c 0 1 Backtrack slide thanks to Sharad Malik (modified) (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) a + b’ +
/425 Declarative Methods - J. Eisner 78 (b’ + c’ + d) Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 d=1 c=1 (a + c’ + d) a=0 d=0 (a + c’ + d’) Conflict! 1 c Other Decision slide thanks to Sharad Malik (modified) b’ + c’ + a + c’ +
/425 Declarative Methods - J. Eisner 79 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 1 c Backtrack slide thanks to Sharad Malik (modified)
/425 Declarative Methods - J. Eisner 80 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 1 c Other Decision slide thanks to Sharad Malik (modified) a’ +
/425 Declarative Methods - J. Eisner 81 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 1 c b 0 Decision slide thanks to Sharad Malik (modified) a’ + b + Again choose b next (not required)
/425 Declarative Methods - J. Eisner 82 Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) b 0 c 0 1 c b 0 c=1 b=0 (a’ + b + c) a=1 c=0 (a’ + b + c’) Conflict! slide thanks to Sharad Malik (modified) a’ + b +
/425 Declarative Methods - J. Eisner 83 Basic DLL Procedure a 0 b 0 c 0 1 c b 0 Backtrack slide thanks to Sharad Malik (modified) (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) (a’ + b’ + c) a’ +
/425 Declarative Methods - J. Eisner 84 (a’ + b’ + c) Basic DLL Procedure a 0 (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (b’ + c’ + d) (a’ + b + c’) b 0 c 0 1 c b 0 1 a=1 b=1 c=1 (a’ + b’ + c) Other Decision slide thanks to Sharad Malik (modified) b’ + a’ + b’ + unit clause that propagates without contradiction (finally!) Often you get these much sooner
/425 Declarative Methods - J. Eisner 85 (b’ + c’ + d) Basic DLL Procedure a b 0 c 0 1 c b 0 1 a=1 b=1 c=1 (a’ + b’ + c)(b’ + c’ + d) d=1 0 slide thanks to Sharad Malik (modified) (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (a’ + b + c’) b’ + c’ + c 1 Forced by unit clause (a’ + b’ + c)
/425 Declarative Methods - J. Eisner 86 Basic DLL Procedure a b 0 c 0 1 c b 0 1 a=1 b=1 c=1 (a’ + b’ + c)(b’ + c’ + d) d=1 0 slide thanks to Sharad Malik (modified) (a + c + d) (a + c + d’) (a + c’ + d) (a + c’ + d’) (a’ + b + c) (a’ + b + c’) b’ + c’ + c 1 (a’ + b’ + c) d 1 Forced by unit clause SAT (b’ + c’ + d)
Watch variables Used to improve the performance of unit propagation - Always mark two variables in a clause A=1 A’ + C + D + E If possible, try and mark two unassigned variables
Watch variables If all but one variable assigned - Mark the unassigned variable as a watch - Mark the most recently assigned variable - The one unassigned variable is propagated A=1, E=0, C = 0 A’ + C + D + E Watch variables—only one is unassigned We can infer D=1 here
Watch variables Final case—one assignment satisfies clause - Any two variables can be marked as watch * except those assigned before satisfying assignment A=1, C=1, D=0 A’ + C + D + E This assignment satisfies the clause
Organization Basic Tree Example Invariants Tactics DPLL algorithm DPLL verification Challenges of large verifications CoqPIE GUI Conclusion
DPLL verification Simplified DPLL algorithm – No learning – 200 lines of C code – Translated by hand to Coq based imperative language Invariant – About 100 lines of Coq code
Data structure #define VAR_COUNT 4 char assignments[VAR_COUNT]; struct clause { struct clause *next; char positive_lit[VAR_COUNT]; char negative_lit[VAR_COUNT]; char watch_var[VAR_COUNT]; struct clause *watch_next[VAR_COUNT]; struct clause *watch_prev[VAR_COUNT]; } *clauses; struct clause *watches[VAR_COUNT]; struct assignments_to_do { struct assignments_to_do *next, *prev; int var; char value; int unit_prop; } *assignments_to_do_head, *assignments_to_do_tail; struct assignment_stack { struct assignment_stack *next; int var; char value; char unit_prop; } *stack;
DPLL invariant Definition invariant: absStateBasic := (AbsExistsT (AbsExistsT (AbsExistsT (AbsExistsT (AbsExistsT ( TREE(!!clauses,v(0),#sizeof_clause,(#next_offset::nil)) ** TREE(!!assignments_to_do_head,v(1),#sizeof_assignment_stack,(#next_offset::n il)) ** TREE(!!stack,v(2),#sizeof_assignment_stack,(#next_offset::nil)) ** ARRAY(!!assignments,#var_count,v(3)) ** ARRAY(!!watches,#var_count,v(4)) ** (* Assertions that the stack and assignments array contain the same set of assignments *) (AbsAll TreeRecords(v(2)) ([--(v(2),v(5))-->stack_var_offset <<<< #var_count] ** ([--(v(2),v(5))-->stack_val_offset ==== #1] *\/* [--(v(2),v(5))-- >stack_val_offset ==== #2]) ** ([nth(v(3),--(v(2),v(5))-->stack_var_offset)====--(v(2),v(5))-- >stack_val_offset]) ** (AbsAll TreeRecords(nth(find(v(2),v(5)),#2)) ([~~(--(v(2),v(5))-->stack_var_offset====--(nth(find(v(2),v(5)),#2),v(6))- ->stack_var_offset)])))) ** (AbsAll range(#0,#(var_count)) ([nth(v(3),v(5))====#0] *\/* AbsExists (TreeRecords(v(2))) ([(--(v(2),v(6))-->stack_var_offset====v(5) //\\ --(v(2),v(6))-->stack_val_offset====nth(v(3),v(5)))]) )) ** (* Assertion defining the prev pointer in the assignments_to_do doubly linked list *) (AbsAll TreeRecords(v(1)) ([(--(v(1),v(5))-->prev_offset====#0 //\\ (!!assignments_to_do_head)====v(5)) \\// (--(v(1),v(5))-->prev_offset inTree v(1) //\\ --(v(1),--(v(1),v(5))-->prev_offset)-->next_offset====v(5))])) ** (AbsEach range(#0,#(var_count)) (* Define the basic linked list connecting the watch variables inside the clauses linked list *) (AbsExistsT ((Path((nth(v(4),v(5))), v(0), v(6), #sizeof_clause, ((#watch_next_offset++++v(5))::nil))) ** (* Define the prev variable and the fact that if null we are at the head of the list *) (AbsAll TreeRecords(v(6)) ([(--(v(6),v(7))--->(#watch_prev_offset++++v(5))====#0 //\\ nth(v(4),v(5))====v(6)) \\// (--(v(6),--(v(6),v(7))--->(#watch_prev_offset++++v(5)))--- >(#watch_next_offset++++v(5)))====v(7)]))))) ** (AbsAll TreeRecords(v(0)) (* The current assignment is consistent with the clause *) ((AbsExists range(#0,#(var_count)) ([(--(v(0),v(5))--->(#positive_lit_offset++++v(6)) //\\ (nth(v(3),v(6))====#2 \\// nth(v(3),v(6))====#0)) \\// (--(v(0),v(5))--->(#negative_lit_offset++++v(6)) //\\ (nth(v(3),v(6))====#1 \\// nth(v(3),v(6))====#0))])) ** (* * make sure that if the watch_var field is non-zero (pointing to * a variable) that watch_next and watch_prev put this clause into * the linked list for the watch variable. * Also, for all watch variables, either positive_lit or negative_lit * is true. *) (AbsAll range(#0,#(var_count)) ([ (--(v(0),v(5))--->(#watch_var_offset++++v(6))====#0) \\// (--(v(0),v(5))--->(#positive_lit_offset++++v(6))) \\// (--(v(0),v(5))--->(#negative_lit_offset++++v(6)))])) ** (AbsAll range(#0,#(var_count)) ([ (~~(--(v(0),v(5))--->(#watch_var_offset++++v(6))====#0) //\\ (~~(--(v(0),v(5))--->(#watch_prev_offset++++v(6))====#0) \\// nth(v(4),v(6))====v(5))) \\// (--(v(0),v(5))--->(#watch_var_offset++++v(6))====#0 //\\ --(v(0),v(5))--->(#watch_prev_offset++++v(6))====#0 //\\ ~~(nth(v(4),v(6))====v(5)))])) ** (* Make sure there are precisely two watch variables per clause or all variables are watches, needs fixing? *) (SUM(range(#0,#(var_count)),ite((--(v(0),v(5))--- >(#watch_var_offset++++v(6))),(#1),(#0)),#2)) ** (* Watch variable invariant--case 1: All but one variable in the clause are assigned, any watch variable pointing to an assigned variable is pointing to a variable that was assigned after all other assigned variables in the clause. Also, one of the two watch variables points to the one unassigned variable *) ((((SUM(range(#0,#(var_count)), (((--(v(0),v(5))--->(#positive_lit_offset++++v(6))) \\// (--(v(0),v(5))--- >(#negative_lit_offset++++v(6)))) //\\ ite(nth(v(3),v(6))====#0,#1,#0)), #1) ** (* The one unassigned literal is a watch--needs fixing? *) (AbsAll range(#0,#(var_count)) ([(#0 (#watch_var_offset++++v(6)) //\\ (nth(v(3),v(6))====#0)) \\// ( ((#0 (#positive_lit_offset++++v(6))====#0 //\\ --(v(0),v(5))--->(#negative_lit_offset++++v(6))====#0))))])) ** (AbsAll range(#0,#(var_count)) (([--(v(0),v(5))--->(#watch_var_offset++++v(6)) \\// ((((--(v(0),v(5))--->(#positive_lit_offset++++v(6)))====#0 //\\ (-- (v(0),v(5))--->(#negative_lit_offset++++v(6))====#0)))) \\// ~~(--(v(0),v(5))--->(#watch_var_offset++++v(7))) \\// nth(v(3),v(6))====#0 \\// nth(v(3),v(7))====#0 \\// v(6)====v(7)]) *\/* (AbsExists TreeRecords(v(2)) (([--(v(2),v(8))-->stack_var_offset====v(7)]) ** (AbsExists TreeRecords(find(v(2),v(8))) ([--(v(2),v(9))-->stack_var_offset====v(6)])))))))))) *\/* (* Watch variable invariant case 2: One of the assignments already satisfies the clause, if a watch variable is assigned a value, then that value must be a satisfying assignment or occured after a satisfying assignment *) ( (AbsExists range(#0,#(var_count)) ([(--(v(0),v(5))--->(#positive_lit_offset++++v(6)) //\\ nth(v(3),v(6))====#2) \\// (--(v(0),v(5))--->(#negative_lit_offset++++v(6)) //\\ nth(v(3),v(6))====#1)])) ** (AbsAll range(#0,#(var_count)) ((([#0====nth(v(3),v(6))]) *\/* ([--(v(0),v(5))--->(#watch_var_offset++++v(6))====#0]) ** ([#0<<<<nth(v(3),v(6))])) *\/* (AbsExists TreeRecords(v(2)) (([--(v(2),v(7))-->stack_var_offset====v(6)]) ** (AbsExists TreeRecords(find(v(2),v(7))) ([((#0 (#positive_lit_offset (v(2),v(8))-- >stack_var_offset))) //\\ --(v(2),v(8))-->stack_val_offset====#2) \\// ((#0 (#negative_lit_offset (v(2),v(8))-- >stack_var_offset)) //\\ --(v(2),v(8))-->stack_val_offset====#1)]))))))) *\/* (* Watch variable invariant case 3: both watch variables point to unassigned variables *) (AbsAll range(#0,#(var_count)) ([--(v(0),v(5))--->(#watch_var_offset++++v(6))====#0 \\// nth(v(3),v(6))====#0])) ))))))))).
DPLL invariant The first part of the invariant are spatial constructs asserting the two arrays and three dynamic data structures in the heap. ARRAY(root, count, functional_representation) is a spatial predicate for arrays. The functional representation is a list of the elements. AbsExistsT v0. AbsExistsT v1. AbsExists v2. AbsExistsT v3. AbsExistsT v4. TREE(clauses,v0,sizeof_clause,[next_offset])) * TREE(assignments_to_do_head,v1,sizeof_assignment_stack,[next_offset]) * TREE(stack,v2,sizeof_assignment_stack,[next_offset]) * ARRAY(assignments,var_count,v3) * ARRAY(watches,var_count,v4) * Next, we add on two assertions that guarantee that both the assignment_stack v2 and assignment array v3 are consistent. We use (a,b)--->c as an abbreviation for nth(find(a,b),c). (AbsAll v5 in TreeRecords(v2). ([nth(v3,(v2,v5)-->stack_var_offset)==(v2,v5)-->stack_val_offset])) * (AbsAll v5 in range(0,var_count-1). ([nth(v3,v5)==0] *\/* AbsExists v6 in (TreeRecords(v2)). ([((v2,v6)-->stack_var_offset==v5 /\ (v2,v6)-->stack_val_offset==nth(v3,v5))]) )) * …
Initial observations Many tactics work without revision – Forward propagation – Pairing off for merge Some tactics need variants – Fold/unfold Many new simplification rules Unfortunately, some entailment proofs are quite difficult
Entailment Code to remove the most recent assignment: var = stack->var; value = stack->value; struct stack *n = stack->next; free(stack); stack = n; assignments[var] = 0; Does not change any watch variables
Watch variable invariant cases 1)The two watch variables are unassigned 2)All but one variable is assigned in the clause. One of the watch variables is the unassigned variable. The other is the most recently assigned variable 3)At least one of the assignments satisfies the clause. If one or both watch variables are assigned, then those assignments were either a satisfying assignment or done after the first satisfying assignment. A + B’ + C + D’ Watch variables
Watch variable invariant cases 1)The two watch variables are unassigned 2)All but one variable is assigned in the clause. One of the watch variables is the unassigned variable. The other is the most recently assigned variable 3)At least one of the assignments satisfies the clause. If one or both watch variables are assigned, then those assignments were either a satisfying assignment or done after the first satisfying assignment. A + B’ + C + D’ Watch variables A=0
Watch variable invariant cases 1)The two watch variables are unassigned 2)All but one variable is assigned in the clause. One of the watch variables is the unassigned variable. The other is the most recently assigned variable 3)At least one of the assignments satisfies the clause. If one or both watch variables are assigned, then those assignments were either a satisfying assignment or done after the first satisfying assignment. A + B’ + C + D’ Watch variables A=0 B=1
Watch variable invariant cases 1)The two watch variables are unassigned 2)All but one variable is assigned in the clause. One of the watch variables is the unassigned variable. The other is the most recently assigned variable 3)At least one of the assignments satisfies the clause. If one or both watch variables are assigned, then those assignments were either a satisfying assignment or done after the first satisfying assignment. A + B’ + C + D’ Watch variables A=0 B=1 C=0
Watch variable invariant cases 1)The two watch variables are unassigned 2)All but one variable is assigned in the clause. One of the watch variables is the unassigned variable. The other is the most recently assigned variable 3)At least one of the assignments satisfies the clause. If one or both watch variables are assigned, then those assignments were either a satisfying assignment or done after the first satisfying assignment. A + B’ + C + D’ Watch variables A=0
Watch variable invariant cases 1)The two watch variables are unassigned 2)All but one variable is assigned in the clause. One of the watch variables is the unassigned variable. The other is the most recently assigned variable 3)At least one of the assignments satisfies the clause. If one or both watch variables are assigned, then those assignments were either a satisfying assignment or done after the first satisfying assignment. A + B’ + C + D’ Watch variables A=0 B=0
Watch variable invariant cases 1)The two watch variables are unassigned 2)All but one variable is assigned in the clause. One of the watch variables is the unassigned variable. The other is the most recently assigned variable 3)At least one of the assignments satisfies the clause. If one or both watch variables are assigned, then those assignments were either a satisfying assignment or done after the first satisfying assignment. A + B’ + C + D’ Watch variables A=0 B=1 D=0
Watch variable invariant cases 1)The two watch variables are unassigned 2)All but one variable is assigned in the clause. One of the watch variables is the unassigned variable. The other is the most recently assigned variable 3)At least one of the assignments satisfies the clause. If one or both watch variables are assigned, then those assignments were either a satisfying assignment or done after the first satisfying assignment. A + B’ + C + D’ Watch variables A=0 B=1
Proof info Six cases 1)Two watch variables are assigned before. 2)All but one variable is assigned but the assignment removed does not appear in the clause 3)All but one variable is assigned and the assignment removed does appear in the clause 4)At least one of the assignments satisfies the clause. The one and only satisfying assignment is the variable being removed 5)At least one of the assignments satisfies the clause. The one assignment removed is not a satisfying assignment. 6)At least two of the assignments satisfies the clause. The one assignment removed is a satisfying assignment. The proof that the invariant holds took over 2000 lines of Coq proof script code.
Organization Basic Tree Example Invariants Tactics DPLL algorithm DPLL verification Challenges of large verifications CoqPIE GUI Conclusion
Performance Issues – Coq slows down substantially with a complex proof Applying a single tactic can take 30 seconds Coq crashes if a proof becomes too large – Inversion of a large hypothesis crashes Coq – Generating more than 100 subgoals crashes Coq Solutions – Break proofs into smaller pieces Use lemmas to avoid case splits – Eliminate unnecessary hypotheses – Extract pieces of a hypothesis
Replay Errors in invariant – discovered while working on proof – All previous proofs have to be updated – For a complex proof, several invariant changes
Sample Proof Tree mergeTheorem1 Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux1 Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux1 Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux1 Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux1 Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 Invariant mergeTheorem1aux4b
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Sample Proof Tree mergeTheorem1 mergeTheorem1aux2 mergeTheorem1aux3 mergeTheorem1aux4 mergeTheorem1aux5 mergeTheorem1aux6 mergeTheorem1aux7 mergeTheorem1aux1 mergeTheorem1aux8 mergeTheorem1aux4b mergeTheorem1aux9 mergeTheorem1aux9b Invariant
Organization Basic Tree Example Invariants Tactics DPLL algorithm DPLL verification Challenges of large verifications CoqPIE GUI Conclusion
GUI basics Python based – About 9000 lines of code – Good scripting language for tactics Tkinter (Tk/Tcl) for UI
GUI features Full project management Hierarchical browser – Just click to view definition and proof step Dependency management – Colors to highlight proofs that need to be updated All intermediate goal states cached – Allows quick review of proof Difference highlighting Replay Tools for splitting proofs/eliminating hypotheses
GUI modules Basic classes for UI window Tools to manage projects – Maintain the set of source files and dependencies Coqtop process manager Coq syntax parser (over 50% of the code) – UI has no semantics Pattern matching library to facilitate scripts
Organization Basic Tree Example Invariants Tactics DPLL algorithm DPLL verification Challenges of large verifications CoqPIE GUI Conclusion
Results (so far) Tree traversal – Code size: ~30 lines – Invariant size: ~10 lines – Proof check time: ~5 minutes – Main proof size: ~220 lines – Status: top level complete, lemmas need to be proven DPLL (A decision procedure for sentential satisfiability) – Code size: ~200 lines – Invariant size: ~100 lines – Verification size: 3000 lines (so far) – Status: Proof incomplete CoqPIE – Basic viewing/editing done – Replay and theorem splitting tactics to be implemented next
Related research
Research contributions Understanding of issues in scaling up Coq based separation logic to larger verification problems – Development of a UI to address these issues – Development of tactics for reasoning about the more complicated invariants
Final thoughts This framework could have found Heartbleed if applied to OpenSSL – Consider the economics if the cost of verification is 10x the cost of development A practical system could be deployed and many major software systems verified by 2020