automated software verification with a permission-based logic 20 th june 2014, zürich malte...
TRANSCRIPT
Automated Software Verification with a
Permission-Based Logic
20th June 2014, ZürichMalte Schwerhoff, ETH Zürich
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}
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
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
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