work-in-progress: verifying the glasgow haskell compiler ...sweirich/talks/dagstuhl18.pdf · 1.is...
Post on 29-Jun-2020
2 Views
Preview:
TRANSCRIPT
Work-in-progress:VerifyingtheGlasgowHaskellCompilerCorelanguage
StephanieWeirich
May2018
JoachimBreitner, AntalSpector-Zabusky, YaoLi,ChristineRizkallah, JohnWiegley
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
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
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
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.
top related