Model Checking Program Equivalence in Interface Middleweight … · 2019. 3. 31. · in Interface...

Preview:

Citation preview

Model Checking Program Equivalence Model Checking Program Equivalence in Interface Middleweight Javain Interface Middleweight Java

Andrzej Murawski Steven Ramsay Nikos Tzevelekos Uni. of Warwick Uni. of Oxford Queen Mary U. of London

Higher-Order Model Checking, Shonan, Mar 2016

Supported by a Royal Academy of Engineering Research Fellowship

what this talk is about

We examine contextual equivalence of Java programs● these are 'higher'-order

We work in an fragment of Middleweight Java ● open code modelled by use of interfaces● denotational approach based on game semantics

Full characterisation based on type disciplines:● queue machine encodings (negative cases)

● pushdown register automata (algorithms)

Implementation of decidable fragment in Coneqct

Program equivalence

M ≅ M'

same observable behaviour in every context

for all closing contexts C:

(C[M],) →* (skip,S) � (C[M'],) →* (skip,S')

● subsumes standard verification properties● contextual: quantification over every context● several methods for proving given equivalences

yet no general procedures

Interface Middleweight Java (IMJ)

Object calculus based on MJ [Bierman, Parkinson, Pitts]● Objects, inheritance, casting, interfaces

Types θ ::= void | int |

Interface definitions

Θ ::= | ( f : θ ), Θ | ( m : θ → θ ), Θ

Interface tables

Δ ::= | ( : Θ ), Δ | ( : Θ

), Δ

Interface Middleweight Java (IMJ)

Object calculus based on MJ [Bierman, Parkinson, Pitts]● Objects, inheritance, casting, interfaces

Types θ ::= void | int |

Interface definitions

Θ ::= | ( f : θ ), Θ | ( m : θ → θ ), Θ

Interface tables

Δ ::= | ( : Θ ), Δ | ( : Θ

), Δ

interface ident.

field identifier

method identif.

Interface Middleweight Java (IMJ)

TermsM ::= skip | a | null | x | i | M ⊕ M | if M M M

| let x = M in M | M = M | ()M | while M M

| new(x : ; M) | M.f | M.f := M | M.m( M )

Method implementations M ::= | (m : λx.Μ), M

Interface Middleweight Java (IMJ)

TermsM ::= skip | a | null | x | i | M ⊕ M | if M M M

| let x = M in M | M = M | ()M | while M M

| new(x : ; M) | M.f | M.f := M | M.m( M )

Method implementations M ::= | (m : λx.Μ), M

M = { mi : λxi .Μi | 1 i n }

IMJ: operational semantics

S, Μ → S', M'

S, let x = v in M → S, M[v/x]

S, a = a' → S, 0/1

S, new(x : ; M) → S ) {(a, , (V, M[a/x])}, a

S stores object names + their types and values

Obj : set of obj. names

a,a' Î Obj

V : default field values

Program equivalence – the plan

M ≅ M'

same observable behaviour in every context

for all closing contexts C:

(C[M],) →* (skip,S) � (C[M'],) →* (skip,S')

Program equivalence – the plan

M ≅ M'

same observable behaviour in every context

for all closing contexts C:

(C[M],) →* (skip,S) � (C[M'],) →* (skip,S')

we consider a finitary restriction IMJfin

and first identify the fragment decidable for termination

we use game semantics and types to characterise the fragment of IMJ

fin decidable for equivalence

termination inequivalence→

Two distinct sources of undecidability:

I.recursive methods

new(x : ; main: λy. {… x.main(..) … } )

II.objects with methods can be stored

let a = new(x : ; main: λy. {… } ) in

let b = new(x' : '; ) in b.var a

Termination

Theorem: Termination is undecidable for IMJfin terms that mayfeature I or II.Conversely, given an IMJfin term M that does not feature I or II, we can always decide whether it terminates.

M terminates if: (M,) →* (skip,S)

Games for program equivalence

We focus on:

and employ the fully abstract game semantics for IMJ:

M ≅ M' ⇔ M = M'

IMJfin

– {I,II}

program: M

denotation: M M

L

.

Games for program equivalence

We focus on:

and employ the fully abstract game semantics for IMJ:

● for negative results, given a queue machine Q, devise terms M, M':

● for decidability, given terms M, M', devise automata A, A':

M ≅ M' ⇔ M = M'

QÝ ⇔ M = M'

M = M' A ~⇔ A'

IMJfin

– {I,II}

Model the execution of programs as a 2-player game:

● Opponent (the environment, O )● Proponent (the program, P )

Qualitative games (no winning conditions)

Computations = plays of a specified game

Programs = strategies for P

Categories of games, extended with names & effects● storage: moves with stores

● conditions for name privacy and propagation

Nominal game semantics

Game apparatus

x1:θ

1, …, x

n:θ

n ⊢ M : θ

input types

output typefree variables

program

Game apparatus

x1:θ

1, …, x

n:θ

n ⊢ M : θ

input types

output typefree variables

program

M : θ1, …, θ

n θ

strategy arenas

Initial game moves

arenas

void = { * }

int = { 0, 1, -1, … }

= { a, b, … , n, … }

moves

M : θ1, …, θ

n θ

a, b, n, … N

N

a set of names

strategy

Games for IMJ programs

Program interactions are modelled by sequences of moves-with-store, written mΣ, where:

● move m is either:

– a value/arena move– an object method call/return

● stores are of the form:

Σ = {n (Emp, ), a (Ptr, val a), p (Pt2, x 1, y 0), c (Ptr', ), q (Pt2', ), … }

call c.set(c'), ret q.get(), …

Ptr' : ( get : Ptr' → Ptr', set : Ptr' → Ptr' )Pt2' : ( get : void → (int,int), set : (int,int) → void )

[ Murawski & T. '14 ]

IMJ example: game semantics

M1 = * c Σ0 ( call c.get() Σ0 ret c.get( nul ) Σ0 )*

call c.set( n1 ) Σ1 ret c.set() Σ1

( call c.get() Σ1 ret c.get( n1 ) Σ1 )*

call c.set( n2 ) Σ2 ret c.set( ) Σ2 ...

Σi = { c (Cell, ) } { nj (Empty, ) | 1 j i }

O OP P

Δ = Empty: , Cell: (get: void → Empty,

set: Empty → void),Var

Emp: (val: Empty),

VarInt

: (val: int)

M1 : let u = new( VarEmp ) in

new( M1 ) : Cell

M1 : get : λ_. u.val,

set : λy. u.val := y

Δ = Empty: , Cell: (get: void → Empty,

set: Empty → void), Var

Emp: (val: Empty),

VarInt

: (val: int)

* [Koutavas & Wand' 07]

IMJ example: game semantics

Δ = Empty: , Cell: (get: void → Empty,

set: Empty → void),Var

Emp: (val: Empty),

VarInt

: (val: int)

M1 : let u = new( VarEmp

) in

new( Cell; M1 ) : Cell

M1 : get : λ(). u.val,

set : λy. u.val := y

M1 = * c Σ0 ( call c.get() Σ0 ret c.get( nul ) Σ0 )*

call c.set( n1 ) Σ1 ret c.set() Σ1

( call c.get() Σ1 ret c.get( n1 ) Σ1 )*

call c.set( n2 ) Σ2 ret c.set( ) Σ2 ... = M2

Σi = { c (Cell, ) } { nj (Empty, ) | 1 j i }

O OP P

M2 : let b = new( VarInt ) in

let u1 = new( VarEmp

) in

let u2 = new( VarEmp

) in

new( M2 ) : Cell

M2 : get : λ_. if b.val

then b.val := 0 ; u1.val

else b.val := 1 ; u2.val,

set : λy. u1.val := y ;

u2.val := y

* [Koutavas & Wand' 07]

Games for program equivalence

We focus on:

and employ the fully abstract game semantics for IMJ:

● for negative results, given a queue machine Q, devise terms M, M':

● for decidability, given terms M, M', devise automata A, A':

M ≅ M' ⇔ M = M'

QÝ ⇔ M = M'

M = M' A ~⇔ A'

IMJfin

– {I,II}

One source of Undecidability

step state

P passes objects of type , and contains methods

: (step: void→void)N : (val: int)

(run: →void) ⊢ void

we can encodecomputations of queue machines!

One source of Undecidability

step

sym

previd

step

id

sym

previd

step

state

P passes objects of type , and contains methods

: (step: void→void)N : (val: int)

(run: →void) ⊢ void

we can encodecomputations of queue machines!

One source of Undecidability

step

sym

previd

step

id

sym

previd

step

state

P passes objects of type , and contains methods

: (step: void→void)N : (val: int)

(run: →void) ⊢ void

we can encodecomputations of queue machines!

One source of Undecidability

step

sym

previd

step

id

sym

previd

stepsym

previd

step

idid

state

P passes objects of type , and contains methods

: (step: void→void)N : (val: int)

(run: →void) ⊢ void

we can encodecomputations of queue machines!

One source of Undecidability

step

sym

previd

step

id

sym

previd

stepsym

previd

step

idid

state

P passes objects of type , and contains methods

: (step: void→void)N : (val: int)

(run: →void) ⊢ void

we can encodecomputations of queue machines!

One source of Undecidability

step

sym

previd

step

id

sym

previd

step

idid

state

P passes objects of type , and contains methods

: (step: void→void)N : (val: int)

(run: →void) ⊢ void

we can encodecomputations of queue machines!

One source of Undecidability

step

sym

previd

step

id

sym

previd

step

idid

state

P passes objects of type , and contains methods

: (step: void→void)N : (val: int)

(run: →void) ⊢ void

we can encodecomputations of queue machines!

One source of Undecidability

P passes objects of type , and contains methods

: (step: void→void)N : (val: int)

(run: →void) ⊢ void

we can encodecomputations of queue machines!

step

id

sym

previd

step

state

Undecidability

Three cases for undecidability:

● L = (…, m : → θ)● R = (…, m : θ → )● R = (…, m : ' → θ) where ' = (…, m : → θ)

and contains methods (i.e. is higher-order)

x : L ⊢ M : R

Decidable types – IMJ*

x : L M : R

G ::= void | int | (f : G)

L ::= void | int | (f : G, m : G → L)

R ::= void | int | (f : G, m : L → G)

Games for program equivalence

We focus on:

and employ the fully abstract game semantics for IMJ:

● for negative results, given a queue machine Q, devise terms M, M':

● for decidability, given terms M, M', devise automata A, A':

M ≅ M' ⇔ M = M'

QÝ ⇔ M = M'

M = M' A ~⇔ A'

IMJfin

– {I,II}

Model checking equivalence

GameSemantics

Automata

M

A(M)

Programs M M ≅ M'⇔

M = M'

GameSemantics

Automata

M

A(M)

Programs M Translation done in two steps:

● terms reduced to canonical forms

● canonical terms are compositionally transformed into automata

We work with pushdown automata:

● over infinite alphabets

● visibly pushdown & deterministic

Implemented in Coneqct!

Model checking equivalence

M ≅ M' ⇔ M = M' A⇔ ~ A' A⇔ ÄA' = 0

Coneqct

Coneqct architecture

IMJA Compiler

Canonical form Converter

Automaton Generator

Input IMJ* terms

IMJA Automata

FPDRA Builder

IMJ2A Converter

FPDRA Converter

FPDRA Automaton

FPDRA Reachability

Checker

FPDRA : Fresh Pushdown Register Automata

● MRT: Reachability in Pushdown Register Automata, MFCS'14

● MT: Algorithmic Games for Full Ground References, ICALP'12

Coneqct example

q32808[s1]

(((q32782, s2), s3), s4)[s1]

(((q32783, s2), s3), s4)[s5]

nu {4}. 4[s5]

(((q196, s2), s3), s4)[s5]

p1

(((q32169, s2), s3), s4)[s5]

nu {}. call 4.get(*)[s5]

((((q436, s6), s2), s3), s4)[s5]

nu {}. call 4.set(null)[s5]

(((q31586, s2), s3), s4)[s7]

nu {5}. call 4.set(5)[s7]

(((q32167, s2), s3), s10)[s5]

{4}

(((((q216, s1), s9), s2), s3), s4)[s5]

{4}

(((q31585, s2), s8), s4)[s7]

{4,5}

(((q31583, s11), s8), s4)[s7]

{4,5}

nu {}. *[s1]

(((q32680, s2), s3), s10)[s5]

nu {}. ret 4.get(null)[s5]

(((q32681, s2), s3), s10)[s5]

{4}

(((((q214, s1), s9), s2), s3), s4)[s5]

nu {}. *[s1]

(((q32388, s11), s8), s4)[s7]

nu {}. ret 4.set(*)[s7]

(((q32389, s11), s8), s4)[s7]

{4,5}(((q197, s2), s3), s10)[s5]

p1

(((q32172, s2), s3), s10)[s5]

nu {}. call 4.get(*)[s5]

((((q707, s6), s2), s3), s10)[s5]

nu {}. call 4.set(null)[s5]

(((q31518, s2), s3), s10)[s7]

nu {5}. call 4.set(5)[s7]

(((q209, s11), s8), s4)[s7]

p2

(((q32289, s11), s8), s4)[s7]

nu {}. call 4.get(*)[s7]

((((q24551, s12), s11), s8), s4)[s7]

nu {}. call 4.set(null)[s7]

(((q31626, s11), s8), s4)[s7]

nu {}. call 4.set(5)[s7]

(((q31810, s11), s8), s4)[s13]

nu {6}. call 4.set(6)[s13]

(((q32170, s2), s3), s4)[s5]

{4}

(((((q496, s1), s9), s2), s3), s10)[s5]

{4}

(((q31517, s2), s8), s10)[s7]

{4,5}

(((q31515, s11), s8), s10)[s7]

{4,5}

nu {}. *[s1]

(((q32682, s2), s3), s4)[s5]

nu {}. ret 4.get(null)[s5]

(((q32287, s11), s8), s10)[s7]

{4,5}

(((((q24322, s1), s15), s11), s8), s4)[s7]

{4,5}

(((q31625, s11), s8), s4)[s7]

{4,5}

(((q31809, s11), s14), s4)[s13]

{4,5,6}

(((q31807, s16), s14), s4)[s17]

{4,6}

(((q31623, s11), s8), s4)[s7]

{4,5}nu {}. *[s1]

(((q32760, s11), s8), s10)[s7]

nu {}. ret 4.get(5)[s7]

(((q32683, s2), s3), s4)[s5]

{4}

(((((q494, s1), s9), s2), s3), s10)[s5]

nu {}. *[s1]

(((q32354, s11), s8), s10)[s7]

nu {}. ret 4.set(*)[s7]

(((q32355, s11), s8), s10)[s7]

{4,5}

p1

(((q32761, s11), s8), s10)[s7]

{4,5}

(((((q24320, s1), s15), s11), s8), s4)[s7]

nu {}. *[s1]

(((q32408, s11), s8), s4)[s7]

nu {}. ret 4.set(*)[s7]

(((q32500, s16), s14), s4)[s17]

nu {}. ret 4.set(*)[s17]

(((q32501, s16), s14), s4)[s17]

{4,6}

(((q32409, s11), s8), s4)[s7]

{4,5}

(((q205, s11), s8), s10)[s7]

p2

p2

(((q32241, s11), s8), s10)[s7]

nu {}. call 4.get(*)[s7]

((((q14410, s12), s11), s8), s10)[s7]

nu {}. call 4.set(null)[s7]

(((q31558, s11), s8), s10)[s7]

nu {}. call 4.set(5)[s7]

(((q31742, s11), s8), s10)[s13]

nu {6}. call 4.set(6)[s13]

p2 p3

(((q32239, s11), s8), s4)[s7]

{4,5}

(((((q14100, s1), s15), s11), s8), s10)[s7]

{4,5}

(((q31557, s11), s8), s10)[s7]

{4,5}

(((q31741, s11), s14), s10)[s13]

{4,5,6}

(((q31739, s16), s14), s10)[s17]

{4,6}

(((q31555, s11), s8), s10)[s7]

{4,5}

nu {}. *[s1]

(((q32728, s11), s8), s4)[s7]

nu {}. ret 4.get(5)[s7]

(((q32729, s11), s8), s4)[s7]

{4,5}

(((((q14098, s1), s15), s11), s8), s10)[s7]

nu {}. *[s1]

(((q32374, s11), s8), s10)[s7]

nu {}. ret 4.set(*)[s7]

(((q32466, s16), s14), s10)[s17]

nu {}. ret 4.set(*)[s17]

(((q32467, s16), s14), s10)[s17]

{4,6}

(((q32375, s11), s8), s10)[s7]

{4,5} p2

p2 p3

s1: map []s2: map [(3, (VarEmpty, map [(val, null)]))]s3: map [(2, (VarEmpty, map [(val, null)]))]s4: map [(1, (VarInt, map [(val, 0)]))]s5: map [(4, (Cell, map []))]s6: map [(5, (_VarInt, map [(_val, 0)]))]s7: map [(4, (Cell, map [])); (5, (Empty, map []))]s8: map [(2, (VarEmpty, map [(val, 5)]))]s9: map [(5, (_VarInt, map [(_val, 1)]))]s10: map [(1, (VarInt, map [(val, 1)]))]s11: map [(3, (VarEmpty, map [(val, 5)]))]s12: map [(6, (_VarInt, map [(_val, 0)]))]s13: map [(4, (Cell, map [])); (5, (Empty, map [])); (6, (Empty, map []))]s14: map [(2, (VarEmpty, map [(val, 6)]))]s15: map [(6, (_VarInt, map [(_val, 1)]))]s16: map [(3, (VarEmpty, map [(val, 6)]))]

s17: map [(4, (Cell, map [])); (6, (Empty, map []))]

p1: map [(1, 1); (2, 2); (3, 3); ... ]p2: map [(1, 1); (2, 2); (3, 3); ... ]p3: map [(1, 1); (2, 2); (3, 3); ... ]

(q191, s1)[s2]

(q192, s1)[s3]

nu {2}. 2[s3]

(q1, s1)[s3]

p1

(q165, s1)[s3]

nu {}. call 2.get(*)[s3]

((q33, s4), s1)[s3]

nu {}. call 2.set(null)[s3]

(q146, s1)[s5]

nu {3}. call 2.set(3)[s5]

(q185, s1)[s3]

nu {}. ret 2.get(null)[s3]

(((q8, s2), s7), s1)[s3]

{2}

(q144, s6)[s5]

{2,3}

(q171, s6)[s5]

nu {}. ret 2.set(*)[s5]

(((q6, s2), s7), s1)[s3]

{2}

(q186, s1)[s3]

{2}

p1

{2}

(q172, s6)[s5]

{2,3}

(q2, s6)[s5]

p2

(q167, s6)[s5]

nu {}. call 2.get(*)[s5]

((q85, s8), s6)[s5]

nu {}. call 2.set(null)[s5]

(q149, s6)[s5]

nu {}. call 2.set(3)[s5]

(q158, s6)[s9]

nu {4}. call 2.set(4)[s9]

(q187, s6)[s5]

nu {}. ret 2.get(3)[s5]

(((q54, s2), s12), s6)[s5]

{2,3}

(q147, s6)[s5]

{2,3}

(q156, s10)[s11]

{2,4}

(q179, s10)[s11]

nu {}. ret 2.set(*)[s11]

(q173, s6)[s5]

nu {}. ret 2.set(*)[s5]

(((q52, s2), s12), s6)[s5]

{2,3}

(q188, s6)[s5]

{2,3}

p2

{2,3}

(q174, s6)[s5]

{2,3}

(q180, s10)[s11]

{2,4}

p3p2

s1: map [(1, (VarEmpty, map [(val, null)]))]s2: map []s3: map [(2, (Cell, map []))]s4: map [(3, (_VarInt, map [(_val, 0)]))]s5: map [(2, (Cell, map [])); (3, (Empty, map []))]s6: map [(1, (VarEmpty, map [(val, 3)]))]s7: map [(3, (_VarInt, map [(_val, 1)]))]s8: map [(4, (_VarInt, map [(_val, 0)]))]s9: map [(2, (Cell, map [])); (3, (Empty, map [])); (4, (Empty, map []))]s10: map [(1, (VarEmpty, map [(val, 4)]))]s11: map [(2, (Cell, map [])); (4, (Empty, map []))]

s12: map [(4, (_VarInt, map [(_val, 1)]))]

p1: map [(1, 1); (2, 2)]p2: map [(1, 1); (2, 2); (3, 3)]p3: map [(1, 1); (2, 2); (4, 3)]

M1 : let v = new { _: VarEmpty t

} in new { _: Cell; get : λ_. v.val,

set : λy. if y = null then divelse v.val := y ; w.val := y

M2 : let b = new { _: VarInt

} in

let v = new { _: VarEmpty

} in

let w = new { _: VarEmpty

} in new { _: Cell; get : λ_. if b.val = 1 then b.val := 0 ; v.val

else b.val := 1 ; w.val, set : λy. if y = null then div

else v.val := y ; w.val := y

(q191, s1)[s2]

(q192, s1)[s3]

nu {2}. 2[s3]

(q1, s1)[s3]

p1

(q165, s1)[s3]

nu {}. call 2.get(*)[s3]

((q33, s4), s1)[s3]

nu {}. call 2.set(null)[s3]

(q146, s1)[s5]

nu {3}. call 2.set(3)[s5]

(q185, s1)[s3]

nu {}. ret 2.get(null)[s3]

(((q8, s2), s7), s1)[s3]

{2}

(q144, s6)[s5]

{2,3}

(q171, s6)[s5]

nu {}. ret 2.set(*)[s5]

(((q6, s2), s7), s1)[s3]

{2}

(q186, s1)[s3]

{2}

p1

{2}

(q172, s6)[s5]

{2,3}

(q2, s6)[s5]

p2

(q167, s6)[s5]

nu {}. call 2.get(*)[s5]

((q85, s8), s6)[s5]

nu {}. call 2.set(null)[s5]

(q149, s6)[s5]

nu {}. call 2.set(3)[s5]

(q158, s6)[s9]

nu {4}. call 2.set(4)[s9]

(q187, s6)[s5]

nu {}. ret 2.get(3)[s5]

(((q54, s2), s12), s6)[s5]

{2,3}

(q147, s6)[s5]

{2,3}

(q156, s10)[s11]

{2,4}

(q179, s10)[s11]

nu {}. ret 2.set(*)[s11]

(q173, s6)[s5]

nu {}. ret 2.set(*)[s5]

(((q52, s2), s12), s6)[s5]

{2,3}

(q188, s6)[s5]

{2,3}

p2

{2,3}

(q174, s6)[s5]

{2,3}

(q180, s10)[s11]

{2,4}

p3p2

s1: map [(1, (VarEmpty, map [(val, null)]))]s2: map []s3: map [(2, (Cell, map []))]s4: map [(3, (_VarInt, map [(_val, 0)]))]s5: map [(2, (Cell, map [])); (3, (Empty, map []))]s6: map [(1, (VarEmpty, map [(val, 3)]))]s7: map [(3, (_VarInt, map [(_val, 1)]))]s8: map [(4, (_VarInt, map [(_val, 0)]))]s9: map [(2, (Cell, map [])); (3, (Empty, map [])); (4, (Empty, map []))]s10: map [(1, (VarEmpty, map [(val, 4)]))]s11: map [(2, (Cell, map [])); (4, (Empty, map []))]

s12: map [(4, (_VarInt, map [(_val, 1)]))]

p1: map [(1, 1); (2, 2)]p2: map [(1, 1); (2, 2); (3, 3)]p3: map [(1, 1); (2, 2); (4, 3)]

Coneqct example

M1 : let v = new { _: VarEmpty t

} in new { _: Cell; get : λ_. v.val,

set : λy. if y = null then divelse v.val := y ; w.val := y

M2 : let b = new { _: VarInt

} in

let v = new { _: VarEmpty

} in

let w = new { _: VarEmpty

} in new { _: Cell; get : λ_. if b.val = 1 then b.val := 0 ; v.val

else b.val := 1 ; w.val, set : λy. if y = null then div

else v.val := y ; w.val := y

Wrapping up

Contextual equivalence● decidability characterised via games● automated decision via FPDRAs Coneqct →

Further on● sound methods for the whole of IMJ● general model checking and logics

References● MRT: Game Semantic Analysis of Equivalence in IMJ, ATVA'15

● MRT: A Contextual Equivalence Checker for IMJ*, ATVA'15

Recommended