work-in-progress: verifying the glasgow haskell compiler ...sweirich/talks/dagstuhl18.pdf · 1.is...

27
Work-in-progress: Verifying the Glasgow Haskell Compiler Core language Stephanie Weirich May 2018 Joachim Breitner , Antal Spector-Zabusky , Yao Li , Christine Rizkallah, John Wiegley

Upload: others

Post on 29-Jun-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Verifiedcompilersandsecurity• Tobeabletoargueaboutthesecurityofaprogram,weneedaspecification ofthelanguagesemantics

• We also need to know that a specificcompilerimplementsthatthatsemanticscorrectly

• This talk: pragmaticsofspecifyingandverifyingatyped,higher-orderfunctionalprogramminglanguage

2

SpecifiedandVerifiedCompilation• Semanticsspecifiedusingtrace-basedco-inductiverelations

• CompCert compilerimplementedastotalfunctionalprograminGallina

• Otherexamples:CakeML,Vellvm,etc.

3

Whatifwealready haveacompilerthatwewanttospecifyandverify?

GlasgowHaskellCompiler(GHC)

5

GHCisabootstrappingcompiler• WanttouseCoqtoreasonaboutGHC– NeedasemanticsforHaskellinCoq– Butthat is what we are trying tobuild!

• "Easy"approach:shallowembedding– UseGallina asastand-inforHaskell

– TranslateHaskellfunctionstoGallina functions,usethatasspecification 6

GHCfrontend

GHCcorelanguage

GHCbackend

Haskell

Core.v

Gallina

hs-to-coqAtoolfortranslatingHaskellcodetoequivalentGallinadefinitionsviashallowembedding[CPP'18]

7

foldr :: (a -> b -> b) -> b -> [a] -> bfoldr k z = go

wherego [] = zgo (y:ys) = y `k` go ys

Definition foldr {a} {b} : (a -> b -> b) -> b -> list a -> b :=

fun k z =>let fix go arg_0__

:= match arg_0__ with| nil => z| cons y ys => k y (go ys)end in

go.

Questionsabouths-to-coqapproach1. IsthereenoughHaskellcodeouttherethatwecantranslatetomakethisapproachworthwhile?

2. Evenifwecanfindcodetotranslate,istheresultsuitableforverification?

3. Evenifwecandotheproofs,dotheymeananythingabouttheHaskellsource?

8

Casestudy:containers• PopularHaskelllibraries:Data.Set andData.IntSet

• UsedbyGHCCorelanguageimplementation• Whatdidweprove?– Invariants in the source filecomments(ensuresthebalanceproperties)

– Mathematicalspecification(bothourownandFSetInterface)

– Quickcheck propertiesinterpretedastheorems– GHCRewriterules

9ExperienceReport:Ready,Set,Verify!Applyinghs-to-coqtoreal-worldHaskellcodeJoachimBreitner, AntalSpector-Zabusky, YaoLi, ChristineRizkallah, JohnWiegley, StephanieWeirichICFP2018(cond.acc.)

IntSet.hs Property-basedtest suite

IntSet.v

hs-to-coq

ExtactedIntSet.hs Property-basedTest suite

Coq

MinimaleditsPropProofs.v

IntSetProperties.v(tests as props)

hs-to-coq

IntSetProofs.v

Coq.FSets.FSetInterface

Containerscasestudy

Whatdidwelearn?1. We can translatethelibrary*2. We can provewhatwewanttoprove**3. Outputissemanticallyequivalent(asfaras

wecantellbytesting)4. HaskellcodeisfunctionallycorrectJ

*Needto address partiality**We"edit"thecodeduringtranslationinsupport ofproofs

11

Partiality:Unsound

Axiom error : forall {a} , String -> a.

Definition head {a}(xs : list a) : a :=

match xs with| (x::_) => x| _ => error "head: empty list"end.

12

head :: [a] -> a head (x:_) = x head [] = error "head: empty list"

Partiality:Annoying

Inductive Partial (a:Type) := | return : a -> Partial a | error : String -> Partial a | …

Definition head {a} (xs : list a) : Partial a :=match xs with| (x::_) => return x| _ => error "head: empty list"end.

13

head :: [a] -> a head (x:_) = x head [] = error "head: empty list"

Partiality:Pragmatic

Definition error : forall {a} `{Default a},String -> a := default.

Definition head {a} `{Default a}(xs : list a) : a :=

match xs with| (x::_) => x| _ => error "head: empty list"end.

14

head :: [a] -> a head (x:_) = x head [] = error "head: empty list"

☞ "default"isanopaquedefinitionandproofsmustworkforanyvalueoftheappropriatetype.Thisisalmostarequirementthatitoccursindeadcode.

AFormalizationGapisagood thing• Machine integers are fixed width. Do wewantto reason aboutoverflow?

• No!– InData.Set,Ints tracksizeoftreeforbalance– GHCusesData.IntSet togenerateuniquenames– Both cases will run out of memorybeforeoverflow

• Controltranslationwithhs-to-coqrewrites– typeGHC.Num.Int = Coq.ZArith.BinNum.Z– Formalizationgapisexplicit&recorded

16

AFormalizationGapisagood thing• Machine integers storepositiveandnegativenumbers.Do we wantthat?

• No!– InData.Set,Ints tracksizeoftreeforbalance– GHCusesData.IntSet togenerateuniquenames– Both cases neverneedtostorenegativenumbers

• Controltranslationwithhs-to-coqrewrites– typeGHC.Num.Int =Coq.NArith.BinNat.N– Formalizationgapisexplicit&recorded

17

WhataboutGHC?

QuestionsaboutGHC1. IsthereenoughcodeinGHC thatwecantranslatetomakethisapproachworthwhile?

2. Evenifwecanfindcodetotranslate,istheresultsuitableforverification?

3. Evenifwecandotheproofs,dotheymeananythingabouttheGHCimplementation?(Note:Coreplug-inoptionavailable)

19

GHC:Currentstatus• Baselibraries(9kloc)– 45separatemodules– Somewrittenby-hand:GHC.Prim,GHC.Num,GHC.Tuple– Mosttranslated:GHC.Base,Data.List,Data.Foldable,Control.Monad,etc.

• Containers(6kloc)– Translated&(mostly)verified:4modules– (Data.Set,Data.Map,Data.IntSet,Data.IntMap)

• GHC,version8.4.1(19kloc)– 55modulessofar(327modulestotalinGHC,butwewon'tneedthemall)

– hs-to-coqedits(2kLOC)• First verificationgoal:Exitify compilerpass

20

21

CoreASTdata Expr b= Var Id| Lit Literal| App (Expr b) (Arg b)| Lam b (Expr b)| Let (Bind b) (Expr b)| Case (Expr b) b Type

[Alt b] | Cast (Expr b) Coercion| Tick (Tickish Id) (Expr b)| Type Type| Coercion Coercionderiving Data

data Bind b = NonRec b (Expr b)

| Rec [(b, (Expr b))]deriving Data

Inductive Expr b : Type:= Mk_Var : Id -> Expr b| Lit : Literal -> Expr b| App :

Expr b -> Arg b -> Expr b| Lam : b -> Expr b -> Expr b| Let :

Bind b -> Expr b -> Expr b| Case : Expr b -> b -> unit

-> list (Alt b) -> Expr b| Cast :

Expr b -> unit -> Expr b| Tick : Tickish Id

-> Expr b -> Expr b| Type_ : unit -> Expr b| Coercion : unit -> Expr b

with Bind b : Type:= NonRec : b -> Expr b

-> Bind b| Rec : list (b * (Expr b))

-> Bind b

Core Optimization:Exitify

23

-- | Given a recursive group of a joinrec, identifies-- “exit paths” and binds them as-- join-points outside the joinrec.

exitify :: InScopeSet -> [(Var,CoreExpr)] -> (CoreExpr -> CoreExpr)

exitify in_scope pairs =\body -> mkExitLets exits (mkLetRec pairs' body)

where pairs' = … // updated recursive groupexits = … // exit paths

-- 215 LOC, incl comments

• Requiresmovingcodefromonebindingscopetoanother• Firstproof:showthatwell-scopedtermsstaywell-scoped

Bugfound!• Exitify doesnotalwaysproducedwell-scopedcode– MissedbyGHCtestsuite– Perhapsnot exploitable at source level

• FixedinGHCHEAD– Proofsupdatedthisweek

• Whatisthegeneralworkflow?– AlwaysworkonHEAD?Maintainseparatebranch?

– Axiomatizefailinglemma?– Fixcodeviahs-to-coqedits?

25

Conclusion&MorequestionsLet'stakeadvantageofthesemanticsimilarityofHaskellandGallina fordevelopingverifiedcompilers

• Howfarcanwepushthisapproach?• Canwegetgoodperformanceof extractedcode?(AndplugbackintoGHC?)

• Canwesayanythingaboutlinkingwithnonverifiedcode?

27

Backupslides…

28

WhynotuseCoInductive?• Anotherformalizationgap– Haskelldatatypesareco-inductivebydefault

• Butinductivereasoningisusefulforcompilersandlanguages– Terminationoffunctionsdependsondecreasingsizeofdatastructure

• Thisisanexampleofaninvariantaboutthecorelanguage– Weassumeitneverneedstoworkwithinfiniteterms,andprovethatitnevergeneratesinfiniteterms

– NevergoingtocreateanASTtermwithan"infinite"numberoflambdaexpressions

29

What'sinGHCCore?• Additionalgeneralpurposelibraries– Bag,State,Maybes,Pair,FiniteMap,OrdList,MonadUtils,BooleanFormula,…

• Compiler-specificutilities– SrcLoc,Module,DynFlags,Constants,– Unique,UniqSupply,UniqSet,UniqFM,…

• CoreASTrepresentation– IdInfo,Var,VarSet,VarEnv,Name,Id,Demand– Class,TyCon,DataCon,CoreSyn

• Coreoperationsandoptimization– CoreFVs, CoreSubst,CallArity,CoreArity,– Exitify

30

Exitify exampleExample:

lett=foobar

joinrec

go0xy=t(x*x)

go(n-1)xy=jumpgo(n-1)(x+y)

in…

Exampleresult:

lett=foobar

joinexitx=t(x*x)

joinrec

go0xy=jumpexitx

go(n-1)xy=jumpgo(n-1)(x+y)

in…

31

Now`t`isnolongerinarecursive

function,andgoodthingshappen!

We’dliketoinline`t`,butthat

doesnothappen:Becausetis

athunk andisusedina

recursivefunction,doingso

mightlosesharingingeneral.

Inthiscase,however,`t`ison

the_exitpath_of`go`,socalled

atmostonce.