Certified Correctness for Higher-order Programs Nikhil Swamy Microsoft Research, Redmond Many recent successes for semi-automated verifiers Spec# Boogie VeriFast Why3 Vampire Simplify CVC4

Download Report

Transcript Certified Correctness for Higher-order Programs Nikhil Swamy Microsoft Research, Redmond Many recent successes for semi-automated verifiers Spec# Boogie VeriFast Why3 Vampire Simplify CVC4

Certified Correctness
for Higher-order Programs
Nikhil Swamy
Microsoft Research, Redmond
Many recent successes
for semi-automated verifiers
Spec#
Boogie
VeriFast
Why3
Vampire Simplify CVC4
But, modern languages
are pervasively higher-order!
Lambdas everywhere!
Delegates, lambdas, LINQ, RX, …
delegate B Func<A,B>(A arg)
foreach (var i in L) {…}
JavaScript: Higher-order state everywhere!
+ AJAX, Event handlers, jQuery, DOM,…
Element.addEventListener(ev, function(node){…})
$('li').each(function(index) { .. })
Higher-order verifiers ~
interactive proof assistants
Agda
Very expressive logics! :-)
Impoverished programming languages
Pure total functions only :-(
NuPRL …
Enter F* …
http://research.microsoft.com/fstar
An ML-like language
with an SMT-based
dependent type system
Fournet
Chen
Bhargavan Borgstrom
Strub
Chugh
Dagand
Fredrikson
Guha
Schlesinger Weinberger
Yang
Jeannin
Livshits
Swamy
val f: x:int -> y:int{y = x + 1}
let f x = x + 1
val
let
|
|
hd: xs:list 'a{xs<>[]} -> 'a
hd = function
x::_ -> x
_ -> raise Not_found
Term language is core-ML,
in a syntax resembling
F#/Caml-light
Type language allows
expressing precise,
functional properties
val counter: unit -> Writer x:int{x >= 0}
let counter =
let c = ref 0 in
fun () -> c := !c + 1; !c
val compose: (x:'b -> DST 'c (WP_f x))
-> (y:'a -> DST 'b (WF_g y))
-> z:'a -> DST 'c (WP_f . WP_g z)
let compose f g x = f (g x)
F* source: core-ML with dependent refinement types uses
SMT solvers to discharge proof obligations (ESOP ‘10, ICFP’11)
val f: x:int -> y:int{y=x+1}
let f x = x + 1
Preserve types in .NET (PLDI ’10)
class C<‘a::int => *>
Interop with
C#, VB.NET, F#,…
F* source
Z3
Type-checker
Type-checker
in F*
+itself
Compiler
rDCIL
Java
Script
Run on Azure,
Windows Phone 7
Z3
C#, F#,…
rDCIL
Type-Checker
rDCIL
.NET Virtual Machine
JS verification by
translation to F*
(PLDI ’13)
Coq
Self-certified
core typechecker
(POPL ’12)
Fully abstract
compiler to JS
(POPL ’13)
7
int:S
int->bool:S
nat:S
Kinds
(>=):int => int => E
S
E
S => S (=):'a:S => 'a => 'a => E
int => S => S
list:S => S
array:int=>S=>S
int => int => E
Types t
int, bool, …
int -> bool
…
zero = x:int{x = 0}
0:int
0:zero
fun
fun x->e
x->e :: int->bool
int->bool
list int
array 17 float
sz:nat
sz:int -> init:'a -> array sz 'a
nat = x:int{x >= 0}
Expressions e
let x = e in e'
match v with D x -> e
ref v | v1 := v2 | !v | …
Values v
0, 1, 2,…
true, false, …
fun x -> e
The four base-kinds/universes of F*
{S, E, A, P}
P <: E
S <: E
A <: E
E universe
All terms, including ghost terms
P universe
S universe
Constructive
logic core , total
functions
Arbitrary
Effectful
computation
A universe
Affine types for
controlling
effects
http://rise4fun.com/FStar/tutorial/guide
http://rise4fun.com/FStar/plplY
http://rise4fun.com/FStar/FCE
http://rise4fun.com/FStar/8Ky
http://rise4fun.com/FStar/tutorial/jsStar
Reasoning
about effects in
monadic F*
Post-condition:
and
writes
heap
hReads
= h' on
all ref
cellsthe
except
{r1, r2},
Relates
pre-heap,
result
and
post-heap
Pre-condition
is
a heap
predicate
(heap => E)
and
any newly
allocated
ref
cells
heap to
=> read
'a =>and
heap
=> Er1, r2
Permission
write
val swap: r1:ref 'a
-> r2:ref 'a
-> Writer unit
(Requires λh. Perm r1 h /\ Perm r2 h)
(Ensures λh () h'. Perm r1 h' /\ Perm r2 h'
/\ h'[r1]=h[r2]
/\ h'[r2]=h[r1])
(Modifies {r1,r2})
let swap r1 r2 =
let tmp = !r1 in
r1 := !r2;
r2 := tmp
Closures and local state
let evens () =
let i = ref 0 in
fun () -> i := !i + 1; 2*!i
let evens' () =
let i = ref 0 in
let j = ref 0 in
fun () -> i := !i + 1;
j := !j + 1;
!i + !j
Can we give both the same spec,
hiding local state from the client?
Idea: pack the closure with invariant on its local state,
hiding the representation from the client
Pkg (Perm i) {i} (fun () -> i:=!i+1; 2*!i) : evens_t
'Inv instantiated to Perm i
fp={i} footprint of the local state
type evens_t =
'Inv is a pre- and post| Pkg: 'Inv:heap =>E
condition of the closure
-> fp:refset
(h|fp) is the fragment of the heap
-> (unit
h whose domain is the set fp of refs
-> Writer int
(Requires λh. 'Inv (h|fp))
(Ensures λh i h'.i%2=0 /\ 'Inv (h'|fp))
(Modifies fp))
-> evens_t
Closure returns an even number
let evens () =
let i = ref 0 in
Pkg (Perm i) {i} (fun () -> i := !i + 1; 2*!i)
The closure owns permission to {i,j};
i and j always hold the same value
let evens' () =
let i = ref 0 in
let j = ref 0 in
Pkg (λh. Perm i h /\ Perm j h /\ h[i]=h[j])
{i,j}
(fun () -> i := !i + 1;
j := !j + 1;
!i + !j)
Both return evens_t … almost there
Return evens_t
Ensures that the invariant of
val evens, evens’:
evens_t holds on the footprint
unit
And that the footprint is fresh
-> Writer evens_t
(Requires λh.True)
(Ensures λh v h'. Pkg.Inv v (h'| Pkg.fp v)
/\ Fresh h (Pkg.fp v))
(Modifies {})
evens_t is a strong sum
Can project the existentially bound variables
Pkg.Inv: evens_t => heap => E
projects the first component of a Pkg value, i.e., the invariant
Pkg.fp: evens_t -> refset
projects the second component of a Pkg value, i.e., the footprint
To date: nearly 50,000 lines of verified F* code
JavaScript
Verified
Solutionslibrary
to
source
VSTTE
forcode
JavaScript
‘11 (browser
competition
runtime
extensions)
with
support
heavy use of local state
PLDI ‘13
But, what does it mean to
verify a program in F*, formally?
F* in Coq
(simplified)
Inductive Tipe :=
| Tarrow : name -> Tipe -> Tipe -> Tipe
| …
with Expr :=
| Elam : name -> Tipe -> Expr -> Expr
| … .
Deep embedding of
syntax of F* in Coq
F* typing relation as an
Inductive Typing : Env -> Config -> Tipe -> Type := inductive type in Coq
| WFVar: g:Env -> x:name -> t:Tipe -> In g (x,t)
–> Typing g (Eval (Var x)) t
…
Inductive Steps : Config -> Config :=
| …
8 mutually recursive
judgments, ~65 rules
F* op. semantics
Metatheory of F* in Coq
(simplified)
Theorem Preservation: forall G e e’ t,
Typing G e t
-> Steps e e’
-> Typing G e’ t.
Theorem Progress: forall G e t,
Typing G e t
-> Value e \/ (exists e’. Steps e e’)
Well-typed F* programs do not contain failing assertions
More Metatheory of F*
(proved manually)
Theorem (Correspondence of the P universe):
Terms in F*’s logical core of constructive proofs
can be embedded in Coq,
and the embedding is a forward simulation
Corollary:
F*’s logical core of constructive proofs is strongly normalizing
E universe
P universe
S universe
A universe
But, what about the
type checker implementation?
Self-Certification
Src.fst
Z3
F* checker
checker
F*
programmed
in
F*
in F#
Theorem?
If src.fst type checks then it does not go wrong.
Coq
Bootstrap
certification
Src.fst
Z3
F*
Type-checker
typechecker
in F*
Theorem:
If src.fst typechecks then it does not go wrong.
Definitions.fst (F*)
type Tipe = ..
type Typing = …
…
Correspondence
theorem
Definitions.v (Coq)
Inductive Tipe := ..
Inductive Typing := …
…
Kernel type checker:
5,200 lines of F* code
organized into 11 modules
check_expr:
G:Env -> e:Expr -> t:Tipe
-> Partial (Typing G e t)
Metatheory.v (Coq)
check_expr’s result (if any)
is a valid typing derivation
F*
Theorem Preservation: …
Theorem Progress: …
Coq
Definitions.fst (F*)
type Tipe = ..
type Typing = …
…
Typing
derivation for
check_expr
Theorem: forall
G e (Coq)
t v,
Definitions.v
Correspondence
Steps (check_expr
G)
Inductive Tipe :=(embed
..
e)
Inductive Typing(embed
:= …
theorem
…
(embed t))
(Evalue v)
-> Typing G e t
Pretty print
as Coq term
check_expr:
G:Env -> e:Expr -> t:Tipe
-> Partial (Typing G e t)
Typing
derivation for
check_expr
7.3GB Coq term
Took 24 machine-days to check
Metatheory.v (Coq)
check_expr’s result (if any)
is a valid typing derivation
F*
Theorem Preservation: …
Theorem Progress: …
Coq
What next?
• More bootstrapping
– Always elaborating into core F* is expensive
– Certify higher-level checkers once and for al
• Meta F* in F*
– Prove syntactic soundness of F* in F*
– (See tutorial on STLC for flavor)
What next?
• JavaScript, TypeScript, and
friends
– Verification of JS/TS source
– Fully abstract embedding of Safe TS in JS
• Relational F*
– A logic for hyperproperties encoded in F*
• …
Try it out … happy to help you get started!
http://research.microsoft.com/fstar/