Download - A Modular Checker for Multithreaded Programs

Transcript
Page 1: A Modular Checker for Multithreaded Programs

1

A Modular Checker for Multithreaded Programs

Cormac FlanaganHP Systems Research Center

Joint work withShaz Qadeer Sanjit A. Seshia

Page 2: A Modular Checker for Multithreaded Programs

2

Multithreaded programs

• Operating systems, databases, web servers, file systems, web browsers– Large programs, many threads

• Correctness problem:– for all inputs and interleavings, program

satisfies specification• Testing ?

– Frangipani filesystem took 1 year of testing– Linux kernel version 2.2 -> 2.4

• fine-grained locking to support multiprocessors• 2.4.* change log has 36 synchronization bug fixes

Page 3: A Modular Checker for Multithreaded Programs

3

Verifying multithreaded programs

• Shared-memory• Many threads• Many procedures• Many synchronization

idioms– locks (mutex, reader-writer)– semaphores (binary, counting)– changes in locking discipline– interrupt levels

Ashcroft 75Owicki-Gries 76Lamport 77Jones 83...

• Many lines of code• Many language features

Sequential checkers:...Extended Static Checking Dijkstra’s weakest precond. Automatic theorem proving...

– dynamic creation heap objects, unbounded # objs

– pointers, pointer chasing, pointer smashing, ...

– aliasing, arrays, arithmetic– classes, method, inheritance, overriding, ...

Page 4: A Modular Checker for Multithreaded Programs

4

Contribution

• New verification methodology for MT programs– thread-modular reasoning– procedure-modular reasoning

• novel procedure specs. that respect module boundaries

– generalization of Jones’ rely-guarantee method• Calvin

– implements our methodology– automatic checker for multithreaded Java

programs– leverages sequential checking technology (ESC)

Page 5: A Modular Checker for Multithreaded Programs

5

Simple multithreaded program

Thread 1:

acquire( )x := x + 1assert x > 0release( )

Thread 2:

acquire( )x := 0release( )

Main module: int x := 0

release( ) { m := 0}

int m := 0 // m = 0 => lock is not held // m = tid => lock held by thread tid

// tid is id of current thread (non-zero int)acquire( ) { int t := tid while (t != 0) CAS(m,0,t)}

Mutex module:

if (m = 0) then m,t := t,m

Page 6: A Modular Checker for Multithreaded Programs

6

Problems

1. Many threads use thread-modular (assume-guarantee)

reasoning

Page 7: A Modular Checker for Multithreaded Programs

7

Other threads

int t := 1

while (t != 0) CAS(m,0,t) x := x + 1 assert x > 0 m := 0

*

*

*

*

*

*

Env assumptionA1* int t := 1A1*while (t != 0) A1* CAS(m,0,t) A1* x := x + 1A1* assert x > 0A1* m := 0

Simplify A1 int t := 1A1

while (t != 0) A1

CAS(m,0,t) A1 x := x + 1A1 assert x > 0A1 m := 0

Thread 1

acquire()

x := x + 1

assert x > 0

release()

Inline body

int t := 1

while (t != 0)

CAS(m,0,t)

x := x + 1

assert x > 0

m := 0

Invariant I m = 0 x >= 0

Env. assumption Atid I I’ m = tid m’ = m x’ = xm,x

• Check using ESC

• Also check actions of Thread1 satisfies A2

• Similar checks for Thread2

Program is OK

Page 8: A Modular Checker for Multithreaded Programs

8

Calvin version 1

• Verifies multithreaded Java programs• Inlines procedures• Thread-modular reasoning

– requires environment assumption– reduces correctness of MT program to

correctness of sequential programs• Leverages Extended Static Checker for Java

– generates VC for sequential programs– uses automatic theorem prover to check VC

Page 9: A Modular Checker for Multithreaded Programs

9

The Apprentice Challenge

• Proposed by Moore and Porter– 50 lines of Java code– requires reasoning about many language

features• pointers, aliasing, arithmetic, infinite state• dynamic allocation of new objects & threads

• ACL2: 1 week• Calvin: 1 afternoon, 6 annotations

Page 10: A Modular Checker for Multithreaded Programs

10

Problems

1. Many threads use thread-modular (assume-guarantee)

reasoning

2. Many procedures use procedure-modular reasoning

Page 11: A Modular Checker for Multithreaded Programs

11

What are the specifications?

Thread 1:

acquire( )x := x + 1assert x > 0release( )

Thread 2:

acquire( )x := 0release( )

Main module: int x := 0

acquire( ) { int t := tid while (t != 0) CAS(m,0,t)}

release( ) { m := 0}

Mutex module: int m := 0

spec. for acquire( ) spec. for release( )

Page 12: A Modular Checker for Multithreaded Programs

12

Procedure specification (Jones)

procedurebody

precondition

postcondition

environmentassumption

guarantee

Page 13: A Modular Checker for Multithreaded Programs

13

Simple multithreaded program

Thread 1:

acquire( )x := x + 1assert x > 0release( )

Thread 2:

acquire( )x := 0release( )

Main module: int x := 0

acquire( ) { int t := tid while (t != 0) CAS(m,0,t)}

release( ) { m := 0}

Mutex module: int m := 0 precondition: Ienv_assumption: I I’ m = tid m’ = m x’ = xm,x

guarantee: I I’ m != 0 m’ = mm postcondition: m = tid x >= 0

Page 14: A Modular Checker for Multithreaded Programs

14

Procedure specifications (Calvin)

procedurebody

precondition

postcondition

environmentassumption

guarantee(action)

abstraction(program)

Page 15: A Modular Checker for Multithreaded Programs

15

Simple multithreaded program

Thread 1:

acquire( )x := x + 1assert x > 0release( )

Thread 2:

acquire( )x := 0release( )

Main module: int x := 0

acquire( ) { int t := tid while (t != 0) CAS(m,0,t)}

release( ) { m := 0}

Mutex module: int m := 0 env_assumption: true abstraction: skip* m = 0 m’ = tidm

skip* env_assumption: true abstraction: m’ = 0m

Page 16: A Modular Checker for Multithreaded Programs

16

Other threads

skip*

m=0m’=tidm skip* x := x + 1 assert x > 0 m’ = 0m

*

*

*

*

*

*

Env assumptionA1* skip*A1*m=0m’=tidm

A1*skip* A1* x := x + 1A1* assert x > 0A1* m’ = 0m

Simplify A1

m=0m’=tidm A1

x := x + 1A1 assert x > 0A1 m’ = 0m

Thread 1

acquire()

x := x + 1

assert x > 0

release()

Inline spec

skip*

m=0m’=tidm

skip*

x := x + 1

assert x > 0

m’ = 0m

Invariant I m = 0 x >= 0

Env. assumption Atid I I’ m = tid m’ = m x’ = xm,x

• Check using ESC

• Theorem prover for additional checks

• Ditto for Thread2

Program is OK

Page 17: A Modular Checker for Multithreaded Programs

17

Verifying Mutex module

Implementation:acquire( ) { int t := tid while (t != 0) { CAS(m,0,t) }}

Implementation is simulated by abstractionwith respect to environment assumption

env_assumption: trueabstraction: skip* m = 0 m’ = tidm

skip*

Page 18: A Modular Checker for Multithreaded Programs

18

Simulation WitnessAbstraction:Implemetation:

m!=tid

m=tid

int t := tid

t != 0

end

CAS(m,0,t)yes

no

skip

skip

m==0 m’==tidm

m!=0

m=0

Page 19: A Modular Checker for Multithreaded Programs

19

Calvin version 2

• Verifies multithreaded Java programs• Thread-modular reasoning• Procedure-modular reasoning

– novel procedure specification mechanism• specifications respect module boundaries

– check procedure body is simulated by abstraction– use procedure abstraction at call site

• Reduces to correctness of sequential program– leverage ESC

Page 20: A Modular Checker for Multithreaded Programs

20

Producer-consumer

Mutex

Queue

Producer-consumer Producer || Consumer

increasingintegers

checkincreasing

acquire( ) { ...}

release( ) { ... }

spec spec

put(int n) int get()spec spec

Page 21: A Modular Checker for Multithreaded Programs

21

Real multithreaded programs• java.util.Vector

– 400 lines of code– 2 environment assumptions

• specify locking discipline

– Calvin reported 1 race condition

• Mercator web crawler– uses reader-writer locks – specified and verified 4 locking primitives

• acquire_read(), release_read(), acquire_write(), release_write()

– checked 1500 LOC that uses reader-writer locks– verified absence of races on many data

structures

Page 22: A Modular Checker for Multithreaded Programs

22

Daisy file system• Multithreaded

– synchronization as in high-performance FS• Verifiable file system

– small, 1500 LOC– straightforward data structures

• Functional– can mount as NFS partition

• Verified absence of race conditions• Verified specifications of many procedures

– ialloc is correct– create is atomic

Page 23: A Modular Checker for Multithreaded Programs

23

Conclusion

• Checking multithreaded programs requires scalable and automated tools

interactive theorem provers:

PVS, ACL2, ...

model checkers:JPF, Bandera,

SPIN, ...

Calvin

Automation

Sca

lab

ility

Note: graph is not to scale