71
A Statically Verifiable Programming Model for Concurrent Object- Oriented Programs Bart Jacobs 1 (≠ Prof. B. P. F. Jacobs, R.U.Nijmegen, The Netherlands) Joint work with Jan Smans 1 , Frank Piessens 1 , Wolfram Schulte 2 , Rustan Leino 2 1 K.U.Leuven, Belgium 2 Microsoft Research, Redmond, WA, USA

A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Embed Size (px)

DESCRIPTION

A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs. Bart Jacobs 1 (≠ Prof. B. P. F. Jacobs, R.U.Nijmegen, The Netherlands) Joint work with Jan Smans 1 , Frank Piessens 1 , Wolfram Schulte 2 , Rustan Leino 2 1 K.U.Leuven, Belgium - PowerPoint PPT Presentation

Citation preview

Page 1: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Bart Jacobs1 (≠ Prof. B. P. F. Jacobs, R.U.Nijmegen, The Netherlands)

Joint work with Jan Smans1, Frank Piessens1, Wolfram Schulte2 , Rustan Leino2

1 K.U.Leuven, Belgium

2 Microsoft Research, Redmond, WA, USA

Page 2: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 3: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

The Problem

Goal: Delivering correct concurrent Java programs

Problem: It’s hard to reason about such programs due to the non-local nature of data races, deadlocks, and object

aliasing

Proposed solution: A programming regime (or programming model)

that prevents data races and deadlocks, and enables local reasoning in the presence of object aliasing.

An annotation syntax and verification approach that enables modular static verification of compliance with the

programming model.

Page 4: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 5: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Data Races

class Account { int balance; }

Account act = …;

int b0 = act.balance;

act.balance += 50;

int b1 = act.balance;

b1 == b0 + 50? Not necessarily!

Page 6: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Data Races

class Account { int balance; }

Account act = …; int b0, b1;

synchronized (act) {

b0 = act.balance;

act.balance += 50;

b1 = act.balance;

}

b1 == b0 + 50? Not necessarily!

Page 7: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Data Races

class Account { int balance; }

Account act = …; int b0, b1;

synchronized (act) {

b0 = act.balance;

act.balance += 50;

b1 = act.balance;

}

b1 == b0 + 50? Not necessarily!

In Java, it’s not sound to reason sequentially about sequential code

due to the possibility of data races.

Page 8: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Access sets Per-thread access set t.A

x = o.f; or o.f = x; requires o in t.A

Always: t1 != t2 ==> t1.A and t2.A disjoint

Object can move between access sets only via proper synchronization

Page 9: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Access sets x := new C; implies x in t.A’

entering synchronized (o) implies o in t.A’

exiting synchronized (o) implies o not in t.A’

Page 10: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Access sets x := new C; implies x in t.A’

entering synchronized (o) implies o in t.A’

exiting synchronized (o) implies o not in t.A’

But: races between creating thread and locking thread?

Page 11: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races:Shared and unshared objects x := new C; implies x is unshared’

attempting synchronized (o) requires x is shared

programmer indicates share o; requires o in t.A and o is unshared implies o is not in t.A’ and o is shared’

shared objects never become unshared again

Property: If a shared object o is not locked by any thread, then it is not in any thread’s access set.

Page 12: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races

// thread 1:

x := new C;

x.f := 5;

share x;

// start thread 2

// thread 2:

synchronized (x) {

int n := x.f;

}

t1.Ashared

Page 13: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races

// thread 1:

x := new C;

x.f := 5;

share x;

// start thread 2

// thread 2:

synchronized (x) {

int n := x.f;

}

t1.Asharedx

Page 14: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races

// thread 1:

x := new C;

x.f := 5;

share x;

// start thread 2

// thread 2:

synchronized (x) {

int n := x.f;

}

t1.Asharedx

Page 15: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races

// thread 1:

x := new C;

x.f := 5;

share x;

// start thread 2

// thread 2:

synchronized (x) {

int n := x.f;

}

t1.Asharedx

Page 16: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races

// thread 1:

x := new C;

x.f := 5;

share x;

// start thread 2

// thread 2:

synchronized (x) {

int n := x.f;

}

t2.A

sharedx

t1.A

Page 17: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races

// thread 1:

x := new C;

x.f := 5;

share x;

// start thread 2

// thread 2:

synchronized (x) {

int n := x.f;

}

t2.A

sharedx

t1.A

Page 18: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races

// thread 1:

x := new C;

x.f := 5;

share x;

// start thread 2

// thread 2:

synchronized (x) {

int n := x.f;

}

t2.A

sharedx

t1.A

Page 19: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races

// thread 1:

x := new C;

x.f := 5;

share x;

// start thread 2

// thread 2:

synchronized (x) {

int n := x.f;

}

t2.A

sharedx

t1.A

Page 20: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Thread creation

new Thread(r).start() requires r in t.A implies r not in t.A’

in new thread: r in t.A

Page 21: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing Data Races: Lock Re-entry Causes difficulties for method effect framing

We disallow it

Page 22: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races:Modular Static Verification Annotations required:

Share commands Method contracts

requires/ensures o is in tid.A (tid = current thread) requires/ensures o is unshared/shared requires/ensures o is not in tid.lockset/tid.lockset is empty

Field modifier: shared

Verification approach: Verification condition generation On entry to synchronized block:

foreach (o.f where o not in t.A) { o.f := random; } Method effect framing: required access sets

Page 23: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

Page 24: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

main.Ashared

main

Page 25: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

main

Page 26: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

main

Page 27: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1

main

Page 28: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1

main

Page 29: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1

s1.A

main

s1

Page 30: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1

s2

s1.A

main

s1

Page 31: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1

s2

s1.A

main

s1

Page 32: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1 s2

s1.As2.A

s1s2

Page 33: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1 s2

s1.As2.A

s1s2

Page 34: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1 s2

s1.As2.A

s1

s2

Page 35: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1 s2

s1.As2.A

s2

Page 36: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1 s2

s1.As2.A

s2

Page 37: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1 s2

s1.As2.A

s2

Page 38: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing data races: Exampleclass Counter {

int count;

}

class Session implements Runnable {

shared Counter counter;

public void run()

requires this in tid.A;

requires tid.lockset is empty;

{

synchronized (counter) {

counter.count++;

}

}

}

Counter counter = new Counter();

share counter;

Session session1 = new Session();

session1.counter = counter;

new Thread(session1).start();

Session session2 = new Session();

session2.counter = counter;

new Thread(session2).start();

c

main.Ashared

s1 s2

s1.As2.A

Page 39: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 40: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing deadlocks

Deadlock = cycle of threads each waiting for the next to release a lock

Proposed solution: Programmer constructs partially ordered set of lock levels

using l := between({ll1,...,lln},{lu1,...,lum}); annotation Assigns a lock level to each shared object A thread may attempt to acquire an object’s lock only if the object

is below the objects whose lock it already holds

Page 41: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Preventing deadlocks: exampleclass Fork {}

class Philosopher implements Runnable {

shared Fork fa, fb;

Philosopher(Fork fa, Fork fb) requires fa.locklevel < fb.locklevel;

{ this.fa = fa; this.fb = fb; }

public void run() requires this in tid.A and lockset is empty;

{ synchronized (fb) { synchronized (fa) { /* eat */ } } }

}

Fork f1 = new Fork(); locklevel l1 = between({},{}); share f1 at l1;

Fork f2 = new Fork(); locklevel l2 = between({l1},{}); share f2 at l2;

Fork f3 = new Fork(); locklevel l3 = between({l2},{}); share f3 at l3;

new Thread(new Philosopher(f1, f2)).start();

new Thread(new Philosopher(f2, f3)).start();

new Thread(new Philosopher(f1, f3)).start();

Page 42: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 43: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Rep Objects Objects often use auxiliary objects to help represent their

state e.g. an ArrayList uses an array object

We wish to protect the array object against data races using the lock of the ArrayList object

Proposed solution: use Spec#’s ownership system Fields may be marked with rep modifier The objects pointed to by o’s rep fields are its rep objects An object may be packed or unpacked When an object is in the packed state, it owns its rep objects A thread can gain access to an owned object by locking the

owner and then unpacking the owner

Page 44: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Ownership system

When packing an object o, using a pack o; annotation, o’s rep objects are removed from tid.A

When unpacking o, using an unpack o; annotation, o’s rep objects are added to tid.A

Page 45: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

Page 46: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

t.Ashared

Page 47: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

bl

t.Ashared

Page 48: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 49: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 50: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 51: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 52: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 53: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 54: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 55: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 56: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 57: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 58: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

bl

Ownership system: Exampleclass BoundedList {

rep Object[] elements;

int count;

BoundedList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

}

BoundedList bl = new BoundedList();

share bl;

synchronized (bl) {

bl.add(null);

}

es

t.Ashared

Page 59: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 60: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Object invariantsclass Account { int balance;

Account() ensures this in tid.A; {

} void deposit(int amount) requires this in tid.A && 0 <= amount; ensures this in tid.A; {

balance += amount;

}}

Account a = new Account();share a;…synchronized (a) { assert 0 <= a.balance; // does not verify}

Page 61: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Object invariantsclass Account { int balance; invariant 0 <= balance; Account() ensures this in tid.A && this is packed; { pack this; } void deposit(int amount) requires this in tid.A && this is packed && 0 <= amount; ensures this in tid.A && this is packed; { unpack this; balance += amount; pack this; }}

Account a = new Account();share a;…synchronized (a) { assert 0 <= a.balance; // verifies!}

Page 62: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 63: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Immutable objectsclass BoundedList {

rep Object[] elements;

int count;

ArrayList(int capacity)

ensures this is in tid.A and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

Object get(int index)

requires this is in tid.A and this is packed;

ensures this is in tid.A and this is packed;

{

unpack this; Object v = elements[index]; pack this;

return v;

}

}

class RsaServer implements Runnable {

shared BoundedList primes;

RsaServer(BoundedList primes)

requires primes is shared;

ensures this is in tid.A and this is packed;

{ this.primes = primes; pack this; }

public void run()

requires lockset is empty;

requires this is in tid.A and this is packed;

{

synchronized (primes) {

/* perform RSA operations */

… int p = primes[…]; …

}

}

}

BoundedList primes = new BoundedList();

fillWithPrimes(primes);

share primes;

new Thread(new RsaServer(primes)).start();

new Thread(new RsaServer(primes)).start();

Page 64: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Immutable objectsclass BoundedList {

rep Object[] elements;

int count;

ArrayList(int capacity)

ensures this is in tid.W and this is packed;

{

elements = new Object[capacity];

pack this;

}

void add(Object value)

requires this is in tid.W and this is packed;

ensures this is in tid.W and this is packed;

{

unpack this;

elements[count++] = value;

pack this;

}

Object get(int index)

requires this is in tid.R and this is packed;

{

read (this) { return elements[index]; }

}

}

class RsaServer implements Runnable {

shared_immutable BoundedList primes;

RsaServer(BoundedList primes)

requires primes is shared_immutable;

ensures this is in tid.W and this is packed;

{ this.primes = primes; pack this; }

public void run()

requires lockset is empty;

requires this is in tid.W and this is packed;

{

/* perform RSA operations */

… int p = primes[…]; …

}

}

BoundedList primes = new BoundedList();

fillWithPrimes(primes);

share_immutable primes;

new Thread(new RsaServer(primes)).start();

new Thread(new RsaServer(primes)).start();

Page 65: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 66: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Related Work

ESC/Modula3, ESC/Java, RCC/Java Calvin/R Safe Concurrent Java Atomicity JML Separation logic Monitor invariants Assertional proof system for monitors Dynamic tools: Eraser, RaceTrack Software Transactional Memory

Page 67: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 68: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Future work

Integrating support for module invariants and rely-guarantee conditions

Verification of non-blocking algorithms (volatile, CAS)

Verification of additional liveness properties

Page 69: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Outline of the Talk

Progressive refinement of the approach: Absence of data races Absence of deadlocks Ownership Object invariants Immutable objects

Related work, future work, conclusion

Page 70: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Conclusion

Programming model and static verification approach

that prevents data races and deadlocks

and supports local reasoning in the presence of object aliasing, using an ownership system.

Has support for object invariants immutable objects

Page 71: A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

A Statically Verifiable Programming Model for Concurrent Object-Oriented Programs

Bart Jacobs1

Joint work with Jan Smans1, Frank Piessens1, Wolfram Schulte2 , Rustan Leino2

1 K.U.Leuven, Belgium

2 Microsoft Research, Redmond, WA, USA