Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

download Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

of 59

Transcript of Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    1/59

    Detecting Pattern-Match Failures

    in Haskell

    Neil Mitchell andColin Runciman

    York University

    www.cs.york.ac.uk/~ndm/catch

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    2/59

    Does this code crash?

    risers [] = []

    risers [x] = [[x]]

    risers (x:y:etc) =ifx y then (x:s) : ss else [x] : (s:ss)

    where (s:ss) = risers (y:etc)

    > risers [1,2,3,1,2] = [[1,2,3],[1,2]]

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    3/59

    Does this code crash?

    risers [] = []

    risers [x] = [[x]]

    risers (x:y:etc) =ifx y then (x:s) : ss else [x] : (s:ss)

    where (s:ss) = risers (y:etc)

    > risers [1,2,3,1,2] = [[1,2,3],[1,2]]

    Potential crash

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    4/59

    Does this code crash?

    risers [] = []

    risers [x] = [[x]]

    risers (x:y:etc) =ifx y then (x:s) : ss else [x] : (s:ss)

    where (s:ss) = risers (y:etc)

    > risers [1,2,3,1,2] = [[1,2,3],[1,2]]Potential crash

    Property:risers (_:_) = (_:_)

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    5/59

    Overview

    zThe problem of pattern-matching

    z A framework to solve patterns

    z Constraint languages for the frameworkzThe Catch tool

    z

    A case study: HsColourz Conclusions

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    6/59

    The problem of Pattern-Matching

    head (x:xs) = x

    head x_xs =case x_xs ofx:xs x

    [] error head []

    z Problem: can we detect calls to error

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    7/59

    Haskell programs go wrong

    z Well-typed programs never go wrong

    z But...

    Incorrect result/actions requires annotations Non-termination cannot always be fixed

    Call error not much research done

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    8/59

    My Goal

    z Write a tool for Haskell 98 GHC/Haskell is merely a front-end issue

    z Check statically that error is not called Conservative, corresponds to a proof

    z Entirely automatic No annotations

    = Catch

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    9/59

    Preconditions

    z Each function has a precondition

    z If the precondition to a function holds, and

    none of its arguments crash, it will not crash

    pre(head x) = x {(:) _ _}

    pre(assertx y) = x {True}

    pre(null x) = True pre(error x) = False

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    10/59

    Properties

    z A property states that if a function is calledwith arguments satisfying a constraint, the

    result will satisfy a constraint

    x {(:) _ _} (null x) {True}

    x {(:) [] _} (head x) {[]}

    x {[]} (head x) {True}

    Calculation direction

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    11/59

    Checking a Program (Overview)

    z Start by calculating the precondition of main If the precondition is True, then program is safe

    z Calculate other preconditions and propertiesas necessary

    z Preconditions and properties are definedrecursively, so take the fixed point

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    12/59

    Checking risers

    risers r =case r of

    [] []

    x:xs

    case xs of[] (x:[]) : []

    y:etc case risers (y:etc) of

    [] error pattern matchs:ss case x y of

    True (x:s) : ss

    False [x] : (s:ss)

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    13/59

    Checking risers

    risers r =case r of

    [] []

    x:xs

    case xs of[] (x:[]) : []

    y:etc case risers (y:etc) of

    [] error pattern matchs:ss case x y of

    True (x:s) : ss

    False [x] : (s:ss)

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    14/59

    Checking risers

    risers r =case r of

    [] []

    x:xs

    case xs of[] (x:[]) : []

    y:etc case risers (y:etc) of

    [] error pattern matchs:ss case x y of

    True (x:s) : ss

    False [x] : (s:ss)

    r {[]} xs {[]}

    risers (y:etc)

    {(:) _ _}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    15/59

    Checking risers

    risers r =case r of

    [] []

    x:xs

    case xs of[] (x:[]) : []

    y:etc case risers (y:etc) of

    [] error pattern matchs:ss case x y of

    True (x:s) : ss

    False [x] : (s:ss) ... [x] : (s:ss) {(:) _ _}

    ... (x:s) : ss {(:) _ _}

    ... {(:) _ _}

    ... (x:[]) : []

    {(:) _ _}

    r {(:) _ _}[] {(:) _ _}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    16/59

    Checking risers

    risers r =case r of

    [] []

    x:xs case

    xsof

    [] (x:[]) : []

    y:etc case risers (y:etc) of

    [] error pattern matchs:ss case x y of

    True (x:s) : ss

    False [x] : (s:ss) ... [x] : (s:ss) {(:) _ _}

    ... (x:s) : ss {(:) _ _}

    ... {(:) _ _}

    ... (x:[]) : []

    {(:) _ _}

    r {(:) _ _}[] {(:) _ _}

    Property:

    r {(:) _ _}risers r {(:) _ _}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    17/59

    Checking risers

    risers r =case r of

    [] []

    x:xs case

    xsof

    [] (x:[]) : []

    y:etc case risers (y:etc) of

    [] error pattern matchs:ss case x y of

    True (x:s) : ss

    False [x] : (s:ss)

    r {[]} xs {[]}

    risers (y:etc)

    {(:) _ _}

    Property:

    r {(:) _ _}risers r {(:) _ _}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    18/59

    r {[]} xs {[]}

    y:etc

    {(:) _ _}

    Checking risers

    risers r =case r of

    [] []

    x:xs case

    xsof

    [] (x:[]) : []

    y:etc case risers (y:etc) of

    [] error pattern matchs:ss case x y of

    True (x:s) : ss

    False [x] : (s:ss)

    Property:

    r {(:) _ _}risers r {(:) _ _}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    19/59

    Calculating Preconditions

    z Variables: pre(x) = True Always True

    z Constructors: pre(a:b) = pre(a) pre(b) Conjunction of the children

    z Function calls: pre(f x) = x pre(f) pre(x) Conjunction of the children

    Plus applying the preconditions of f

    Note: precondition is recursive

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    20/59

    Calculating Preconditions (case)

    pre(case on of

    [] a

    x:xs b)= pre(on) (on {[]} pre(a))

    (on

    {(:) _ _}

    pre(b))

    z An alternative is safe, or is never reached

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    21/59

    Extending Constraints ()risers r =case r of

    [] []

    x:xs case xs of

    [] (x:[]) : []

    y:etc ...

    xs {(:) _ _} ...r {(:) _ _}

    r

    {(:) _ ((:) _ _)}

    {(:) _ _}{(:) _ ((:) _ _)}

    {True}{(:) True _}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    22/59

    Splitting Constraints ()risers r =case r of

    [] []

    x:xs case xs of

    [] (x:[]) : []

    y:etc ...

    (x:[]):[] {(:) _ _} ...True

    ((:) 1 2) {(:) _ _}True

    ((:) 1 2) {[]}False

    ((:) 1 2) {(:) True []}

    1 {True} 2 {[]}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    23/59

    Summary so far

    z Rules for Preconditions

    z How to manipulate constraints

    Extend () for locally bound variables Split () for constructor applications

    Invoke properties for function application

    z Can change a constraint on expressions, toone on function arguments

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    24/59

    Algorithm for Preconditions

    set all preconditions to True

    set error precondition to False

    while any preconditions changerecompute every precondition

    end while

    z Algorithm for properties is very similar

    Fixed Point!

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    25/59

    Fixed Point

    zTo ensure a fixed point exists demand only afinite number of possible constraints

    z At each stage, () with the previousprecondition

    z Ensures termination of the algorithm But termination useable speed!

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    26/59

    The Basic Constraints

    zThese are the basic ones I have introduced

    z Not finite but can bound the depth A little arbitrary

    Cant represent infinite data structures

    z But a nice simple introduction!

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    27/59

    A Constraint System

    z Finite number of constraints

    z Extend operator ()

    z Split operator ()z notin creation, i.e. x {(:) _ _)}

    z

    Optional simplification rules in a predicate

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    28/59

    Regular Expression Constraints

    z Based on regular expressions

    z x r c

    r is a regular expression of paths, i.e. c is a set of constructors

    True if all r paths lead to a constructor in c

    z Split operator () is regular expressiondifferentiation/quotient

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    29/59

    RE-Constraint Examples

    z head xs xs (1 {:})

    z

    map head xs xs (* {:})

    z map head (reverse xs) xs (* {:})

    xs (* {:})

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    30/59

    RE-Constraint Problems

    zThey are finite (with certain restrictions)

    z But there are many of them!

    z Some simplification rules Quite a lot (19 so far)

    Not complete

    z In practice, too slow for moderate examples

    This fact took 2years to figure

    out!

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    31/59

    Multipattern Constraints

    z Idea: model the recursive and non-recursivecomponents separately

    z Given a list Say something about the first element

    Say something about all other elements Cannot distinguish between element 3 and 4

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    32/59

    MP-Constraint Examples

    z head xs xs ({(:) _} {[], (:) _})

    z Use the types to determine recursive bits

    xs must be (:)

    xs. must be _

    All recursive tails

    are unrestricted

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    33/59

    More MP-Constraint Examples

    z map head xs {[], (:) ({(:) _} {[], (:) _})}

    {[], (:) ({(:) _} {[], (:) _})}

    z An infinite list

    {(:) _} {(:) _}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    34/59

    MP-Constraint semantics

    MP = {set Val}

    Val = _ | {set Pat} {set Pat}

    Pat= Constructor [(non-recursive field, MP)]

    Element must satisfy

    at least one pattern

    Each recursive part must

    satisfy at least one pattern

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    35/59

    MP-Constraint Split

    z ((:) 1 2) {(:) _} {(:) {True}} An infinite list whose elements (after the first) are

    all true

    z 1 _

    z 2 {(:) {True}} {(:) {True}}

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    36/59

    MP-Constraint Simplification

    zThere are 8 rules for simplification Still not complete...

    z

    But! x a x b = x c union of two sets

    x a x b = x c cross product of two sets

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    37/59

    MP-Constraint Currying

    z We can merge all MPs on one variable

    z We can curry all functions so each has only

    one variablez MP-constraint Predicate MP-constraint

    (||) a b (||) (a, b)

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    38/59

    MP vs RE constraints

    z Both have different expressive power Neither is a subset/superset

    z RE-constraints grow too quickly

    z MP-constraints stay much smaller

    zTherefore Catch uses MP-constraints

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    39/59

    Numbers

    data Int = Neg | Zero | One | Pos

    z Checks Is positive? Is natural? Is zero?

    z Operations (+1), (-1)

    z Works very well in practice

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    40/59

    Summary so far

    z Rules for Preconditions and Properties

    z Can manipulate constraints in terms of three

    operationsz MP and RE Constraints introduced

    z Have picked MP-Constraints

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    41/59

    Making a Tool (Catch)

    Haskell

    Core

    First-order Core

    Curried

    Analyse

    Yhc

    In draft paper,see website

    This talk

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    42/59

    Testing Catch

    zThe nofib benchmark suite, but

    main =do [arg] getArgsprint $ primes !! (read arg)

    z Benchmarks have no real users

    z Programs without real users crash

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    43/59

    Nofib/Imaginary Results (14 tests)

    Trivially Safe

    Perfect Answer

    Good Failu res

    Bad Failures

    Good failure:Did not get perfect answer,

    but neither did I!

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    44/59

    Bad Failure: Bernouilli

    tail (tail x)

    z Actual condition: list is at least length 2z Inferred condition: list must be infinite

    drop 2 x

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    45/59

    Bad Failure: Paraffins

    radical_generator n = f undefinedwhere f unused = big_memory_result

    z array :: Ix a (a, a) [(a, b)] Array a b Each index must be in the given range

    Array indexing also problematic

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    46/59

    Perfect Answer: Digits of E2

    e =(2.++) $

    tail concat $map (show head) $

    iterate (carryPropagate 2 map (10*) tail) $

    2 : [1,1 ..]

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    47/59

    Performance of Catch

    0

    1

    2

    3

    45

    6

    7

    8

    0 200 400 600 800 1000 1200 1400

    Source Code

    Time(Seco

    nds)

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    48/59

    Case Study: HsColour

    zTakes Haskell source code and prints out acolourised version

    z

    4 years old, 6 contributors, 12 modules, 800+lines

    z Used by GHC nightly runs to generate docsz Used online by http://hpaste.org

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    49/59

    HsColour: Bug 1

    data Prefs = ... deriving (Read,Show)z Uses read/show serialisation to a file

    z readFile prefs, then read result

    z Potential crash if the user has modified thefile

    z Real crash when Prefs structure changed!

    FIXED

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    50/59

    HsColour: Bug 1 Catch

    > Catch HsColour.hsCheck Prelude.read: no parse

    Partial Prelude.read$252Partial Language.Haskell.HsColour

    .Colourise.parseColourPrefs

    ...

    Partial Main.mainFull log is recordedAll preconditions

    and properties

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    51/59

    HsColour: Bug 2

    zThe latex output mode had:outToken (\:xs) = ++ init xs ++

    z file.hs:

    z hscolour latex file.hs

    z Crash

    FIXED

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    52/59

    HsColour: Bug 3

    zThe html anchor output mode had:outToken ( :xs) = ++ init xs ++

    z file.hs: ( )

    z hscolour html anchor file.hs

    z Crash

    F

    IXED

    CH

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    53/59

    HsColour: Problem 4

    z A pattern match without a [] casez A nice refactoring, but not a crash

    z

    Proof was complex, distributed and fragile Based on the length of comment lexemes!

    z End result: HsColour cannot crash Or could not at the date I checked it...

    z Required 2.1 seconds, 2.7Mb

    CHANGED

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    54/59

    Case Study: FiniteMap library

    z Over 10 years old, was a standard libraryz 14 non-exhaustive patterns, 13 are safe

    delFromFM (Branch key ..) del_key

    | del_key > key = ...

    | del_key < key = ...

    | del_key key = ...

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    55/59

    Case Study: XMonad

    z Haskell Window Managerz Central module (StackSet)

    z

    Checked by Catch as a library

    z No bugs, but suggested refactorings

    z Made explicit some assumptions about Num

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    56/59

    Catchs Failings

    z Weakest Area: Yhc Conversion from Haskell to Core requires Yhc

    Can easily move to using GHC Core (once fixed)

    z 2nd Weakest Area: First-order transform

    Still working on this Could use supercompilation

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    57/59

    ??-Constraints

    z Could solve more complex problemsz Could retain numeric constraints precisely

    z

    Ideally have a single normal form

    z MP-constraints work well, but there is roomfor improvement

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    58/59

    Alternatives to Catch

    z Reach, SmallCheck Matt Naylor, Colin R Enumerative testing to some depth

    z

    ESC/Haskell - Dana Xu Precondition/postcondition checking

    z Dependent types Epigram, Cayenne

    Push conditions into the types

  • 7/29/2019 Slides-Detecting Pattern Match Failures in Haskell-26 Nov 2007

    59/59

    Conclusions

    z Pattern matching is an important area thathas been overlooked

    z Framework separate from constraints Can replace constraints for different power

    z Catch is a good step towards the solution

    Practical tool Has found real bugs

    www.cs.york.ac.uk/~ndm/catch