Aditya V. Nori, Sriram K. Rajamani Microsoft Research India  An industrial strength program verifier  Idea: Synergize verification and testing  Synergy [FSE ’06], Dash.

Download Report

Transcript Aditya V. Nori, Sriram K. Rajamani Microsoft Research India  An industrial strength program verifier  Idea: Synergize verification and testing  Synergy [FSE ’06], Dash.

Aditya V. Nori, Sriram K. Rajamani
Microsoft Research India

An industrial strength program verifier

Idea: Synergize verification and testing

Synergy [FSE ’06], Dash [ISSTA ‘08], SMASH [POPL
‘10] algorithms to perform scalable analysis

Engineered a number of optimizations for scalability

Integrated with Microsoft’s Static Driver Verifier (SDV)
toolkit and used internally

Share our experiences in making Yogi robust, scalable and
industrial strength

Several of the implemented optimizations are folklore
 Very difficult to design tools that are bug free ⇒ evaluating
optimizations is hard!
 Our empirical evaluation gives tool builders information about
what gains can be realistically expected from optimizations

Vanilla implementation of algorithms:
 (flpydisk, CancelSpinLock) took 2 hours

Algorithms + engineering + optimizations:
 (flpydisk, CancelSpinLock) took less than 1 second!

Overview of Yogi

Overview of optimizations

Evaluation setup

Empirical Results

Summary
Question
void foo()
{
*p = 4;
*q = 5;
if (condition)
error();
}
Is error() unreachable for all possible inputs?
Verification: can prove the absence of bugs,
but can result in false errors
Testing: finds bugs, but can’t prove their
absence
Input:
Program P
Property ψ
Construct initial abstraction
Construct random tests
Test
succeeded?
yes
Bug!
no
Abstraction
succeeded?
no
τ = error path in abstraction
f = frontier of error path
yes
Can extend
test beyond
frontier?
no
Refine abstraction
yes
Proof!
Input:
Program P
Property ψ
×
y=1
1
Construct initial abstraction
Construct random tests
Test
succeeded?
××
yes
Bug!
no
Abstraction
succeeded?
no
τ = error path in abstraction
f = frontier of error path
yes
0
yes
Proof!
void foo(int y)
{
0: int x, lock = 0;
1: do {
2:
lock = 1;
3:
x = y;
4:
if (*) {
5:
lock = 0;
6:
y = y+1;
}
7: } while (x != y);
8: if (lock != 1)
9:
error();
10:
}
Can extend
test beyond
frontier?
2
××
3
××
4
××
×
×
5
7
××
6
×
8
no
Refine abstraction
9
Symbolic execution +
Theorem proving
×
10
Input:
Program P
Property ψ
×
1
Construct initial abstraction
Construct random tests
Test
succeeded?
××
yes
Bug!
no
Abstraction
succeeded?
no
τ = error path in abstraction
f = frontier of error path
yes
Can extend
test beyond
frontier?
0
yes
Proof!
void foo(int y)
{
0: int x, lock = 0;
1: do {
2:
lock = 1;
3:
x = y;
4:
if (*) {
5:
lock = 0;
6:
y = y+1;
}
7: } while (x != y);
8: if (lock != 1)
9:
error();
10:
}
2
××
3
××
4
××
×
×
5
7
××
6
8:¬ρ
×
8:ρ
×
no
9
Refine abstraction
×
10
Input:
Program P
Property ψ
×
× ×1
Construct initial abstraction
Construct random tests
Test
succeeded?
yes
Bug!
no
Abstraction
succeeded?
no
τ = error path in abstraction
f = frontier of error path
0
yes
Proof!
void foo(int y)
{
0: int x, lock = 0;
1: do {
2:
lock = 1;
3:
x = y;
4:
if (*) {
5:
lock = 0;
6:
y = y+1;
}
7: } while (x != y);
8: if (lock != 1)
9:
error();
10:
}
× ×2
×× 3
4:s
×4:¬s
×
5:s
×5:¬s
6:r
6:¬r
yes
Can extend
test beyond
frontier?
no
Refine abstraction
×
7:q
×7:¬q
×
8:p
8:¬p
×
10
9

Initial abstraction from property predicates

Relevance heuristics for predicate abstraction
 Suitable predicates (SP)
 Control dependence predicates (CD)

Interprocedural analysis
 Global modification analysis
 Summaries for procedures

Thresholds for tests

Fine tuning environment models

Benchmarks:
 30 WDM drivers and 83 properties (2490 runs)
 Anecdotal belief: most bugs in the tools are usually
caught with this test suite

Presentation methodology:
 Group optimizations logically such that related
optimizations are in the same group
 Total time taken, total number of defects found for
every possible choice of enabling/disabling each
optimization in the group
state {
enum {Locked = 0, Unlocked = 1}
state = Unlocked;
}
KeAcquireCancelSpinlock.Entry
{
if (state != Locked) {
state = Locked;
}
else
abort;
}
KeReleaseCancelSpinlock.Entry
{
if (state == Locked) {
state = Unlocked;
}
else
abort;
}
0
𝑇
1
𝑇
0
(𝑠𝑡𝑎𝑡𝑒 = 𝐿𝑜𝑐𝑘𝑒𝑑)
0
(𝑠𝑡𝑎𝑡𝑒 ≠ 𝐿𝑜𝑐𝑘𝑒𝑑)
1
(𝑠𝑡𝑎𝑡𝑒 = 𝐿𝑜𝑐𝑘𝑒𝑑)
1
(𝑠𝑡𝑎𝑡𝑒 ≠ 𝐿𝑜𝑐𝑘𝑒𝑑)
Abstraction
using SLIC
predicates
Total time
(minutes)
#defects
#timeouts
yes
2160
241
77
no
2580
241
86
16%
Irrelevant?
A

𝑇
𝜌 = 𝑊𝑃 𝑎𝑠𝑠𝑢𝑚𝑒 𝜙 , 𝛿 = 𝜙 ∧ 𝛿
B
C
𝑇
𝑇
𝑎𝑠𝑠𝑢𝑚𝑒(𝜙)

Avoid irrelevant conjuncts
D
𝛿
 𝜌 = 𝛿?
A
𝑇
B
𝑇
C
¬𝜌
C
𝜌
𝑎𝑠𝑠𝑢𝑚𝑒(𝜙)
D
𝛿

Abstract assume statements that are not
potentially relevant by skip statements

If Yogi proves that the program satisfies
property, we are done.

Otherwise, validate the error trace and refine
the abstraction by putting back assume
statements, if the error trace is spurious
int x;
void foo() {
bool protect = true;
…
if (x > 0)
protect = false;
…
if (protect)
KeAcquireCancelSpinLock();
for (i = 0; i < 1000; i++) {
a[i] = readByte(i);
}
if (protect)
KeReleaseCancelSpinLock();
A
𝑇
B
C
𝑇
𝑇
𝑎𝑠𝑠𝑢𝑚𝑒(𝑖 > 1000)
D
𝑠𝑡𝑎𝑡𝑒 = 𝑙𝑜𝑐𝑘𝑒𝑑
𝜌 = state = Locked ∧ (𝑖 > 1000)
A
𝑇
B
𝑇
C
¬𝜌
C
𝜌
𝑎𝑠𝑠𝑢𝑚𝑒(𝑖 > 1000)
}
D
𝑠𝑡𝑎𝑡𝑒 = 𝑙𝑜𝑐𝑘𝑒𝑑
int x;
void foo() {
bool protect = true;
…
if (x > 0)
protect = false;
…
if (protect)
KeAcquireCancelSpinLock();
for (i = 0; i < 1000; i++) {
a[i] = readByte(i);
}
if (protect)
KeReleaseCancelSpinLock();
A
𝑇
B
C
𝑇
𝑇
𝑎𝑠𝑠𝑢𝑚𝑒(𝑖 > 1000)
D
𝑠𝑡𝑎𝑡𝑒 = 𝑙𝑜𝑐𝑘𝑒𝑑
𝜌 = state = Locked
A
𝑇
B
𝑇
C
¬𝜌
C
𝜌
𝑎𝑠𝑠𝑢𝑚𝑒(𝑖 > 1000)
}
D
𝑠𝑡𝑎𝑡𝑒 = 𝑙𝑜𝑐𝑘𝑒𝑑
int x;
void foo() {
bool protect = true;
…
if (x > 0)
protect = false;
…
if (protect)
KeAcquireCancelSpinLock();
for (i = 0; i < 1000; i++) {
a[i] = readByte(i);
}
if (protect)
KeReleaseCancelSpinLock();
}
SP
heuristic
CD
heuristic
Total time
(minutes)
#defects
#timeouts
yes
yes
2160
241
77
yes
no
2580
239
91
no
yes
2400
238
87
no
no
2894
235
174
10%
SP
heuristic
CD
heuristic
Total time
(minutes)
#defects
#timeouts
yes
yes
2160
241
77
yes
no
2580
239
91
no
yes
2400
238
87
no
no
2894
235
174
16%
SP
heuristic
CD
heuristic
Total time
(minutes)
#defects
#timeouts
yes
yes
2160
241
77
yes
no
2580
239
91
no
yes
2400
238
87
no
no
2894
235
174
25%

Yogi performs a compositional analysis
 𝜙1 , 𝑃, 𝜙2 : Is it possible to execute 𝑃 starting
from state 𝜙1 and reach state 𝜙2 ?

Global modification analysis

May-Must analysis (SMASH, POPL 2010)
A
𝑇
B
C
𝑇
𝑇
𝑓𝑜𝑜(… )
D
𝑠𝑡𝑎𝑡𝑒 = 𝑙𝑜𝑐𝑘𝑒𝑑
𝜙1 , 𝑓𝑜𝑜(… ), 𝜙2
A
𝑇
B
𝑇
C
¬𝜌
C
𝜌
foo(…)
D
𝑠𝑡𝑎𝑡𝑒 = 𝑙𝑜𝑐𝑘𝑒𝑑
Modification Summaries
analysis
Total time #defects
(minutes)
#timeouts
yes
yes
2160
241
77
yes
no
2760
239
109
no
yes
3180
237
134
no
no
3780
236
165
32%
Modification Summaries
analysis
Total time #defects
(minutes)
#timeouts
yes
yes
2160
241
77
yes
no
2760
239
109
no
yes
3180
237
134
no
no
3780
236
165
28%
Modification Summaries
analysis
Total time #defects
(minutes)
#timeouts
yes
yes
2160
241
77
yes
no
2760
239
109
no
yes
3180
237
134
no
no
3780
236
165
42%

Yogi relies on tests for “cheap” reachability

Long tests ⇒
 avoiding several potential reachability queries
 results in too many states and thus memory
consumption

Test thresholds: time vs. space tradeoff
Test
threshold
Total time
(minutes)
#defects
#timeouts
250
2600
236
92
500
2160
241
77
1000
2359
240
88
1500
2400
239
89
if (DestinationString)
{
DestinationString->Buffer = SourceString;
}
// DestinationString->Length should be set to the
// length of SourceString. The line below is missing
// from the original stub SDV function
DestinationString->Length = strlen(SourceString);
if (SourceString == NULL)
{
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
}
Issue type
#issues
Integers used as pointers
8
Uninitialized variables
15
Type inconsistencies
9

Described optimizations implemented in Yogi

Evaluated optimizations on the WDM test suite

Empirical data used to decide which optimizations to
include in Yogi

We believe that this detailed empirical study of
optimizations will enable tool builders to decide which
optimizations to include and how to engineer their
tools

http://research.microsoft.com/yogi