Smallfoot program verification with separation logic by O Hearn et al. Anders Møller <amoeller@cs.au.dk>
Plan Hoare logic + pointers and functions Separation logic Smallfoot 2 / 20
Hoare logic and pointers Consider the standard axiom for assignment: {Q[E/X]} X=E; {Q} Example: {y+7>42} x=y+7; {x>42} This doesn t work with pointers! Example: {y.a=42} x.a=c; {y.a=42} aliasing? 3 / 20
Morris general axiom of assignment Idea: encode all possible aliasing scenarios Assume for simplicity that Y is the only heap reference in Q {(X=Y Q[E / Y.F]) (X Y Q)} X.F=E; {Q} Example: {(x=y c=42) (x y y.a=42)} x.a=c; {y.a=42} This works, but it gives a blow-up in formula size it results in global reasoning We want simpler proofs! 4 / 20
Hoare logic and function calls Let P pre and P post be the pre/post-conditions of a function f??? {Q} {R} x=f(y) Proof obligations (ignore parameter and return value passing): Q P pre P post R??? this is too weak! ( the frame problem ) we want modular reasoning! 5 / 20
Example: Reversing a linked list struct Node { struct Node *n; int data; } Node *reverse(node *x) { Node *y, *t; y = NULL; while (x!= NULL) { t = y; y = x; x = x->n; y->n = t; } return y; } Assume that the input is an acyclic list, argue that there are no null pointer dereferences no elements are lost the output is an acyclic list the output is the reverse of the input no other parts of the heap are modified 6 / 20
Reversing a linked list Consider a possible loop invariant: α,β: LIST α (x) LIST β (y) α 0R = R α β Unfortunately, it is not enough: we must explicitly forbid sharing between the x and y lists we must explicitly state that every other part of the heap is unaffected! 7 / 20
Plan Hoare logic + pointers and functions Separation logic Smallfoot 8 / 20
Separation logic New assertions: emp (empty heap) E F 1 :E 1,..,F n :E n (one-record heap) P * Q (separating conjunction) assertions describe heaplets, not global heaps! 9 / 20
Examples (x a:42, b:nil) * (y a:42, b:nil) x,y are not aliases (x a:42, b:nil) (y a:42, b:nil) x,y are aliases ((x a:42, b:nil) * true) ((y a:42, b:nil) * true) x,y may be aliases (x a:7, b:y) * (y a:87, b:x) 2-node cyclic list 10 / 20
Axioms Axiom for assignment to the heap ( mutation ): mutation): { } { } {X ρ, F:_,σ} X.F = E; ; {X ρ,f:e,σ} Axiom for assignment from the heap ( lookup ): { ρ,, } { ρ,, } {Y ρ,f:v,σ} X = Y.F; ; {X=V Y ρ,f:v,σ} - variants for backwards reasoning also exist - allocation/disposal, pointer arithmetic, etc., also work 11 / 20
The frame rule, local reasoning {P} S S {Q} {P{ * R} {Q{ * R} All heap cells that are not mentioned in the specification are guaranteed to remain unchanged! Many other new inference rules... Loop invariant for the list reversal example: α,β: (LIST α (x) * LIST β (y)) α 0R = R α β 12 / 20
Other issues Logical variables/predicates are often used in proofs Classical Hoare logic is relatively complete this extension does not preserve that property... New assertion languages? (beyond predicate logic, e.g. to express isomorphisms) Concurrent languages?, code pointers?,... 13 / 20
Plan Hoare logic + pointers and functions Separation logic Smallfoot 14 / 20
Smallfoot A step towards automated program verification with separation logic Requires pre/post-conditions and loop invariants Also supports concurrent extension of separation logic The general verification problem is undecidable predicate logic... data structures specified by inductive definitions... applying the frame rule is not trivial... 15 / 20
The approach Hardwired reasoning about a small collection of list and tree structures Limits the assertion language: only allowing conjunctions of pure boolean conditions *-combination of heap predicates (e.g. no quantifiers, no general inductive reasoning) Generates verification condition for each Hoare triple using a technique of symbolic execution Verifies VCs (easy, because of the limited assertion language) reminiscent of PALE... 16 / 20
Demo reverse.sf list_reverse(o,i) [list(i)] { local t; o = NULL; while (i!= NULL) [list(i) * list(o)] { t = i->tl; i->tl = o; o = i; i = t; } } [list(o)] Properties being verified: there are no null pointer dereferences no elements are lost the output is an acyclic list the output t is the reverse of the input no other parts of the heap are modified similar to PALE cannot be expressed in the annotation language of Smallfoot using the frame rule! 17 / 20
Demo VERIFICATION CONDITION: [listseg(tl; i, 0)] o=0; fcall({i, o, t},listseg(tl; i, 0) * listseg(tl; o, 0), 0==i * listseg(tl; i, 0) * listseg(tl; o, 0)); [listseg(tl; o, 0)] VERIFICATION CONDITION: [0!=i * listseg(tl; i, 0) * listseg(tl; o, 0)] t=i->tl; i->tl=o; o=i; i=t; [listseg(tl; i, 0) * listseg(tl; o, 0)] Valid 18 / 20
Demo If we accidentally swap two lines in the loop: File "reverse-bug.sf", line 4, characters 2-97: ERROR invalid entailment: loop exit 0!=o * o_2!=o * o!=t * o -> tl:o * listseg(tl; t, 0) * listseg(tl; o_2, 0) - listseg(tl; t, 0) * listseg(tl; o, 0) NOT Valid 19 / 20
Conclusion Separation logic extends Hoare logic with pointers key idea: separating conjunction (P*Q) Permits local reasoning (the frame rule) Smallfoot: the first tool based on separation logic automated verification for simple data structures and simple properties (limited assertion language) 20 / 20