Permissions foo(x)

An Introduction to Automated
Program Verification with
Permission Logics
Uri Juhasz, Ioannis Kassios, Peter Müller, Milos Novacek,
Malte Schwerhoff, Alex Summers (and several students)
15th May 2015, Systems Group, ETH Zurich
Initial Example (Pseudo Java)
class Cell {
int v
void add(Cell c)
{ v = v + c.v }
void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
}
c1.add(c2)
assert c1.v == 3
assert c2.v == 2
}
Goal: Check assertions statically
Challenges:
− Whole-code analysis is expensive
− Dynamic dispatch (inheritance; open-world assumption)
3
Modularity
class Cell {
int v
void add(Cell c)
{ v = v + c.v }
void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
}
c1.add(c2)
assert c1.v == 3
assert c2.v == 2
}
?
4
Specifications
class Cell {
int v
void add(Cell c)
requires c != null
ensures v == old(v) + old(c.v)
{ v = v + c.v }
void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
c1.add(c2)
}
assert c1.v == 3
assert c2.v == 2
}
5
Reasoning with Specifications
class Cell {
int v
void add(Cell c)
requires c != null
ensures v == old(v) + old(c.v)
{ v = v + c.v }
void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
c1.add(c2)
}
assert c1.v == 3
assert c2.v == 2
}
?
6
An Incorrect Implementation
class Cell {
int v
void add(Cell c)
requires c != null
ensures v == old(v) + old(c.v)
{
v = v + c.v
c.v = 0
}
}

void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
c1.add(c2)

assert c1.v == 3
assert c2.v == 2
}
7
Strengthening Specifications
class Cell {
int v
void add(Cell c)
requires c != null
ensures v == old(v) + old(c.v)
ensures c.v == old(c.v)
{
v = v + c.v
c.v = 0
}

void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
c1.add(c2)
assert c1.v == 3
assert c2.v == 2
}
}
8
Strengthening Specifications
class Cell {
int v
void add(Cell c)
requires c != null
ensures v == old(v) + old(c.v)
ensures c.v == old(c.v)
{ v = v + c.v }
}
void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
?
c1.add(c2)
assert c1.v == 3
assert c2.v == 2
}
9
Aliasing
class Cell {
int v
void add(Cell c)
requires c != null
ensures v == old(v) + old(c.v)
ensures c.v == old(c.v)
{ v = v + c.v }
}

void client() {
Cell c1 = new Cell()
c1.v = 1
Cell 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
}

10
Challenges
Reason about Shared State
(Including Data Races)
and
Control Aliasing
11
Modular Static Verification + Shared State
foo(x)
bar(x)
13
Modular Static Verification + Shared State
foo(x)
bar(x)
?
14
Modular Static Verification + Shared State
foo(x)
bar(x)
?
15
Permissions
foo(x)
bar(x)
16
Permission Transfer
foo(x)
bar(x)
?
17
Permission Transfer
foo(x)
bar(x)
?
18
Fractional Permissions
foo(x)
bar(x)
19
Splitting Fractional Permissions
foo(x)
bar(x)
?
20
Merging Fractional Permissions
foo(x)
bar(x)
?
21
Silver: Assertion Language Basics
Accessibility predicates denote
permissions
acc(c.f)
Assertions may be heapdependent
acc(c.f) && c.f == 0
Fractional permissions
acc(c.f, ½)
Conjunction sums up permissions
(similar to ∗ in separation logic)
Write permission is exclusive
(similar to ∗ in separation logic)
acc(c.f, ½) && acc(c.f, ½)
acc(c1.f) && acc(c2.f,ε)
⇒ c1 != c2
22
Demo
23
Permission Transfer Reloaded
Idea of permission transfer generalises
− Fork-join (transfer between threads)
− Locks (transfer to/from lock invariant)
− Message passing (pass permissions)
Common operations
foo(x)
bar(x)
?
− Gain permissions
− Lose permissions
24
Silver: Inhale and Exhale Statements
Statement inhale A means
− Gain permissions required by A (e.g. acc(x.f))
− Assume logical constraints in A (e.g. x.f != 0)
Statement exhale A means
− Assert and remove permissions required by A
− Assert logical constraints in A
− Havoc locations to which all permissions were removed
(i.e. forget their values)
25
Concurrency
Examples
26
Fork-Join Concurrency (Pseudo-Java)
class Cell {
int v
void add(Cell c) {
v = v + c.v
}
void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
}
Token tk = fork c1.add(c2)
// ...
join tk
assert c1.v == 3
assert c2.v == 2
}
27
Locks and @GuardedBy Annotations (Pseudo-Java)
class SharedPair {
@GuardedBy(“this”)
int x, y
void inc(int dx, int dy) {
synchronized(this) {
x = x + dx
y = y + dy
}
}
void swap() {
int t = x
x = y
y = t
}
}

28
Lock Invariants (Pseudo-Java)
class SharedPair {
@GuardedBy(“this”, “x < y”)
int x, y
void inc(int dx, int dy) {
synchronized(this) {
assert x < y
x = x + dx
y = y + dy
assert x < y
}
}

}
29
Lock Invariants (Pseudo-Java)
class SharedPair {
@GuardedBy(“this”, “x < y”)
int x, y
void inc(int dx, int dy) {
assert dx <= dy
synchronized(this) {
assert x < y
x = x + dx
y = y + dy
assert x < y
}
}
}
30
Viper: Our Verification Infrastructure
Silver:
Front-ends
Front-end
Front-end
Silver
(IVL)
Back-ends
Front-end
− Intermediate Verification Language
− Few (but expressive) constructs
− Designed with verification and
inference in mind
Back-ends: Two verifiers;
plans to develop inference, slicer
Front-ends (proof of concept):
Automatic
prover
− Chalice (concurrency research)
− Scala (very small subset)
− Java (VerCors, U Twente)
− OpenCL (VerCors, U Twente)
31
Viper: Our Verification Infrastructure
Java
(U Twente)
Scala
Chalice
OpenCL
(U Twente)
generate
Silver AST
infer additional
specifications
Static
Analysis
verified by
Carbon
Silicon
encodes in
Boogie
queries
(Microsoft)
queries
Z3
(Microsoft)
32
Verification Condition Generation vs. Symbolic Execution
one weakest precondition
per method
Program
read by
calculates
Verifier
WPs
given to
Prover
VCG
Query prover once with full information (Carbon)
symbolically execute
every path through
each method
Program
read by
Verifier
maintains
Symbolic State σ
SE
used by
Prover
query prover at every step if
next statement is executable
σ1
σ2 σ3
σ4 σ 5
Query prover often with limited information (Silicon)
33
Outlook
Information hiding, abstraction and inheritance
Unbounded (recursive) data structures
Obligations – the dual to permissions
Specification inference
Encoding of high-level features
− Immutable data (vs. permissions)
− Lazy evaluation (vs. permissions)
− Closures/higher order functions
− Actor-based concurrency
− Fine-grained locking, lock-free algorithms
34
www.pm.inf.ethz.ch/research/viper.html
Java
(U Twente)
Scala
Chalice
OpenCL
(U Twente)
generate
Silver AST
infer additional
specifications
Static
Analysis
verified by
Carbon
Silicon
encodes in
Boogie
queries
(Microsoft)
queries
Z3
(Microsoft)
35
You shouldn’t even be
here!
36
Fork-Join Concurrency (Pseudo-Java)
class Cell {
int v
void add(Cell c) {
v = v + c.v
}
void client() {
Cell c1 = new Cell()
c1.v = 1
Cell c2 = new Cell()
c2.v = 2
}
Token tk = fork c1.add(c2)
// ...
join tk
assert c1.v == 3
assert c2.v == 2
}
37
Fork-Join Concurrency (Silver)
field v: Int
method add(this: Ref, c: Ref)
requires acc(this.v) && acc(c.v, ½)
ensures acc(this.v) && acc(c.v, ½)
ensures this.v == old(this.v) + old(c.v)
{
this.v := this.v + c.v
}
method client() {
// instantiate cells c1, c2; initialise with 1, 2
// Token tk = fork c1.add(c2)
exhale acc(c1.v) && acc(c2.v, ½)
// join tk
inhale acc(c1.v) && acc(c2.v, ½)
inhale c1.v == 1 + 2
assert c1.v == 3 && c2.v == 2
}
38
Locks and @GuardedBy Annotations (Pseudo-Java)
class SharedPair {
@GuardedBy(“this”)
int x, y
void inc(int dx, int dy) {
synchronized(this) {
x = x = dx
y = y = dy
}
}
void swap() {
int t = x
x = y
y = t
}
}

39
Locks and @GuardedBy Annotations (Silver)
field x: Int
field y: Int
define inv(this) acc(this.x) && acc(this.y)
method inc(this: Ref, dx: Int, dy: Int) {
// begin synchronize(this)
inhale inv(this)
this.x := this.x + dx
this.y := this.y + dy
// end synchronize(this)
exhale inv(this)
}
method swap(this: Ref) {
var t: Int := this.x
this.x == this.y
this.y == t
}

40
Lock Invariants (Pseudo-Java)
class SharedPair {
@GuardedBy(“this”, “x < y”)
int x, y
void inc(int dx, int dy) {
synchronized(this) {
assert x < y
x = x = dx
y = y = dy
assert x < y

}
}
}
41
Lock Invariants (Pseudo-Java)
class SharedPair {
@GuardedBy(“this”, “x < y”)
int x, y
void inc(int dx, int dy) {
assert dx <= dy
synchronized(this) {
assert x < y
x = x = dx
y = y = dy
assert x < y
}
}
}
42
Lock Invariants (Silver)
field x: Int
field y: Int
define inv(this)
acc(this.x) && acc(this.y)
&& this.x <= this.y
method inc(this: Ref, dx: Int, dy: Int)
requires dx <= dy
{
// begin synchronize(this)
inhale inv(this)
this.x := this.x + dx
this.y := this.y + dy
// end synchronize(this)
exhale inv(this)
}
43