Synergy: A New Algorithm for Property Checking Bhargav S. Gulavani (IIT Bombay) Yamini Kannan...
-
date post
20-Dec-2015 -
Category
Documents
-
view
216 -
download
0
Transcript of Synergy: A New Algorithm for Property Checking Bhargav S. Gulavani (IIT Bombay) Yamini Kannan...
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