automated software verification with a permission-based logic 20 th june 2014, zürich malte...

30
Automated Software Verification with a Permission-Based Logic 20 th June 2014, Zürich Malte Schwerhoff, ETH Zürich

Upload: donte-robey

Post on 14-Dec-2015

215 views

Category:

Documents


1 download

TRANSCRIPT

Automated Software Verification with a

Permission-Based Logic

20th June 2014, ZürichMalte Schwerhoff, ETH Zürich

Outline

1. Motivation2. Permissions3. Viper4. Demo

3

‐We have‐ Mutable state (heap locations)‐ Method calls, loops‐ Concurrency

‐We want:‐ Automated static verification‐ Modularity

Automated Software Verification

4

Example

class Cell { var v: int

method add(c: Cell) { v := v + c.v }}

method client() { var c1 := new Cell c1.v := 1 var c2 := new Cell c2.v := 2 c1.add(c2) assert c1.v == 3 assert c2.v == 2}

5

Modularity

class Cell { var v: int

method add(c: Cell) { v := v + c.v }}

method client() { var c1 := new Cell c1.v := 1 var c2 := new Cell c2.v := 2 c1.add(c2) assert c1.v == 3 assert c2.v == 2}

?

6

Specifications

class Cell { var v: int

method add(c: Cell) requires c != null ensures v == old(v) + old(c.v) { v := v + c.v }}

method client() { var c1 := new Cell c1.v := 1 var c2 := new Cell c2.v := 2 c1.add(c2) assert c1.v == 3 assert c2.v == 2}

7

Reasoning with Specifications

class Cell { var v: int

method add(c: Cell) requires c != null ensures v == old(v) + old(c.v) { v := v + c.v }}

method client() { var c1 := new Cell c1.v := 1 var c2 := new Cell c2.v := 2 c1.add(c2) assert c1.v == 3 assert c2.v == 2}

?

8

An Incorrect Implementation

class Cell { var v: int

method add(c: Cell) requires c != null ensures v == old(v) + old(c.v) { v := v + c.v c.v := 0 }}

method client() { var c1 := new Cell c1.v := 1 var c2 := new Cell c2.v := 2 c1.add(c2) assert c1.v == 3 assert c2.v == 2}

9

Strengthening Specifications

class Cell { var v: int

method add(c: Cell) requires c != null ensures v == old(v) + old(c.v) ensures c.v == old(c.v) { v := v + c.v c.v := 0 }}

method client() { var c1 := new Cell c1.v := 1 var c2 := new Cell c2.v := 2 c1.add(c2) assert c1.v == 3 assert c2.v == 2}

10

Strengthening Specifications

method client() { var c1 := new Cell c1.v := 1 var c2 := new Cell c2.v := 2 c1.add(c2) assert c1.v == 3 assert c2.v == 2}

class Cell { var v: int

method add(c: Cell) requires c != null ensures v == old(v) + old(c.v) ensures c.v == old(c.v) { v := v + c.v }}

?

11

Aliasing

class Cell { var v: int

method add(c: Cell) requires c != null ensures v == old(v) + old(c.v) ensures c.v == old(c.v) { v := v + c.v }}

method client() { var c1 := new Cell c1.v := 1 var c2 := new Cell c2.v := 2

c1.add(c1) // ensures c1.v == 1 + 1 // ensures c1.v == 1

assert c1.v == 3 assert c2.v == 2}

12

Reason about Shared State

&

Control Aliasing

Challenges

13

‐Use permissions to control access to shared state

‐Permissions only exist conceptually, not at run-time

‐Permissions‐ Per field x.f‐ Exclusive write permissions (allows reading as well)

‐ Non-exclusive read permissions

Permission-Based Verification

14

‐Permissions to a location x.f can be‐ Split into multiple read permissions‐ Transferred between methods (or threads)‐ Recombined again

Permission-Based Verification

15

Fractional Permissions

client(x) add(x)

16

Splitting & Transferring Fractional Permissions

?

client(x) add(x)

?

17

Merging Fractional Permissions

?

client(x) add(x)

18

‐Assumptions such as x.f == 0 can only be made if permissions to x.f are available

‐ If all permissions to x.f are lost, assumptions about x.f must be havoced (forgotten)

Permission-Based Verification

19

‐Permissions can be split:

acc(x.f, 1) ⇔ acc(x.f, 1/2) && acc(x.f, 1/2)

‐Write permissions are exclusive:

acc(x.f, 1) && acc(y.f, 1) ⇒ x ≠ y

‐Write permissions are “maximal”:

acc(x.f, 1) && acc(y.f, 1/100000) ⇒ x ≠ y

Syntax, Separating Conjunction

20

Return of the Example

20

method add(c: Cell) requires acc(v) && acc(c.v, 1/2) ensures acc(v) && acc(c.v, 1/2) ensures v == old(v) + c.v

method client() { var c1 := new Cell // acc(c1.v) c1.v := 1 // c1.v == 1 var c2 := new Cell // acc(c2.v) c2.v := 2 // c2.v == 2

c1.add(c2) assert c1.v == 3 && c2.v == 2}

?

21

Return of the Example

21

method add(c: Cell) requires acc(v) && acc(c.v, 1/2) ensures acc(v) && acc(c.v, 1/2) ensures v == old(v) + c.v

method client() { var c1 := new Cell // acc(c1.v, 1) c1.v := 1 // c1.v == 1 var c2 := new Cell // acc(c2.v, 1) c2.v := 2 // c2.v == 2

c1.add(c2) assert c1.v == 3 && c2.v == 2}

Reason about call by exhaling preconditionfollowed by inhaling postcondition

22

Return of the Example

22

method add(c: Cell) requires acc(v) && acc(c.v, 1/2) ensures acc(v) && acc(c.v, 1/2) ensures v == old(v) + c.v

method client() { ... // c1.add(c2)

// acc(c1.v, 1) && c1.v == 1 && acc(c2.v, 1) && c2.v == 2 exhale acc(c1.v) && acc(c2.v, 1/2) // && acc(c2.v, 1/2) && c2.v == 2 inhale acc(c1.v) && acc(c.v, 1/2) // acc(c1.v, 1) && acc(c2.v, 1) && c2.v == 2 inhale c1.v == old(c1.v) + c2.v // acc(c1.v, 1) && c1.v == 3 && acc(c2.v, 1) && c2.v == 2 assert c1.v == 3 && c2.v == 2}

23

Viper

Silver

SiliconCarbon

Boogie(Microsoft)

Z3(Microsoft)

verified by

queries

VerificationCondition

Generation

Symbolic Execution

24

Silver

‐Silver is an intermediate verification language

‐ Encode source languages (with specs) in Silver‐ Use Silver verifier to verify encoding

‐Simple:‐ Objects, fields (heap), methods, loops, if-then-else

‐ Rudimentary type system (primitives + Ref) ‐ Verification features such as specifications‐ No concurrency primitives

‐Silver programs can be used for‐ Verification‐ Specification inference

25

Demo

26

Symbolic Execution with Silicon

- Symbolically each method (method-modular)

- At each statement:- query state (and prover) to decide if statement is

executable - update state by exhaling precondition and inhaling postcondition

- Branch over conditionals

Program

Verifierverifies maintains Symbolic State

σ

Prover

uses

σ1 σ2 σ3 σ4 σ5

queries

27

Symbolic state σ comprises‐ γ: Store mapping local variables to symbolic values (terms)

c1 ↦ tc1, c2 ↦ tc2‐ h: Heap recording permissions to and values of fields in the form of heap chunks

tc1.v ↦ tv1 # p1, tc2 ↦ tv2 # p2‐ π: Path conditions with assumptions about values

tc1 ≠ null, tv1 > 0

Symbolic Execution with Silicon

28

Slide of the Undead Example

28

method client() { ...

// γ: c1 ↦ tc1, c2 ↦ tc2 // h: tc1.v ↦ tv1 # 1, tc2.v ↦ tv2 # 1 // π: tv1 == 1, tv2 == 2

exhale acc(c1.v) && acc(c2.v, 1/2) // h: tc2.v ↦ tv2 # 1/2 // π: tv1 == 1, tv2 == 2

inhale acc(c1.v) && acc(c.v, 1/2) // h: tc1.v ↦ tv1 # 1, tc2.v ↦ tv3 # 1 // π: tv1 == 1, tv2 == 2

inhale c1.v == old(c1.v) + c2.v // π: tv1 == 1, tv2 == 2, tv3 == tv1 + tv2 assert c1.v == 3 && c2.v == 2 // π ⊢ tv3 == 3 && tv2 == 2}

29

‐ Information hiding and abstraction

‐Recursive data structures

‐Opposite of permissions: obligations

‐Translation of high-level features‐ Immutable data (vs. permissions)‐ Lazy evaluation (vs. permissions)‐ Closures‐ Actor-based concurrency

‐Specification inference

Outlook

30

Questions?