Higher-Order Verification With Liquid Types Ranjit Jhala, UC San Diego (with Pat Rondon, Ming...

Post on 22-Dec-2015

214 views 0 download

Tags:

transcript

Higher-Order VerificationWith Liquid Types

Ranjit Jhala, UC San Diego(with Pat Rondon, Ming Kawaguchi)

Part IFirst-Order Verification

Part IIHigher-Order Verification

char* rev_copy(char* a, int n){

i = 0; j = n – 1; b = malloc(n); while(0<=j){ b[i] = a[j]; i++; j--; } return b;}

First-Order Verification

char* rev_copy(char* a, int n){

i = 0; j = n – 1; b = malloc(n); while(0<=j){ b[i] = a[j]; i++; j--; } return b;}

Example: Memory Safety

Access Within Array Bounds

char* rev_copy(char* a, int n){

i = 0; j = n – 1; b = malloc(n); while(j>=0){ b[i] = a[j]; i++; j--; } return b;}

assert (0<=i && i<n);

0:

1: 2:

How to prove assert never fails ?

assert (i<n);

0: i = 0; j = n–1; 1: while (0<=j){ 2: assert(i<n); i = i+1; j = j–1; }Access Within Array Bounds

How to prove asserts?Invariants [Floyd-Hoare]

Invariants

Predicate that is always true@ Program Location

0: i = 0; j = n–1; 1: while (0<=j){

2: assert(i<n);

i = i+1; j = j–1; }

true

i+j=n-1

i+j=n-1 Æ 0·j

Invariant Proves Assert

How to Prove Asserts?How to Find Invariants?

0: i = 0; j = n–1; 1: while (0<=j){

2: assert(i<n);

i = i+1; j = j–1; }

?

What are Invariants ?

??

What are Invariants ?

Let Xi = Invariant @ location i

0: i = 0; j = n–1; 1: while (0<=j){

2: assert(i<n);

i = i+1; j = j–1; }

?

What are Invariants ?

??

X0

X1

X2Properties of X0,X1,X2?

0: i = 0; j = n–1; 1: while (0<=j){

2: assert(i<n);

i = i+1; j = j–1; }

What are Invariants ?

X0

Initial Values ArbitraryX0= true

0: i = 0; j = n–1; 1: while (0<=j){

2: assert(i<n);

i = i+1; j = j–1; }

What are Invariants ?

i=0 Æ j=n-1 )

X1

true

X1

0: i = 0; j = n–1; 1: while (0<=j){

2: assert(i<n);

i = i+1; j = j–1; }

What are Invariants ?

0·j Æ X1 ) X2

X1X2

0: i = 0; j = n–1; 1: while (0<=j){

2: assert(i<n);

i = i+1; j = j–1; }

What are Invariants ?

X2 ) i<n

X2

0: i = 0; j = n–1; 1: while (0<=j){

2: assert(i<n);

i = i+1; j = j–1; }

What are Invariants ?

i=io+1 Æ j=jo-1 Æ [io/i][jo/j]X2 )

X1

X1X2

What are Invariants ?

… Æ [io/i][jo/j]X2 ) X1

Predicates X1, X2 s.t.

i=0 Æ j=n-1 ) X1

0·j Æ X1 ) X2

X2 ) i<n

What are Invariants ?

… Æ [io/i][jo/j]X2 ) X1

Predicates X1, X2 s.t.i=0 Æ j=n-1 ) X1

0·j Æ X1 ) X2

X2 ) i<n

How to Infer Invariants? How to Solve for X1, X2? Idea: Lazy Abstraction

Idea: Lazy AbstractionTree of executions over atomic predicates

i+j=n-10·j

Nodes: X1, X2

Edges: X1 ) X2

… [io/i][jo/j]X2 ) X1

0·j Æ X1 ) X2

X2 ) i<n

Lazy Predicate Abstraction

X0 trueTree Root Root X (i.e. non-RHS)

i=0 Æ j=n-1Æ X0 )

X1

Atoms: i+j=n-1, 0·j

Lazy Predicate Abstraction

X0 true

X1

Tree Edge“Unrolled” Implication

… [io/i][jo/j]X2 ) X1

0·j Æ X1 ) X2

X2 ) i<n

i=0 Æ j=n-1Æ X0 )

X1

Atoms: i+j=n-1, 0·j

Lazy Predicate Abstraction

X0 true

X1

Theorem Prover

i=0 Æ j=n-1Æ X0 )

X1

Atoms: i+j=n-1, 0·j

?i=0 Æ j=n-1Ætrue

)i+j=n-1

Valid

Lazy Predicate Abstraction

X0 true

X1i+j=n-1

Theorem Prover

i=0 Æ j=n-1Æ X0 )

X1

Atoms: i+j=n-1, 0·j

i=0 Æ j=n-1Ætrue

)0·j

Invalid

… [io/i][jo/j]X2 ) X1

0·j Æ X1 ) X2

X2 ) i<n

?

Lazy Predicate Abstraction

X0 true

X1i+j=n-1

… [io/i][jo/j]X2 ) X1

0·j Æ X1 ) X2

X2 ) i<n

i=0 Æ j=n-1Æ X0 )

X1

Atoms: i+j=n-1, 0·jX2 i+j=n-1 Æ 0·j?

Lazy Predicate Abstraction

X0 true

X1i+j=n-1

… [io/i][jo/j]X2 ) X1

0·j Æ X1 ) X2

X2 ) i<n

i=0 Æ j=n-1Æ X0 )

X1

Atoms: i+j=n-1, 0·jX2 i+j=n-1 Æ 0·j

i<n

Theorem Prover0·j Æ i+j=n-1 )i<n

Valid

Lazy Predicate Abstraction

X0 true

X1i+j=n-1

X2

X1 i<n?

i+j=n-1 Æ 0·j

… [io/i][jo/j]X2 ) X1

0·j Æ X1 ) X2

X2 ) i<n

i=0 Æ j=n-1Æ X0 )

X1

Atoms: i+j=n-1, 0·j

i+j=n-1

Lazy Predicate Abstraction

X0 true

X1i+j=n-1

X2

X1 i<n

i+j=n-1 Æ 0·j

… [io/i][jo/j]X2 ) X1

0·j Æ X1 ) X2

X2 ) i<n

i=0 Æ j=n-1Æ X0 )

X1

Atoms: i+j=n-1, 0·j

i+j=n-1

FixpointStop UnrollingInferred InvariantsProved Asserts…Constraints Solved

…not so fast!

C Program+

Asserts

Lazy Abstraction[popl 02]

Atoms

Safety Invariants

How to get good atoms?e.g. i+j=n-1

If we have bad atoms...e.g. i=0, j=n-1, 0·j

X2 i<n

X0true

X1i=0 Æ j=n-1

X2

X1

i<ni=0 Æ j=n-1 Æ 0·j

true

true

…Yields Counterexample “Path”Abstraction With Bad Atoms...

Assert Holds

Not a fixpoint

Assert Fails

i:=0j:=n–1

0<=j?

i:=i+1j:=j-1

0<=j?

Bad atoms yield counterexample paths

C Program+

Asserts

Lazy Abstraction[popl 02]

Atoms Path

Safety Invariants

CounterexampleAnalysis

UnsafePaths

“Counterexample Guided Abstraction Refinement”[Kurshan 94, Clarke et al. 00, Ball & Rajamani 00]

Path Atoms

X2

i<n

X0

X1

X2

X1

i:=0j:=n–1

0<=j?

i:=i+1j:=j-1

0<=j?

Path AtomsFormula Proof

Good AtomsRelationships from pastProve safety of future

i:=0j:=n–1

0<=j?

i:=i+1j:=j-1

0<=j?

How to computegood atoms from paths?

Path AtomsFormula Proof

Æ i0 = 0

Æ j0 = n–1Æ 0 · j0

Æ i1 = i0 + 1

Æ j1 = j0 - 1Æ n · i1 ¸

Æ 0 · j1

Negate Assert

RenameVariables

(SSA)

Formula Unsatisfiable iff Assert Holds

X2

i<n

X0

X1

X2

X1

i:=0j:=n–1

0<=j?

i:=i+1j:=j-1

0<=j?

Path AtomsFormula Proof

Æ i0=0

Æ j0=n–1

Æ 0·j0

Æ i1=i0+1

Æ j1=j0-1

Æ n·i1

Æ 0·j1

Æ i0 = 0

Æ j0 = n–1Æ 0 · j0

Æ i1 = i0 + 1

Æ j1 = j0 - 1Æ i1 ¸ n

Æ 0 · j1

0·j1

j1=j0-1

j0=n-1

n·i1

i1=i0+1

i0=0

0·j0-1

0·n-2

0·-1

n·i0+1

n·1

False

X2

i<n

X0

X1

X2

X1

i:=0j:=n–1

0<=j?

i:=i+1j:=j-1

0<=j?

+

+

+

+

+

Path AtomsFormula Proof

0·j1

j1=j0-1

j0=n-1

n·i1

i1=i0+1

i0=0

0·j0-1

0·n-2

n·i0+1

n·1

False

+

+

+

+

+

Good AtomsRelationships from pastProve safety of future+ i+j=n-1

Atom = Craig InterpolantOf Past, Future FormulasExtracted from proof

Of path unsatifiabilityInferred Good Atomi+j=n-1X2

i<n

X0

X1

X2

X1

0<=j?

i:=0j:=n–1

0<=j?

i:=i+1j:=j-1

0<=j?

RecapHow to verify safety ?Compute invariants X1, X2 ...

How to solve for X1, X2 ... ?Tree of executions over atoms

How to find good atoms ?Interpolants of path formulas

RecapSafety

Invariants

Implications

AI, PA, CEGAR,…

X0 , X1

X0 ) X1

Part IFirst-Order (by Logic)

Part IIHigher-Order Verification

Key Problem: Invariants for…

Collections?Closures?

Polymorphism?Recursive Data?

Idea: Logically Qualified TypesFactor Invariant to Logic x Type

Idea: Liquid Types

LogicDescribes Individual Data

TypeQuantifies over Structure

factored into

8i: 0 ·i<table.length )-1· table[i]

table :: {v:int|-1 · v} array

Type Logic

factored into

8x: next*(root,x) )-1 · x.data

root :: {v:int|-1 · v} list

Type Logic

Pre-Condition x:’a array

-> {v:int|0·v< len x}-> ’a

Functions: Array.get

Post-Condition

’a array

-> int-> ’a

int-> int-> (int-> unit) -> unit

Higher-Order: ffor

lo:int-> hi:{int|lo·v}-> ({v:int|lo·v<hi}->

unit) -> unit

LogicDescribes Individual Data

TypeQuantifies over Structure

Theorem ProverReasoning about Individual Data

Type SystemQuantified Reasoning about Structure

Demo“Map-Reduce”

“Map-Reduce”map :: (e -> (k, v) list) -> e list -> (k, v) list

group :: (k, v) list -> (k, v list)

tablereduce :: (v -> v -> v) -> (k, v list)

table -> (k, v) table

K-Means Clustering

0. Choose K Centers Arbitrarily

1. (Map) Points to Nearest Center

2. (Group) Points by Center

3. (Reduce) Centroids into New Centers

Repeat 1,2,3 Until Convergence

DemoK-Means via Map-Reduce

Base TypesCollections

ClosuresPolymorphismRecursive Data

let rec ffor l u f =

if l < u then ( f l; ffor (l+1) u f )

Type of f

int ! unitTemplate of f

{v:int|X1}!unit

Liquid Type of f

{v:int|l·v Æ v<u} ! unit

l Flows Into Input of f {v:int|v=l} <: {v:int|X1}

l<u |-

l<u Æ v=l ) X1

Solution X1 = l·v Æ v<u

Reduces to

Base TypesCollections

ClosuresPolymorphismRecursive Data

let nearest dist ctra x = let da = Array.map (dist x) ctra in

[min_index da, (x, 1)]Type of Output

int * ’b * int listTemplate of Output

{v:int | X1} * ’b * {v:int | X2} list

(’a !’b)!x:’a array!{v:’b array|len x = len v}

Liquid Type of

x:’a array!{v:int| 0·v Æ v < len x}

min_index da {v:int| 0·v Æ v < len da}da {v:’b array| len v = len ctra}

len da = len ctra Æ 0·v<len da ) X1

len da = len ctra Æ v=1 ) X2

da:{len v = len ctra}|-{ 0·v<len da} * ’b * {v=1} list <: {X1} * ’b * {X2}

list

Reduces To

Solution X1 = 0·v < len ctra X2 = 0 < v

Liquid Type of Output{v:int|0·v<len ctra}*’b*{v:int|0<v}

list

Base TypesCollections

ClosuresPolymorphismRecursive Data

let min_index a = let min = ref 0 in ffor 0 (Array.length a) (fun i -> if a.(i) < a.(!min) then min :=

i ); !min

Liquid Type of ffor 0 (len a)

({v:int|0· v < len a} ! unit)! unit

Template of (fun i ->...)

{v:int|Xi} ! unit

{Xi}!unit <: {0·v<len a}!unit{0·v<len a} unit{Xi} unit

{0·v<len a} <: {Xi}

Reduces To

unit <: unit0· v < len a ) Xi

Solution Xi = 0·v< len a

Liquid Type of (fun i ->...) {v:int|0·v<len a} ! unit

Liquid Type of fforl:int!u:int!({v:int|l·v<u}!unit)!unit

Liquid Type of ffor 0u:int!({v:int|0·v< u} ! unit)! unit

Base TypesCollections

ClosuresPolymorphismRecursive Data

mapreduce (nearest dist ctra) (centroid plus) xs

|> List.iter (fun (i,(x,sz)) -> ctra.(i)<- div x

sz) Type of mapreduce(’a !’b * ’c list) !...! ’b * ’c list

Template of mapreduce(’a ! {X1} * ’a * {X2} list)!...! {X1} * ’a * {X2} list

Type Instantiation ’a with ’a ’b with int

’c with ’a * int

Template Instantiation ’a with ’a

’b with {v:int|X1}

’c with ’a * {v:int|X2}

Liquid Type of (nearest dist ya)’a ! {0 · v < len ctra} * ’a * {0<v} list’a ! {0 · v < len ctra} * ’a * {0<v} list

<:’a ! {X1} * ’a * {X2} list

Solution X1 = 0 · v < len ctra X2 = 0 < v

Reduces To0 · v < len ctra ) X1

0 < v ) X2

Liquid Type of mapreduce Output {0 · v < len ctra} * ’a * {0 < v} list

Polymorphism = “Meta” Invariants

Polymorphism = “Meta Invariants”

foldl :: (a->b-> a)-> a-> b list-> a

Polymorphism = “Meta Invariants”

foldl :: (a->b-> a)-> a-> b list-> a

Initial Value Satisfies a

Polymorphism = “Meta Invariants”

foldl :: (a->b-> a)-> a-> b list-> a

Each “Iteration” Preserves a

Polymorphism = “Meta Invariants”

foldl :: (a->b-> a)-> a-> b list-> a

Hence, Output Satisfies a

Polymorphism = “Meta Invariants”

foldl :: (a->b-> a)-> a-> b list-> a

At callsite instantiate a for invariantAnalysis oblivious to iterated structure

Base TypesCollections

ClosuresPolymorphismRecursive Data

Recursive Data Structures

Data (Structure) Invariants

Piggyback Predicates On Types

[] ::

{x:int|0<x} listint list0<x Describes all elementsx:int

Representation

[] ::

0<x

x:int

Type Unfolding

[] ::

0<h

h:int

[] ::

0<x

x:int

Head TailEmptyPositive Property holds recursivelyList of positive integers

[] ::

0<x Describes all elementsx:int

x<v v Describes tail elements

Representation

[] ::

x<v

x:int

Type Unfolding

[] ::

h:int

[] ::

x<v

x:int

Head TailEmptyElements larger than head Property holds recursively

List of sorted integers

h<v

Push Edge Predicate Into NodeRename Variable

h<x

Piggyback Predicates On Types

Data (Structure) Invariants

[] ::

x:intUnfold

::

h:int

[] ::

x:int

l:sorted list h:int t:sorted

list & {h<x}

list

Instantiate

tl

match l with

h::t

x<Vx<V

h<x

Quantifier Instantiation

Piggyback Predicates On Types

Data (Structure) Invariants

[] ::

x:intFold

h:int

[] ::

x:int

::

l:sorted list h:int t:sorted

list & {h<x}

list

Generalize

tl

let l = h::t in

x<Vx<V

h<x

Quantifier Generalization

Demoisort

Recursive Data Structures

Piggyback Predicates On Types

(Data) Structure Invariants

measure len =| [] -> 0 | x::xs -> 1 + len xs

Representation: List Length

Representation: List Length

8l,x,xs. len([]) = 0 len(x::xs) = 1+len(xs)

Piggyback Predicates On Types

(Data) Structure Invariants

l:’a list

l:’a listh:’at:’a listlen(l)=1+len(t)

Instantiate

match l with

h::t

Quantifier Instantiation

8l,x,xs. len([]) = 0 len(x::xs) = 1+len(xs)

Piggyback Predicates On Types

(Data) Structure Invariants

h:’at:’a list

Quantifier Generalization

8l,x,xs. len([]) = 0 len(x::xs) = 1+len(xs)

Generalize

let l = h::t in h:’at:’a listl:’a listlen(l)=1+len(t)

Demomsortb

Recursive Data StructuresPiggyback Measures

Leaf

l r

l = Left subtreer = Right subtree

treeHeight

H l = Left subtree’s heightH r = Right subtree’s height

measure H =

| Leaf = 0| Node(x,l,r) = 1 + max (H l) (H r)

Height Balanced Tree

|Hl–Hr|<2

Node

Height difference bounded at each node

Demoeval

Automatic Liquid Type InferenceBy Predicate Abstraction

0<x

[] ::

x:int

x<v

Automatic Liquid Type Inference

Predicates Determine InvariantLet X1, X2, ... = Unknown Predicates

Complex Subtyping Between data types

X1

X2

Reduces To Simple Implications Between X1, X2, ...

Solved by Predicate AbstractionOver atoms 0<x, x<v, ...

Part IFirst-Order (by Logic)

Part IIHigher-Order (by Types)

Take Home LessonsWhy are HO Programs difficult?Complex “invariants”

How to represent invariants? Factor into liquid type

How to compute liquid type?AbsInt/Predicate Abstraction/…

“Back-End” LogicConstraint Solving

Rich Decidable Logics Qualifier Discovery…

Much Work Remains…

“Front-End” TypesDestructive Update

ConcurrencyObjects & Classes

Dynamic Languages…

Much Work Remains…

User InterfaceThe smarter your analysis,

the harder to tell why it fails!

Much Work Remains…

http://goto.ucsd.edu/liquidsource, papers, demo, etc.

Finite Maps (ML)5: ‘cat’

3: ‘cow’ 8: ‘tic’

1: ‘doc’ 4: ‘hog’ 7: ‘ant’ 9: ‘emu’From Ocaml Standard Library

Implemented as AVL TreesRotate/Rebalance on Insert/Delete

Verified InvariantsBinary Search Ordered

Height BalancedKeys Implement Set

Binary Decision Diagrams (ML)X1

X2 X2

X3

X4 X4

1

Graph-Based Boolean Formulas [Bryant 86]

X1ÛX2 Ù X3ÛX4 Efficient Formula Manipulation

Memoizing Results on SubformulasVerified Invariant

Variables Ordered Along Each Path

Vec: Extensible Arrays (317 LOC)

“Python-style” extensible arrays for Ocaml

find, insert, delete, join etc.

Efficiency via balanced trees

Balanced

Height difference between siblings ≤ 2

Dsolve found balance violation

fatal off-by-one error

Recursive Rebalance

Debugging via Inference

Using Dsolve we found

Where imbalance occurred

(specific path conditions)

How imbalance occurred

(left tree off by up to 4)

Leading to test and fix