Full Functional Verification of Linked Data Structures Karen Zee , - - PowerPoint PPT Presentation

full functional verification of linked data structures
SMART_READER_LITE
LIVE PREVIEW

Full Functional Verification of Linked Data Structures Karen Zee , - - PowerPoint PPT Presentation

Full Functional Verification of Linked Data Structures Karen Zee , Viktor Kuncak , and Martin Rinard MIT CSAIL EPFL, I&C Goal Verify full functional correctness of linked data structure implementations What is Full


slide-1
SLIDE 1

Full Functional Verification of Linked Data Structures

Karen Zee†, Viktor Kuncak‡, and Martin Rinard†

†MIT CSAIL

‡EPFL, I&C

slide-2
SLIDE 2

Goal

Verify full functional correctness of linked data structure implementations

slide-3
SLIDE 3

What is Full Functional Correctness?

  • Complete, precise formal specification
  • Captures every property client needs

(except resource consumption)

  • Implementation satisfies specification
slide-4
SLIDE 4

Benefits of Full Functional Correctness

  • Complete, precise, unambiguous interfaces

for linked data structures

  • Enables sound reasoning with specification

(can discard implementation when reasoning)

  • Human developers
  • Automated analyses of client code
  • First complete realization of concept of

abstract data types

slide-5
SLIDE 5

Example

slide-6
SLIDE 6

Hashtable Specification

class Hashtable { //: public ghost specvar content :: “(obj * obj) set” = “{}”; //: public ghost specvar init :: “bool” = “false”; public Object put(Object key, Object value) /*: requires “init ∧ key ≠ null ∧ value ≠ null” modifies content ensures “content = old content - {(key, result)} ∪ {(key, value)} ^ (result = null → ¬(∃v. (key, v) ∈ old content)) ∧ (result ≠ null → (key, result) ∈ old content)” */ { … } … }

  • Specifications at class granularity
  • Specifications appear as comments
  • Can use standard Java compilers
slide-7
SLIDE 7

Abstract State as Sets, Relations

class Hashtable { //: public ghost specvar content :: “(obj * obj) set” = “{}”; //: public ghost specvar init :: “bool” = “false”; public Object put(Object key, Object value) /*: requires “init ∧ key ≠ null ∧ value ≠ null” modifies content ensures “content = old content - {(key, result)} ∪ {(key, value)} ^ (result = null → ¬(∃v. (key, v) ∈ old content)) ∧ (result ≠ null → (key, result) ∈ old content)” */ { … } … }

  • Represent abstract state using

specification variables

  • Contents of hash table as set
  • f key-value pairs
slide-8
SLIDE 8

Method Preconditions, Postconditions

class Hashtable { //: public ghost specvar content :: “(obj * obj) set” = “{}”; //: public ghost specvar init :: “bool” = “false”; public Object put(Object key, Object value) /*: requires “init ∧ key ≠ null ∧ value ≠ null” modifies content ensures “content = old content - {(key, result)} ∪ {(key, value)} ^ (result = null → ¬(∃v. (key, v) ∈ old content)) ∧ (result ≠ null → (key, result) ∈ old content)” */ { … } … }

  • Standard assume-guarantee reasoning

for method interfaces

  • Pre-, post-conditions in higher-order

logic (HOL)

slide-9
SLIDE 9

Requires Clause

class Hashtable { //: public ghost specvar content :: “(obj * obj) set” = “{}”; //: public ghost specvar init :: “bool” = “false”; public Object put(Object key, Object value) /*: requires “init ∧ key ≠ null ∧ value ≠ null” modifies content ensures “content = old content - {(key, result)} ∪ {(key, value)} ^ (result = null → ¬(∃v. (key, v) ∈ old content)) ∧ (result ≠ null → (key, result) ∈ old content)” */ { … } … }

Pre-condition requires that key and value be non-null

slide-10
SLIDE 10

Modifies Clause

class Hashtable { //: public ghost specvar content :: “(obj * obj) set” = “{}”; //: public ghost specvar init :: “bool” = “false”; public Object put(Object key, Object value) /*: requires “init ∧ key ≠ null ∧ value ≠ null” modifies content ensures “content = old content - {(key, result)} ∪ {(key, value)} ^ (result = null → ¬(∃v. (key, v) ∈ old content)) ∧ (result ≠ null → (key, result) ∈ old content)” */ { … } … }

  • Modifies clause gives frame condition
  • put method modifies only content
slide-11
SLIDE 11

Ensures Clause

class Hashtable { //: public ghost specvar content :: “(obj * obj) set” = “{}”; //: public ghost specvar init :: “bool” = “false”; public Object put(Object key, Object value) /*: requires “init ∧ key ≠ null ∧ value ≠ null” modifies content ensures “content = old content - {(key, result)} ∪ {(key, value)} ^ (result = null → ¬(∃v. (key, v) ∈ old content)) ∧ (result ≠ null → (key, result) ∈ old content)” */ { … } … }

  • Previous key-value binding is removed
  • New binding is added
slide-12
SLIDE 12

Ensures Clause

class Hashtable { //: public ghost specvar content :: “(obj * obj) set” = “{}”; //: public ghost specvar init :: “bool” = “false”; public Object put(Object key, Object value) /*: requires “init ∧ key ≠ null ∧ value ≠ null” modifies content ensures “content = old content - {(key, result)} ∪ {(key, value)} ^ (result = null → ¬(∃v. (key, v) ∈ old content)) ∧ (result ≠ null → (key, result) ∈ old content)” */ { … } … }

Returns previously-bound value or null

slide-13
SLIDE 13

Hashtable Data Structure

k0 v0 k1 v1 k2 v2 k3 v3 k4 v4 k5 v5

slide-14
SLIDE 14

Hashtable Data Structure

k0 v0 k1 v1 k2 v2 k3 v3 k4 v4 k5 v5

Abstraction {< , >, …, < , >}

k0 v0 kn vn

slide-15
SLIDE 15

Abstraction Function

  • Invariants
  • Dependent specification

variables

/*: invariant ContentDef: “init → content = {(k,v). (∃ i. 0 ≤ i ∧ i < table.length ∧ (k,v) ∈ table[i].bucketContent)}” static ghost specvar bucketContent :: “obj ⇒ (obj * obj) set” = “λ n. {}” invariant bucketContentNull: “null.bucketContent = {}” invariant bucketContentDef: “∀x. x ∈ Node ∧ x ∈ alloc ∧ x ≠ null → x.bucketContent = {<x.key, x.value>} ∪ x.next.bucketContent ∧ (∀v. (x.key, v) ∉ x.next.bucketContent)” invariant Coherence: “init → (∀ i k v. (k,v) ∈ table[i].bucketContent → i = hash k table.length)” static specvar hash :: “obj ⇒ int ⇒ int” vardefs “hash == λ k. (λ n. (abs (hashFunc k)) mod n)” static specvar abs :: “int ⇒ int” vardefs “abs == λ m. (if (m < 0) then -m else m)” … */

slide-16
SLIDE 16

Abstraction Function

Hash table contents consists of the contents

  • f all the buckets

/*: invariant ContentDef: “init → content = {(k,v). (∃ i. 0 ≤ i ∧ i < table.length ∧ (k,v) ∈ table[i].bucketContent)}” static ghost specvar bucketContent :: “obj ⇒ (obj * obj) set” = “λ n. {}” invariant bucketContentNull: “null.bucketContent = {}” invariant bucketContentDef: “∀x. x ∈ Node ∧ x ∈ alloc ∧ x ≠ null → x.bucketContent = {<x.key, x.value>} ∪ x.next.bucketContent ∧ (∀v. (x.key, v) ∉ x.next.bucketContent)” invariant Coherence: “init → (∀ i k v. (k,v) ∈ table[i].bucketContent → i = hash k table.length)” static specvar hash :: “obj ⇒ int ⇒ int” vardefs “hash == λ k. (λ n. (abs (hashFunc k)) mod n)” static specvar abs :: “int ⇒ int” vardefs “abs == λ m. (if (m < 0) then -m else m)” … */

slide-17
SLIDE 17

Abstraction Function

  • Contents of each bucket

defined recursively over linked list

  • Keys are unique

/*: invariant ContentDef: “init → content = {(k,v). (∃ i. 0 ≤ i ∧ i < table.length ∧ (k,v) ∈ table[i].bucketContent)}” static ghost specvar bucketContent :: “obj ⇒ (obj * obj) set” = “λ n. {}” invariant bucketContentNull: “null.bucketContent = {}” invariant bucketContentDef: “∀x. x ∈ Node ∧ x ∈ alloc ∧ x ≠ null → x.bucketContent = {<x.key, x.value>} ∪ x.next.bucketContent ∧ (∀v. (x.key, v) ∉ x.next.bucketContent)” invariant Coherence: “init → (∀ i k v. (k,v) ∈ table[i].bucketContent → i = hash k table.length)” static specvar hash :: “obj ⇒ int ⇒ int” vardefs “hash == λ k. (λ n. (abs (hashFunc k)) mod n)” static specvar abs :: “int ⇒ int” vardefs “abs == λ m. (if (m < 0) then -m else m)” … */

slide-18
SLIDE 18

Abstraction Function

Every key is in the correct bucket

/*: invariant ContentDef: “init → content = {(k,v). (∃ i. 0 ≤ i ∧ i < table.length ∧ (k,v) ∈ table[i].bucketContent)}” static ghost specvar bucketContent :: “obj ⇒ (obj * obj) set” = “λ n. {}” invariant bucketContentNull: “null.bucketContent = {}” invariant bucketContentDef: “∀x. x ∈ Node ∧ x ∈ alloc ∧ x ≠ null → x.bucketContent = {<x.key, x.value>} ∪ x.next.bucketContent ∧ (∀v. (x.key, v) ∉ x.next.bucketContent)” invariant Coherence: “init → (∀ i k v. (k,v) ∈ table[i].bucketContent → i = hash k table.length)” static specvar hash :: “obj ⇒ int ⇒ int” vardefs “hash == λ k. (λ n. (abs (hashFunc k)) mod n)” static specvar abs :: “int ⇒ int” vardefs “abs == λ m. (if (m < 0) then -m else m)” … */

slide-19
SLIDE 19

Abstraction Function

/*: invariant ContentDef: “init → content = {(k,v). (∃ i. 0 ≤ i ∧ i < table.length ∧ (k,v) ∈ table[i].bucketContent)}” static ghost specvar bucketContent :: “obj ⇒ (obj * obj) set” = “λ n. {}” invariant bucketContentNull: “null.bucketContent = {}” invariant bucketContentDef: “∀x. x ∈ Node ∧ x ∈ alloc ∧ x ≠ null → x.bucketContent = {<x.key, x.value>} ∪ x.next.bucketContent ∧ (∀v. (x.key, v) ∉ x.next.bucketContent)” invariant Coherence: “init → (∀ i k v. (k,v) ∈ table[i].bucketContent → i = hash k table.length)” static specvar hash :: “obj ⇒ int ⇒ int” vardefs “hash == λ k. (λ n. (abs (hashFunc k)) mod n)” static specvar abs :: “int ⇒ int” vardefs “abs == λ m. (if (m < 0) then -m else m)” … */

set expressions quantifiers lambda expressions

slide-20
SLIDE 20

Loop Invariants

public Object get(Object k0) /*: requires “init ∧ k0 ≠ null” ensures “(result ≠ null → (k0, result) ∈ content) ∧ (result = null → ¬(∃v. (k0, v) ∈ content))” */ { int hc = compute_hash(k0); Node current = table[hc]; while /*: inv “∀v. ((k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent)” */ (current != null) { if (current.key == k0) { return current.value; } current = current.next; } return null; }

Source of Invariants

  • Inferred by system
  • Provided by developer
  • Inferred by shape analysis
slide-21
SLIDE 21

Generating Verification Conditions

  • Convert to guarded commands
  • Apply weakest liberal pre-conditions

program specification desugar guarded commands wlp verification condition

slide-22
SLIDE 22

Verification Condition for Hashtable.put

128 KB

slide-23
SLIDE 23

How to prove?

slide-24
SLIDE 24

Available Provers

  • Syntactic provers
  • Nelson-Oppen provers
  • Resolution-based provers
  • Decision procedures
  • Monadic second-order logic
  • BAPA
  • Proof assistants

prover1 provern prover0 fast & dumb slow & smart

slide-25
SLIDE 25

prover1 provern prover0 fast & dumb slow & smart verification condition

slide-26
SLIDE 26

prover1 provern prover0 verification condition formula splitter fast & dumb slow & smart

slide-27
SLIDE 27

prover1 provern prover0 verification condition formula splitter

slide-28
SLIDE 28

prover1 provern prover0 verification condition formula splitter

slide-29
SLIDE 29

prover1 provern prover0 verification condition formula splitter

slide-30
SLIDE 30

prover1 provern prover0 verification condition formula splitter

slide-31
SLIDE 31

prover1 provern prover0 verification condition formula splitter

slide-32
SLIDE 32

prover1 provern prover0 verification condition formula splitter

slide-33
SLIDE 33

prover1 provern prover0 HOL verification condition formula splitter HOL formulas

slide-34
SLIDE 34

prover1 provern prover0 verification condition formula splitter HOL formulas formula approximation

slide-35
SLIDE 35

prover1 provern prover0 verification condition formula splitter HOL formulas formula approximation

slide-36
SLIDE 36

prover1 provern prover0 verification condition formula splitter HOL formulas formula approximation

Integrated Reasoning

slide-37
SLIDE 37

Integrated Reasoning In Jahob

prover1 manual proof syntactic prover verification condition formula splitter HOL formulas formula approximation

slide-38
SLIDE 38

Formula Splitting

  • Transform verification condition into

equivalent conjunction of smaller formulas A → G1 ∧ G2

A → G1, A → G2 A → (B → G[p])[q]

(A ∧ B[q]) → G[pq] A → ∀x.G

A → G[x:=xfresh]

  • Enables application of different solvers to

solve different parts of verification condition

slide-39
SLIDE 39

Formula Approximation

  • Feed any formula to any prover or decision procedure
  • Approximate given formula with a stronger formula in appropriate

logic subset

  • Translate constructs where possible
  • Transform set expressions to predicates
  • Apply beta-reduction to lambda expressions
  • Rewrite tuples into elements
  • Apply extensionality
  • Approximate where necessary
  • Descend formula recursively
  • Approximate inexpressible subformulas according to arity
slide-40
SLIDE 40

Formula Approximation Rules

α : (0,1) × C αp(f1∧f2) ≡ αp(f1) ∧ αp(f2) αp(f1∨f2) ≡ αp(f1) ∨ αp(f2) αp(¬f) ≡ ¬α¬p(f) αp(∀x.f) ≡ ∀x.αp(f) αp(∃x.f) ≡ ∃x.αp(f) α0(f) ≡ false, for f not representable in C α1(f) ≡ true, for f not representable in C αp(f) ≡ e, for f directly representable in C as e

slide-41
SLIDE 41

Formula Approximation Rules

α : (0,1) × C αp(f1∧f2) ≡ αp(f1) ∧ αp(f2) αp(f1∨f2) ≡ αp(f1) ∨ αp(f2) αp(¬f) ≡ ¬α¬p(f) αp(∀x.f) ≡ ∀x.αp(f) αp(∃x.f) ≡ ∃x.αp(f) α0(f) ≡ false, for f not representable in C α1(f) ≡ true, for f not representable in C αp(f) ≡ e, for f directly representable in C as e

slide-42
SLIDE 42

Formula Approximation Rules

α : (0,1) × C αp(f1∧f2) ≡ αp(f1) ∧ αp(f2) αp(f1∨f2) ≡ αp(f1) ∨ αp(f2) αp(¬f) ≡ ¬α¬p(f) αp(∀x.f) ≡ ∀x.αp(f) αp(∃x.f) ≡ ∃x.αp(f) α0(f) ≡ false, for f not representable in C α1(f) ≡ true, for f not representable in C αp(f) ≡ e, for f directly representable in C as e

slide-43
SLIDE 43

Formula Approximation Rules

α : (0,1) × C αp(f1∧f2) ≡ αp(f1) ∧ αp(f2) αp(f1∨f2) ≡ αp(f1) ∨ αp(f2) αp(¬f) ≡ ¬α¬p(f) αp(∀x.f) ≡ ∀x.αp(f) αp(∃x.f) ≡ ∃x.αp(f) α0(f) ≡ false, for f not representable in C α1(f) ≡ true, for f not representable in C αp(f) ≡ e, for f directly representable in C as e

slide-44
SLIDE 44

Why Does Formula Approximation Work?

  • Formula splitting preserves assumptions
  • Proof of a given subformula depends
  • nly on a subset of assumptions
  • Some HOL formulas directly translatable

into formulas in simpler logics

slide-45
SLIDE 45

Dealing With Proof Complexity

  • Proof complexity issues
  • Provers overwhelmed by assumptions
  • Proof of a single subformula requires expertise of

multiple provers

  • Note statements

//: note f: “…” from f0, f1, … fn;

  • Tell provers which assumptions to use
  • Introduce intermediate lemmas into verification

conditions

  • In effect, developer guides proof decomposition
slide-46
SLIDE 46

Note Example (get)

public Object get(Object k0) /*: requires "init ∧ k0 ≠ null” ensures "(result ≠ null → (k0, result) ∈ content) ∧ (result = null → ¬(∃v. (k0, v) ∈ content))" */ { int hc = compute_hash(k0); Node current = table[hc]; //: note ThisProps: “this ∈ old alloc ∧ this ∈ Hashtable ∧this.init”; //: note HCProps: “0 ≤ hc ∧hc < table.length ∧ hc = hash key (table.length)”; /*: note InCurrent: “∀v. ((k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent)” from ContentDef, HCProps, Coherence, ThisProps, InCurrent; */ while /*: inv "∀v. (k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent” */ (current != null) { if (current.key == k0) { return current.value; } current = current.next; } return null; }

slide-47
SLIDE 47

Note Example (get)

public Object get(Object k0) /*: requires "init ∧ k0 ≠ null” ensures "(result ≠ null → (k0, result) ∈ content) ∧ (result = null → ¬(∃v. (k0, v) ∈ content))" */ { int hc = compute_hash(k0); Node current = table[hc];

//: note ThisProps: “this ∈ old alloc ∧ this ∈ Hashtable ∧this.init”; //: note HCProps: “0 ≤ hc ∧hc < table.length ∧ hc = hash key (table.length)”;

/*: note InCurrent: “∀v. ((k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent)” from ContentDef, HCProps, Coherence, ThisProps, InCurrent; */ while /*: inv "∀v. (k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent” */ (current != null) { if (current.key == k0) { return current.value; } current = current.next; } return null; }

Label known facts

slide-48
SLIDE 48

Note Example (get)

public Object get(Object k0) /*: requires "init ∧ k0 ≠ null” ensures "(result ≠ null → (k0, result) ∈ content) ∧ (result = null → ¬(∃v. (k0, v) ∈ content))" */ { int hc = compute_hash(k0); Node current = table[hc]; //: note ThisProps: “this ∈ old alloc ∧ this ∈ Hashtable ∧this.init”; //: note HCProps: “0 ≤ hc ∧hc < table.length ∧ hc = hash key (table.length)”;

/*: note InCurrent: “∀v. ((k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent)” from ContentDef, HCProps, Coherence, ThisProps, InCurrent; */

while /*: inv "∀v. (k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent” */ (current != null) { if (current.key == k0) { return current.value; } current = current.next; } return null; }

State proof goal (intermediate fact or final goal)

slide-49
SLIDE 49

Note Example (get)

public Object get(Object k0) /*: requires "init ∧ k0 ≠ null” ensures "(result ≠ null → (k0, result) ∈ content) ∧ (result = null → ¬(∃v. (k0, v) ∈ content))" */ { int hc = compute_hash(k0); Node current = table[hc]; //: note ThisProps: “this ∈ old alloc ∧ this ∈ Hashtable ∧this.init”; //: note HCProps: “0 ≤ hc ∧hc < table.length ∧ hc = hash key (table.length)”;

/*: note InCurrent: “∀v. ((k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent)” from ContentDef, HCProps, Coherence, ThisProps, InCurrent; */

while /*: inv "∀v. (k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent” */ (current != null) { if (current.key == k0) { return current.value; } current = current.next; } return null; }

Identify a set of known facts

slide-50
SLIDE 50

Note Example (get)

public Object get(Object k0) /*: requires "init ∧ k0 ≠ null” ensures "(result ≠ null → (k0, result) ∈ content) ∧ (result = null → ¬(∃v. (k0, v) ∈ content))" */ { int hc = compute_hash(k0); Node current = table[hc]; //: note ThisProps: “this ∈ old alloc ∧ this ∈ Hashtable ∧this.init”; //: note HCProps: “0 ≤ hc ∧hc < table.length ∧ hc = hash key (table.length)”;

/*: note InCurrent: “∀v. ((k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent)” from ContentDef, HCProps, Coherence, ThisProps, InCurrent; */

while /*: inv "∀v. (k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent” */ (current != null) { if (current.key == k0) { return current.value; } current = current.next; } return null; }

  • Instruct prover to use set to prove goal
  • Proven fact inserted into assumption base
slide-51
SLIDE 51

Note Example (get)

public Object get(Object k0) /*: requires "init ∧ k0 ≠ null” ensures "(result ≠ null → (k0, result) ∈ content) ∧ (result = null → ¬(∃v. (k0, v) ∈ content))" */ { int hc = compute_hash(k0); Node current = table[hc]; //: note ThisProps: “this ∈ old alloc ∧ this ∈ Hashtable ∧this.init”; //: note HCProps: “0 ≤ hc ∧hc < table.length ∧ hc = hash key (table.length)”; /*: note InCurrent: “∀v. ((k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent)” from ContentDef, HCProps, Coherence, ThisProps, InCurrent; */ while /*: inv "∀v. (k0, v) ∈ content) = ((k0, v) ∈ current.bucketContent” */ (current != null) { if (current.key == k0) { return current.value; } current = current.next; } return null; }

Proved trivially by syntactic prover

slide-52
SLIDE 52

Constructs for Directly Controlling Proof

  • havoc x0,…,xn suchThat f

Instantiates ∃x0,…,xn.f

  • pickAny x0,…,xn in (c; note g)

Prove ∀x0,…,xn.g

  • assuming f in (cpure; note g)

Prove f → g

  • Desugar into standard guarded commands
slide-53
SLIDE 53

Jahob System Diagram

SPASS E CVC3 Z3 MONA Coq Isabelle Coq interface Isabelle interface field constraint analysis BAPA SMT-LIB interface lexer, parser, resolver FOL interface desugar splitter, dispatcher, syntactic prover vcgen interactively proven lemmas Implementation , specification, proof hints verification conditions (VCs)

slide-54
SLIDE 54

Experimental Results

slide-55
SLIDE 55

Verified Data Structures

  • Cursor List
  • Singly-Linked List
  • Circular List
  • Array List
  • Priority Queue
  • Binary Search Tree
  • Hash Table
  • Spanning Tree
  • Space Subdivision Tree
  • Association List

Provers

  • Syntactic prover
  • MONA
  • Z3
  • SPASS
  • E
  • CVC3
  • Isabelle (simplifier)
  • Isabelle proof assistant
slide-56
SLIDE 56

500 1000 1500 Association List Space Subdivision Tree Spanning Tree Hash Table Binary Search Tree Priority Queue Array List Circular List Singly-Linked List Cursor List

Syntactic Prover MONA Z3 SPASS E CVC3 Isabelle Script Interactive Proof

Formulas Verified

1 6 4

slide-57
SLIDE 57

500 1000 1500 Association List Space Subdivision Tree Spanning Tree Hash Table Binary Search Tree Priority Queue Array List Circular List Singly-Linked List Cursor List

Syntactic Prover MONA Z3 SPASS E CVC3 Isabelle Script Interactive Proof

Formulas Verified

1 6 4

slide-58
SLIDE 58

50 100 150 200 250 300 Association List Space Subdivision Tree Spanning Tree Hash Table Binary Search Tree Priority Queue Array List Circular List Singly-Linked List Cursor List

Syntactic Prover MONA Z3 SPASS E CVC3 Isabelle Script

Verification Time

Time (s) 6250 6300

slide-59
SLIDE 59

Prover Efficiency

5 10 15 20 25 Syntactic Prover MONA Z3 SPASS E CVC3 Isabelle Script Sequents per Second

slide-60
SLIDE 60

Manual Proofs

  • Space Subdivision Tree
  • 1 proof, 4 lines of proof script
  • 2 case splits, 1 quantifier instantiation
  • Priority Queue
  • 2 proofs, 78 + 4 lines
  • Inductive proof with modulo arithmetic
  • Hashtable
  • 1 proof for add, 7 lines, 3 case splits
  • 4 proofs for remove, 19 + 2 + 2 + 10 lines,

case splits

slide-61
SLIDE 61

Logical Lines of Code

50 100 150 200 250 300

Association List Space Subdivision Tree Spanning Tree Hash Table Binary Search Tree Priority Queue Array List Circular List Singly-Linked List Cursor List

Code Specifications Proof Annotations

slide-62
SLIDE 62

Observations

  • Implementation easier than specification

(but more current expertise with implementation)

  • Easy to prove – callers, observer methods
  • Difficult to prove
  • Destructive update (constructors*, add, remove*)
  • Leaf methods (reasoning about concrete + abstract state)
  • Incentive to decompose larger methods
  • Incentive to reuse existing methods
  • Must understand why implementation is correct to
  • btain proof
slide-63
SLIDE 63

Implications

  • Verified data structure libraries
  • Integrated reasoning in other contexts
  • New program analysis techniques
  • Client analyses based on sets and relations

(no more reasoning about pointers)

  • More precise data structure analyses
  • Semantic commutativity analysis for

parallel programs

slide-64
SLIDE 64

Related Work: Hob

  • Kuncak, Lam, Zee, and Rinard [TSE 2006];

Lam [PhD. Thesis MIT 2007]

  • Sets summarize data structure state
  • Full functional verification only for data

structures with set interface

  • Multiple decision procedures

(early form of integrated reasoning)

slide-65
SLIDE 65

Related Work (cont’d)

Software Verification Tools

  • Spec#: Barnett, DeLine, Fähndrich, Leino, and Schulte [J. Obj. Tech. 2004]
  • ESC/Modula-3: Detlefs, Leino, Helson, Saxe [TR159 COMPAQ SRC 1998]
  • ESC/Java: Flanagan, Leino, Lilibridge, Nelson, Saxe and Stata [PLDI 2002]
  • ESC/Java: Chalin, Hurlin, and Kiniry [VSTTE 2005]
  • Krakatoa: Filliatre [J. Func. Programming 2003]; Marche, Paulin-Mohring, and

Urbain [J. Logic & Alg. Prog. 2003]

  • KIV: Balser, Reif, Schellhorn, Stenzel, and Thums [FASE 2000]
  • KeY: Ahrendt, Baar, Beckert, Bubel, Giese, Hähnle, Menzel, Mostowski, Roth,

Schlager, and Schmitt [Soft. & Sys. Modeling 2005]

  • LOOP: van der Berg and Jacobs [TR CSI-R0019 U. Nijmegen 2000]
slide-66
SLIDE 66

Related Work (cont’d)

Shape Analysis

  • Chong and Rugina [SAS 2003]
  • Role analysis: Kuncak, Lam, and Rinard [POPL 2002]
  • Grammar-based shape analysis: Lee, Yang, and Ki [ESOP 2005]
  • TVLA: Sagiv, Reps, and Wilhelm [TOPLAS 2002]
  • Symbolic shape analysis: Podelski and Wies [SAS 2005]
  • Guo, Vachharajani, and August [PLDI 2007]

Separation Logic

  • Smallfoot: Berdine, Calcagno, and O’Hearn [FMCO 2005]
  • Nguyen, David, Qin, and Chin [VMCAI 2007]
  • Nguyen and Chin [CAV 2008]
  • Yang, Lee, Berdine, Calcagno, Cook, Distefano, and O’Hearn [CAV 2008]
slide-67
SLIDE 67

Unrelated Work

Bounded model checking

  • Bogor: Robby, Rodríguez, Dwyer and Hatcliff [STTT 2006]
  • JACK: Bouali, Gnesi and Larosa [EATCS 1994]
  • Forge: Dennis, Chang and Jackson [ISSTA 2006]
  • J-Sim: Sobeih, Mahesh, Marinov and Hou [IPDPS 2007]

Testing

  • Korat: Boyapati, Khurshid and Marinov [ISSTA 2002]
  • TestEra: Khurshid and Marinov [Autom. Soft. Eng. 2004]
  • Cute: Sen, Marinov and Agha [FSE 2005]
slide-68
SLIDE 68

Conclusions

  • Full functional correctness for linked data

structure implementations

  • Formula splitting
  • Formula approximation
  • Integrated reasoning
  • Constructs for guiding proofs
  • Complete realization of abstract data types
  • Precise, complete, and verified specifications
  • Enables new, more precise and scalable client

program analyses

slide-69
SLIDE 69

Questions?