Download - Synergy: A New Algorithm for Property Checking Bhargav S. Gulavani (IIT Bombay) Yamini Kannan (Microsoft Research India) Thomas A. Henzinger (EPFL) Aditya.

Transcript

Synergy: A New Algorithm for Property Checking

Bhargav S. Gulavani (IIT Bombay)Yamini Kannan (Microsoft Research India)Thomas A. Henzinger (EPFL)Aditya V. Nori (Microsoft Research India)Sriram K. Rajamani (Microsoft Research India)

Problem statement

• Check if a program satisfies a given safety property:– API usage rules– Protocols on objects

• Interesting programs have infinite state spaces ranging over infinite domains– This problem in general is undecidable

Two approaches to property checking

• Testing: find inputs and executions that demonstrate effectively violations of a property

• Verification: find a proof that all executions of the program satisfy a property

Tests: presence of bugs void foo(int a) {0: i = 0;1: c = 0;2: while (i < 1000) {3: c = c + i;4: i = i + 1;

}5: assume (a <= 0);6: assert (false); }

0

65

32

4

1

×

×

× ×××

× × ××

×× ××

×

×

(a = -5)

Proofs: absence of bugs

void foo(int y1, int y2) {0: state = 1;1: if (y1) {2: x0 = x0 + 1;

} else {3: x0 = x0 – 1;

}4: if (y2) {5: x1 = x1 + 1;

} else {6: x1 = x1 – 1;

}7: assert (state == 1); }

O: state=11: state=1

2: state=1 3: state=14: state=1

5: state=1 6: state=17: state=1

Error

exponential number of

tests required

linear proof exists!

Key insights

• Testing works when errors are easy to find and is inefficient for finding proofs

• Verification works when proofs are easy to find and is inefficient for finding errors

Questions

• Can we combine “systematically” testing with verification?

• How does one generate/direct test cases?– Can abstraction help?

• Given a spurious abstract error trace, how does one perform refinement?– Can testing help?

Solution: Synergy• Combines under- and over-approximation

reasoning (testing and verification) of programs.

• Unifies several disparate existing algorithms in the literature:a) Counterexample driven refinement approaches for

verification (SLAM, BLAST)b) Directed testing approaches (DART)c) Partition refinement algorithms (Lee-Yannakakis,

Paige-Tarjan)

Synergy – sketch

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

Example void foo(int y) {1: do {2: lock(); 3: x = y;4: if (*) {5: unlock(); 6: y = y + 1; }7: } while (x != y);

8: unlock();

}

Does this program obey the locking rule?

Example void foo(int y) {1: do {2: lock(); 3: x = y;4: if (*) {5: unlock(); 6: y = y + 1; }7: } while (x != y);

8: unlock();

}

no

Example void foo(int y) {1: do {2: lock(); 3: x = y;4: if (*) {5: unlock(); 6: y = y + 1; }7: } while (x != y);

8: unlock();

}Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

Exampley = 1

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

void foo(int y) {1: do {2: lock(); 3: x = y;4: if (*) {5: unlock(); 6: y = y + 1; }7: } while (x != y);

8: unlock();

}

01234

56

789

×

× ×

× ×

× ×

× ×

×

×

× ×

×

Example

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

void foo(int y) {1: do {2: lock(); 3: x = y;4: if (*) {5: unlock(); 6: y = y + 1; }7: } while (x != y);

8: unlock();

}

01234

56

789

×

× ×

× ×

× ×

× ×

×

×

× ×

×

y = 1

τ=(0,1,2,3,4,7,8,9)frontier

Example

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

void foo(int y) {1: do {2: lock(); 3: x = y;4: if (*) {5: unlock(); 6: y = y + 1; }7: } while (x != y);

8: unlock();

}

01234

56

78⋀¬p

9

×

× ×

× ×

× ×

× ×

×

×

× ×

×8⋀p×

split <pc=8> into two regions wrt p= (lock.state != L)

Example

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

void foo(int y) {1: do {2: lock(); 3: x = y;4: if (*) {5: unlock(); 6: y = y + 1; }7: } while (x != y);

8: unlock();

}

01234

56

78⋀¬p

9

×

× ×

× ×

× ×

× ×

×

×

× ×

×8⋀p×

τ=(0,1,2,3,4,7,<8,p>,9)frontier

Correct, the program is void foo(int y) {1: do {2: lock(); 3: x = y;4: if (*) {5: unlock(); 6: y = y + 1; }7: } while (x != y);

8: unlock();

}

0123

4⋀¬s5⋀¬s6⋀¬r

9

×

× ×

× ×

× ×

××

×

×

7⋀¬q×

8⋀¬p×

4⋀s5⋀s6⋀r7⋀q

8⋀p×

Example • 0

• 6• 5

• 3• 2

• 4

• 1

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

void foo(int a) {0: i = 0;1: c = 0;2: while (i < 1000) {3: c = c + i;4: i = i + 1; }5: if (a <= 0)6: error(); }

Example • 0

• 6• 5

• 3• 2

• 4

• 1

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

void foo(int a) {0: i = 0;1: c = 0;2: while (i < 1000) {3: c = c + i;4: i = i + 1; }5: if (a <= 0)6: error(); }

× ×

× ×

× ×

× ×

× ×

× ×

a = 45

Example • 0

• 6• 5

• 3• 2

• 4

• 1

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

void foo(int a) {0: i = 0;1: c = 0;2: while (i < 1000) {3: c = c + i;4: i = i + 1; }5: if (a <= 0)6: error(); }

× ×

× ×

× ×

× ×

× ×

× ×

τ=(0,1,2,(3,4,2)1000,5,6)frontier

Example • 0

• 6• 5

• 3• 2

• 4

• 1

Can extend test beyond frontier?

Refine proof

Construct random testsConstruct initial proof

Input:Program P

Property ψ

Test succeeded? Bug!

Proof succeeded?

τ = error path in failed proof f = frontier of error path

yes

no

yes

no

Proof! yes

no

void foo(int a) {0: i = 0;1: c = 0;2: while (i < 1000) {3: c = c + i;4: i = i + 1; }5: if (a <= 0)6: error(); }

× ×

× ×

× ×

× ×

× ×

× ×

×

a = -5

Soundness and Termination

• Theorem: Suppose we run Synergy on any program P= ⟨Σ, σI, →⟩ and property ψ– If Synergy returns (“pass”, ≃), then the abstract program P≃ = ⟨Σ≃, σI≃, →≃⟩ simulates P, and thus is a proof that P does not reach ψ– If Synergy returns (“fail”, t), then t is an error trace

• Theorem: If P= ⟨Σ, σI, →⟩ has a finite bisimulation quotient, then Synergy terminates

• Theorem: Synergy terminates in strictly more cases than the Lee-Yannakakis algorithm

Implementation

Synergy is the core engine of a property checking tool called Yogi– Checks x86 binaries against safety

properties – Implemented in F# over MSR program

analysis infrastructure

Experimental Evaluationprogram (correct) Yogi SLAM LY

iterations time (secs) iterations time (secs) iterations time (secs)

test1.c 9 3.92 4 1.7 * *

test2.c 6 7.88 4 1.55 * *

test3.c 5 2.19 13 8.03 * *

test4.c 2 2.67 12 3.52 22 8.08

test5.c 2 1.28 1 0.9 * *

test6.c 1 1.45 1 1.27 1 1.75

test7.c 6 2.11 4 1.11 6 2.06

test8.c 2 1.28 2 1.19 * *

test9.c 3 1.39 1 1.19 3 1.42

test10.c 3 1.52 1 1.25 3 1.52

test11.c 2 1.30 13 5.03 * *

test12.c 7 2.30 13 10.25 * *

test13.c 12 3.17 2 1.31 12 3.18

test14.c 1 1.06 12 3.45 * *

test15 3 5.98 * * 3 5.65

test16.c 3 9.2 * * * *

test17.c 2 2.28 * * * *

test18.c 24 13.41 * * * *

test19.c 24 10.84 * * * *

test20.c 22 9.42 * * * *

The Future• Only integer domains with linear arithmetic

have been considered– Incorporate more expressive domains– New techniques for discovering predicates– Interprocedural analysis

• Check properties of device drivers• A more comprehensive analysis of combining

over– and under-approximations of programs