static contract checking for haskell dana n. xu university of cambridge ph.d. supervisor: simon...

27
Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Upload: antonia-beardall

Post on 29-Mar-2015

232 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Static Contract Checking for Haskell

Dana N. XuUniversity of Cambridge

Ph.D. Supervisor:Simon Peyton JonesMicrosoft Research Cambridge

Page 2: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

From Types to Contractshead [] = BADhead (x:xs) = x

head :: [a] -> a

…(head 1)…

head {xs | not (null xs)} -> {r | True}

…(head [])…

Bug!

Bug!Contract(arbitrary

Haskell boolean expression)

Type null :: [a] -> Boolnull [] = Truenull (x:xs) = False

BAD means “should not

happen: crash”

Page 3: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

What we want• Adapt Findler-Felleisen’s ideas for dynamic (high-order) contract checking.• Do static contract checking for a lazy language.

Contract Haskell function

Glasgow Haskell Compiler (GHC)

Where the bug is Why it is a bug

Page 4: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Three Outcomes(1) Definitely Safe (no crash, but may loop)(2) Definite Bug (definitely crashes)(3) Possible Bug

Page 5: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

5

Sorting

sorted [] = Truesorted (x:[]) = Truesorted (x:y:xs) = x <= y && sorted (y : xs)

insert :: Int -> [Int] -> [Int]insert {i | True} -> {xs | sorted xs} -> {r | sorted r}

merge :: [Int] -> [Int] -> [Int]merge {xs | sorted xs}->{ys | sorted ys}->{r | sorted r}

bubbleHelper :: [Int] -> ([Int], Bool)bubbleHelper {xs | True} -> {r | not (snd r) ==> sorted (fst r)}

insertsort, mergesort, bubblesort {xs | True} -> {r | sorted r}

(==>) True x = x(==>) False x = True

Page 6: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

AVL Tree

balanced :: AVL -> Boolbalanced L = Truebalanced (N t u) = balanced t && balanced u &&

abs (depth t - depth u) <= 1

data AVL = L | N Int AVL AVL insert, delete :: AVL -> Int -> AVLinsert {x | balanced x} -> {y | True} -> {r | notLeaf r && balanced r &&

      0 <= depth r - depth x &&      depth r - depth x <= 1 }

delete {x | balanced x} -> {y | True} -> {r | balanced r && 0 <= depth x - depth r &&

        depth x - depth r <= 1}

(&&) True x = x(&&) False x = False

Page 7: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

The Contract Idea for Higher-Order Function[Findler/Felleisen]

f1 :: (Int -> Int) -> Intf1 ({x | x > 0} -> {y | y >= 0}) -> {r | r >= 0}f1 g = (g 0) - 1

f2 :: {r | True}f2 = f1 (\x -> x – 5)

Blame f1: f1 calls g with

wrong argument

f1 does not satisfy its post-condition

Blame f2: f2 calls f1 with

wrong argument

f3 :: {r | True}f3 = f1 (\x -> x – 1)

f3 is Ok.Can’t tell at

run-time

Page 8: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

What is a Contract?

Contract t ::= {x | p} Predicate Contract

| x:t1 -> t2 Dependent Function Contract

| (t1, t2) Tuple Contract

| Any Polymorphic Any Contract

3 { x | x > 0 } (3, []) Any3 { x | True } (3, []) (Ok, {ys | null ys})

Ok = {x | True} arbitrary Haskell boolean

expression

inc x:{x | x>0} -> {y | y == x + 1}

Precondition

Postcondition

Postcondition can mention

argument

arbitrary constructor

Page 9: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

What we want?

Check f <contract_of_f>• If main Ok , then the whole program

cannot crash.• If not, show which function to blame and

why.

Beauty of Contract Checking

Page 10: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Define e t

Construct e t

(e “ensures” t)

Main Theorem e t iff e t is crash-free

(related to Blume&McAllester:JFP’06)

some e’

Symbolically simplify (e t)

See if BAD is syntactically in e’.If yes, DONE;

else give BLAME

[POPL’10]

ESC/Haskell [Haskell’06]

Page 11: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

e {x | p} = case p[e/x] ofTrue -> eFalse -> BAD

e x:t1 -> t2 = v. (e (v t1)) t2[(vt1)/x]

e (t1, t2) = case e of (e1, e2) -> (e1 t1, e2 t2)

e Any = UNR

Wrappers and ( pronounced ensures pronounced requires)

related to [Findler-Felleisen:ICFP02]

Page 12: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Wrappers and ( pronounced ensures pronounced requires)

related to [Findler-Felleisen:ICFP02]

e {x | p} = case p[e/x] ofTrue -> eFalse -> UNR

e x:t1 -> t2 = v. (e (v t1)) t2[v t1/x]

e (t1, t2) = case e of (e1, e2) -> (e1 t1, e2 t2)

e Any = BAD

Page 13: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Some Interesting Details

PracticeTheory

Adding tags, e.g. BAD “f”• Achieves precise blaming

More tags to trace functions to blame• Achieves the same goal of [Meunier:POPL06]

Using a theorem proverCounter-example guided unrolling

Contracts that loopContracts that crashLovely Lemmas

Page 14: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Lovely Lemmas

Page 15: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Summary• Static contract checking is a fertile and under-researched

area• Distinctive features of our approach– Full Haskell in contracts; absolutely crucial– Declarative specification of “satisfies”– Nice theory (with some very tricky corners)– Static proofs– Modular Checking– Compiler as theorem prover

Page 16: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

After Ph.D.

• Postdoc project in 2009: probabilistic contract for component base design [ATVA’2010]

• Current project at Xavier Leroy’s team (INRIA) - a verifying compiler: 1. Apply the idea to OCaml compiler by allowing both static and dynamic contract checking 2. Connect with Coq to verify more programs statically. 3. Use Coq to prove the correctness of the framework. 4. Apply new ideas back to Haskell (e.g. GHC).

Page 17: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Static and Dynamic

Program with Specifications

Run time error attributes blame to

the right place

Compile time error attributes blame to

the right place

Dynamicchecking

Staticchecking

No blamingmeans

Program cannot crashs

Or, more plausibly: If you guarantee that f t,then the program cannot crash

Page 18: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge
Page 19: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

What exactly does it mean to say that

e “satisfies” contract t?

e t

Page 20: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

When does e satisfy a contract?

• Brief, declarative…

inc x:{x | x > 0} -> {y | y == x + 1}

Precondition

Postcondition

Postcondition can mention

argument

Page 21: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

When does e satisfy a contract?

• The delicate one is the predicate contract.• Our decision: e {x | p} iff e is crash-free• Question: What expression is crash-free ? e is crash-free iff no blameless context can make e crash

e is crash-freeiff

C. BAD s C. C[e] * BAD

Page 22: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Crash-free Examples

Lemma: e is syntactically safe => e is crash-free.

Crash-free?

\x -> x YES

(1, True) YES

(1, BAD) NO

\x -> if x > 0 then x else (BAD, x) NO

\x -> if x*x >= 0 then x + 1 else BAD Hmm.. YES

Page 23: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

When does e satisfy a contract?

See the paper for …

• Why e must be crash-free to satisfy predicate contract?• Why divergent expression satisfies all contract?• What if contract diverges (i.e. p diverges)?• What if contract crashes (i.e. p crashes)?

Page 24: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

How can we mechanically check that

e “satisfies” contract t?

e t ???

Page 25: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Example

head { xs | not (null xs) } -> Ok

head {xs | not (null xs)} -> Ok

= \v. head (v {xs | not (null xs)}) Ok

e Ok = e

= \v. head (v {xs | not (null xs)})

= \v. head (case not (null v) ofTrue -> vFalse -> UNR)

head:: [a] -> ahead [] = BADhead (x:xs) = x

Page 26: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

\v. head (case not (null v) ofTrue -> vFalse -> UNR)

null :: [a] -> Boolnull [] = Truenull (x:xs) = False

not :: Bool -> Boolnot True = Falsenot False = True

= \v. head (case v of [] -> UNR (p:ps) -> p)

Now inline ‘not’ and ‘null’

Now inline ‘head’

= \v. case v of [] -> UNR (p:ps) -> p

head:: [a] -> ahead [] = BADhead (x:xs) = x

So head [] fails with UNR, not

BAD, blaming the caller

Page 27: Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge

Static and Dynamic

Program with Specifications

Run time error attributes blame to

the right place

Compile time error attributes blame to

the right place

Dynamicchecking

Staticchecking

[Findler, Felleisen,

Blume, Hinze,

Loh, Runciman, Chitil]

[Flanaghan, Mitchell, Pottier]