software verification with blast thomas a. henzinger, ranjit jhala, rupak majumdar, george necula,...

37
Software Software Verification with Verification with Blast Blast Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar, George Necula, Grégoire Sutre, Wes Weimer UC Berkeley

Post on 19-Dec-2015

215 views

Category:

Documents


1 download

TRANSCRIPT

Software Verification Software Verification with Blastwith Blast

Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar,George Necula, Grégoire Sutre, Wes Weimer

UC Berkeley

2

MotivationMotivation

Verification of systems codeLocking disciplinesInterface specifications

Essential for correct operationHigh rate of bugs

Temporal propertiesRequire path-sensitive analysisSwamped by false positives

Really hard to check

3

Model CheckingModel Checking

Doesn’t scale to low level implementations

Can only model check “abstractions”

Requires human intervention …

Abstract – Check – Refine LoopMicrosoft SLAM Project[Clarke et. al. 00], [Saidi 00]

4

Abstract-Check-Refine LoopAbstract-Check-Refine Loop

Abstract

Explanation

YES (Trace)

BUG

Feasible

???

Check

Refine

NO

SAFE

Seed Abstraction

Program

Abstraction

InfeasibleWhy infeasible ?

Is model unsafe ?

5

Model Checking 101Model Checking 101

ERROR STATES

Init

SYSTEM’S STATE SPACE

Keep searching successors until …Hit error states: report “bug” !Add no new successors: report “safe”Could take a long time …

6

Model Checking & AbstractionModel Checking & Abstraction

Problem: Far too many states Iterations don’t terminate !Solution: Abstract …

ERROR STATES

Init

7

ERROR STATES

Init

Model Checking & AbstractionModel Checking & Abstraction

Problem: Abstraction too coarseSolution: Refine abstraction

Make boxes smaller

8

ERROR STATES

Init

Model Checking & AbstractionModel Checking & Abstraction

Problem: Abstraction too coarseSolution: Refine abstraction

Make boxes smaller

9

Abstract Only Where RequiredAbstract Only Where Required

ERROR STATES

Abstraction is very expensive Why abstract regions that are never visited ?

Init

Reachable States

On-the-fly abstraction: driven by the search

10

Refine Only Where RequiredRefine Only Where Required

Why be precise everywhere ?Don’t refine error-free regions

ERROR STATES

Init

ERROR FREE

11

Refine Only Where RequiredRefine Only Where Required

Why be precise everywhere ?Don’t refine error-free regions

Different precision for different regions Local Refinement : driven by the search

ERROR STATES

Init

ERROR FREE

12

How to improve How to improve

Abstract only where requiredReachable state space is very sparseConstruct the abstraction on-the-fly

Use greater precision only where requiredDifferent precisions/abstractions for different regionsRefine locally

Reuse work from earlier phasesBatch-oriented ) lose work from previous runsIntegrate the three phases

Exploit control flow structure

13

ExampleExample

Q: Is Error Reachable ?

Example ( ) {1: if (*) { 7: do { got_lock = 0;8: if (*) {9: lock(); got_lock ++; }10: if (got_lock) {11: unlock(); }12: } while (*) ; }2: do { lock(); old = new;3: if (*) {4: unlock(); new ++; }5: } while ( new != old);6: unlock (); return;}

unlock() lock()

lock()

unlock()

14

Example ( ) {1: if (*) { 7: do { got_lock = 0;8: if (*) {9: lock(); got_lock ++; }10: if (got_lock) {11: unlock(); }12: } while (*) ; }2: do { lock(); old = new;3: if (*) {4: unlock(); new ++; }5: } while ( new != old);6: unlock (); return;}

Example:CFAExample:CFA1

3

lock();

old = new

2 7

[>][>]

4

5

[>]

[>]

unlock()

new++

6

[new==old]

[new!=old]

retunlock()

15

Example ( ) {1: if (*) { 7: do { got_lock = 0;8: if (*) {9: lock(); got_lock ++; }10: if (got_lock) {11: unlock(); }12: } while (*) ; }2: do { lock(); old = new;3: if (*) {4: unlock(); new ++; }5: } while ( new != old);6: unlock (); return;}

Example:CFAExample:CFA

8

10

9

12

11

7

1

3

2

4

5

6

ret

got_lock=0

[>]

[>]

lock();

got_lock++

[got_lock == 0]

[got_lock != 0]

unlock()

[>] [>]

16

Example:CFAExample:CFA

Q: Is Error Reachable ?

Example ( ) {1: if (*) { 7: do { got_lock = 0;8: if (*) {9: lock(); got_lock ++; }10: if (got_lock) {11: unlock(); }12: } while (*) ; }2: do { lock(); old = new;3: if (*) {4: unlock(); new ++; }5: } while ( new != old);6: unlock (); return;}

8

10

9

12

11

7

1

3

2

4

5

6

retunlock() lock()

lock()

unlock()

17

Step 1: SearchStep 1: Search

Set of predicates:

LOCK=0, LOCK=1

1 LOCK=0

2 LOCK=0

4 LOCK=1

6 LOCK=0

[>]

lock();

old = new

[>]

unlock()

new++

[new==old]

unlock()

8

10

9

12

11

7

1

3

2

4

5

6

ret

5 LOCK=0

3 LOCK=1

Err LOCK=0

18

Q: When can:

Step 2:Step 2: Analyze CounterexampleAnalyze Counterexample

1 LOCK=0

2 LOCK=0

3 LOCK=1

4 LOCK=1

5 LOCK=0

6 LOCK=0

Err LOCK=0

8

10

9

12

11

7

1

3

2

4

5

6

ret

n Errops

States that can = wp( >,ops)

States at node n = Rn

) check:

Rn Æ wp( >,ops) = ? ?

19

Step 2:Step 2: Analyze CounterexampleAnalyze Counterexample

1 LOCK=0

2 LOCK=0

3 LOCK=1

4 LOCK=1

5 LOCK=0

6 LOCK=0

Err LOCK=0

lock();

old = new

[>]

unlock();

new++

[new==old]

unlock()

LOCK=0

LOCK=0

LOCK=0 Æ new = old

LOCK=0 Æ new+1 = new

LOCK=1 Æ new+1 = old

LOCK=1 Æ new +1 = old

8

10

9

12

11

7

1

3

2

4

5

6

ret

Rn Æ wp (>,ops) = ? ?

20

Step 2:Step 2: Analyze CounterexampleAnalyze Counterexample

1 LOCK=0

2 LOCK=0

3 LOCK=1

4 LOCK=1

5 LOCK=0

6 LOCK=0

Err LOCK=0

lock();

old = new

[>]

unlock();

new++

[new==old]

unlock()

LOCK=0

LOCK=0

LOCK=0 Æ new = old

LOCK=0 Æ new+1 = new

LOCK=1 Æ new+1 = old

LOCK=1 Æ new +1 = old

8

10

9

12

11

7

1

3

2

4

5

6

ret

Track the predicate:

new = old

21

Step 3: Resume searchStep 3: Resume search1LOCK=0

2LOCK=0

4LOCK=1 Æ new = old

lock();

old = new

[>]

unlock()

new++

[new==old]

? 6[new!=old]

2

LOCK=0 Æ : new = old µ LOCK =0

Set of predicates:

LOCK=0, LOCK=1

New predicate:

new = old,

8

10

9

12

11

7

1

3

2

4

5

6

ret

5LOCK=0 Æ : new = old

3LOCK=1 Æ new = old

22

Step 3: Resume searchStep 3: Resume search1LOCK=0

2LOCK=0

3LOCK=1 Æ new = old

4LOCK=1 Æ new = old

5LOCK=0 Æ : new = old

? 6 2

LOCK=0 Æ : new = old

[>]

5LOCK=1 Æ new=old

6

[new==old][new!=old]

1

?unlock()

8

10

9

12

11

7

1

3

2

4

5

6

ret

Set of predicates:

LOCK=0, LOCK=1

New predicate:

new = old

retLOCK=0Æ new=old

23

Example ( ) {1: if (*) { 7: do { got_lock = 0;8: if (*) {9: lock(); got_lock ++; }10: if (got_lock) {11: unlock(); }12: } while (*) ; }2: do { lock(); old = new;3: if (*) {4: unlock(); new ++; }5: } while ( new != old);6: unlock (); return;}

Example:CFAExample:CFA

8

10

9

12

11

7

1

3

2

4

5

6

ret

got_lock=0

[>]

[>]

lock();

got_lock++

[got_lock == 0]

[got_lock != 0]

unlock()

[>] [>]

24

Step 4: Search Right BranchStep 4: Search Right Branch1 LOCK=0

[>]

2LOCK=0 7 LOCK=0

[>]

Err

8

10

9

12

11

7

1

3

2

4

5

6

ret

Set of predicates:

LOCK=0, LOCK=1

New predicate: (from trace)

got_lock = 0

25

Leaves Covered (Reuse work)Leaves Covered (Reuse work)1 LOCK=0

2LOCK=0 7 LOCK=0

222

LOCK=0 Æ …

COVERED !

Leaves covered:

Avoid repeating search when paths merge

8

10

9

12

11

7

1

3

2

4

5

6

ret

27

Reachability TreeReachability Tree1LOCK=0

2LOCK=0

3LOCK=1 Æ new = old

4LOCK=1 Æ new = old

5LOCK=0 Æ : new = old

? 6 2

5LOCK=1 Æ new=old

6 1

?

retLOCK=0Æ new=old

8

12

7

10

10

11

1211

9

LOCK=0

12

82

LOCK=0 Æ got_lock=0

LOCK=1 Æ got_lock!=0

LOCK=0 Æ got_lock=0

LOCK=0 Æ got_lock=0

?

?

28

InvariantsInvariants1LOCK=0

2LOCK=0

3LOCK=1 Æ new = old

4LOCK=1 Æ new = old

5LOCK=0 Æ : new = old

? 6 2

5LOCK=1 Æ new=old

6 1

?

retLOCK=0Æ new=old

Regions in the tree are invariants:

Invariant Inv (n) for node n =

Disjunction of all node-n regions in the tree

Inv (5) is:

LOCK=0 Æ : new = old Ç LOCK=1 Æ new=old

Inv (6) is:

LOCK=1 Æ new=old

29

Proof GenerationProof Generation1

3

2

4

5

6

ret

LOCK=0 Æ : new = oldÇ

LOCK=1 Æ new=old [new==old]

[new!=old]

Use the invariants from the tree

Verification Conditions for correctness

1. Pre ) Inv (1)

2. Inv (e) = false for error node e

3. Post (Inv (j), cjk ) ) Inv (k)

These can be formalized as in PCC

1. Inv (1) contains Pre as disjunct

2. Error node not in tree

30

Proof Generation IIProof Generation II1

3

2

4

5

6

ret

LOCK=0 Æ : new = oldÇ

LOCK=1 Æ new=old [new==old]

[new!=old]

Prove : Post ( Inv (i) , cij ) ) Inv (j)

Use the tree to break the proof:

Post(AÇ B, c) ) D Ç E

becomes:

Post (A,c) ) D and Post (B,c) ) E

Example: Post (Inv (5), new==old) ) Inv (6)

LOCK=1 Æ new=old

Post (LOCK=0 Æ : new=old, new==old) ) LOCK=1Æ new=old

Post(LOCK=1 Æ new=old, new==old) ) LOCK=1 Æ new=old

31

Proof Generation IIProof Generation II1

3

2

4

5

6

ret

LOCK=0 Æ : new = oldÇ

LOCK=1 Æ new=old [new==old]

[new!=old]

Prove : Post ( Inv (i) , cij ) ) Inv (j)

Use the tree to break the proof:

Post(AÇ B, c) ) D Ç E

becomes:

Post (A,c) ) D and Post (B,c) ) E

But these were computed in the forward search!

Example: Post (Inv (5), new==old) ) Inv (6)

LOCK=1 Æ new=old

false ) LOCK=1Æ new=old

LOCK=1 Æ new=old) LOCK=1 Æ new=old

33

BLASTBLAST

LAZY

ABSTRACTION

Berkeley Lazy Abstraction Software verification Tool10K Lines of OcamlAnalyze Linux/Windows Device Drivers

CIL

(C ! CFA)

REGION

STRUCTURE

BDD Engine

(Boolean ops)

Simplify

(Post#)

Vampyre

(focus)

Proof Gen

(PCC)

34

MPR3

CallDriver

MPRcompletion

synch

not pending returned

SKIP2

IPCCallDriver

Skip returnchild status

DC

Completerequest

returnnot Pend

PPCprop

completion

CallDriver

N/A

no propcompletion

CallDriver

start NP

returnPending

NP

MPR1

MPRcompletion

SKIP2

IPCCallDriver

CallDriver

DC

Completerequest

PPCprop

completion

CallDriver

N?A

no propcompletion

CallDriver

start P Mark Pending

IRP accessible N/A

synch

SKIP1CallDriver

SKIP1Skip

MPR2 MPR1

NP

MPR3

CallDrivernot pending returned

MPR2

synch

From the SLAM project

35

ExperimentsExperiments

Windows Drivers (IRP Spec – 22 states)

Program Lines Predicates Time Proof

floppy.c 17386 62 37 35 min

17386 93 44 21 min 60K

parport.c 61781 193 50 33 min 103K

mouclass.c 17352 57 46 1 min

cdaudio.c 17798 85 45 23 min 156K

kbfiltr.c 12131 54 40 1 min

12131 12 8 10 sec 7K

36

Experiments Experiments : Linux Locking: Linux Locking

Program Lines Predicates Time Proof

ide.c 18131 5 5 4 sec 253

aironet.c 18152 17 11 4 min

aha152x.c 17736 2 2 20 sec

tlan.c 16505 5 4 7 min 405

37

Why Abstract Lazily ?Why Abstract Lazily ?

Reach set is very sparseAbstract on-the-flyOnly the reachable regionRequires very fast post#

Exploit Control-Flow StructureFree partitioning of state spacePartition preds: different abstractionsRefine locally: don’t repeat old work

38

Problems/Future workProblems/Future work

Engineering IssuesProgram analysis Partitioning by partial evaluation

Theory of counterexample driven refinement

for all linear and branching time logics

44

“BLAST! This is why I hate flying!”- Jedi Master Obi-Wan Kenobi in Episode II: Attack of the

Clones, 2002