View
216
Download
0
Embed Size (px)
Citation preview
Lazy Abstraction
Lecture 2: Modular Analyses
Ranjit JhalaUC San Diego
With: Tom Henzinger, Rupak Majumdar, Ken McMillan, Gregoire Sutre
Program Verification by
Lazy Abstraction
Ranjit JhalaUC San Diego
Lecture 1
With: Tom Henzinger, Rupak Majumdar, Ken McMillan, Gregoire Sutre
Last lecture …Lazy Abstraction for Sequential Programs
• Predicates:– Abstract infinite program states
• Counterexample-guided Refinement:– Find predicates tailored to prog, property
1. Abstraction : Expensive Reachability Tree
2. Refinement : Find predicates, use locations Proof of unsat of TF + Interpolation
This Lecture: Modular Analyses
Procedures- Summaries
Concurrency- Thread-Context Reasoning
An example
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
Inline Calls in Reach Treemain(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1,2
Initial
2,2
4,2
3,2
4,2
3 3
4
1,4
2,4
4,4
3,4
4,4
5 5
Inline Calls in Reach Tree
1
2
1,2
Initial
2,2
4,2
3,2
4,2
3 3
4
1,4
2,4
4,4
3,4
4,4
5 5
Problem- Repeated analysis for “inc”- Exploding call contexts
int x; //globalf1(){1: x = 0;2: if(*) f2();3: else f2(); 4: if (x<0) ERROR;return;}
int x; //globalf1(){1: x = 0;2: if(*) f2();3: else f2(); 4: if (x<0) ERROR;return;}
f2(){1: if(*) f3();2: else f3(); return;}
f2(){1: if(*) f3();2: else f3(); return;}
f3(){1: if(*) f4();2: else f4(); return;}
f3(){1: if(*) f4();2: else f4(); return;}
f4(){1: if(*) f5();2: else f5(); return;}
f4(){1: if(*) f5();2: else f5(); return;}
fn(){1: x ++; return;}
fn(){1: x ++; return;}
2n nodes in Reach Tree
Inline Calls in Reach Tree
1
2
1,2
Initial
2,2
4,2
3,2
4,2
3 3
4
1,4
2,4
4,4
3,4
4,4
5 5
Problem- Repeated analysis for “inc”- Exploding call contexts- Cyclic call graph (Recursion)
- Infinite Tree!
Solution : Procedure SummariesSummaries: Input/Output behavior• Plug summaries in at each callsite … instead of inlining entire procedure[Sharir-Pnueli 81, Reps-Horwitz-Sagiv 95]
• Summary = set of (F F’)– F : Precondition formula describing input
state– F’ : Postcondition formula describing output
state
Solution : Procedure SummariesSummaries: Input/Output behavior• Plug summaries in at each callsite … instead of inlining entire procedure[Sharir-Pnueli 81, Reps-Horwitz-Sagiv 95, Ball-Rajamani 01]
• Summary = set of (F F’)– F : Precondition formula describing input
state– F’ : Postcondition formula describing output
state
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
• (: sign=0 rv > a) • (sign = 0 rv < a)
Q. How to compute, use summaries ?
Lazy Abstraction + Procedure Summaries
Abstract
Refine
C Program
Safe
Trace
Yes
NoPropert
y
Q. How to compute, use summaries ?
Abstraction with Summariesmain(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
main
Predicates: flag=0 , y>x , y<z
sign=0 , rv>a , rv<a
: flag=0 a=x
sign=flag:
sign=0
[flag!=0]
Abstraction with Summariesmain(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1
main
2
4
Predicates: flag=0 , y>x , y<z
sign=0 , rv>a , rv<a
inc
: flag=0
: sign=0
a=x
sign=flag:
sign=0
[sign!=0]
: sign=0rv=a+1
rv>a
Summary: (: sign=0 rv>a),
Summary Successormain(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1
main
2
4
Predicates: flag=0 , y>x , y<z
sign=0 , rv>a , rv<a
inc
: flag=0
: sign=0
rv>a
Summary: (: sign=0 rv>a),
3
a=x
sign=flag
y>xassume rv>ay=rv
Abstraction with Summariesmain(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1
main
2
4
Predicates: flag=0 , y>x , y<z
sign=0 , rv>a , rv<a
inc
: flag=0
: sign=0
rv>a
Summary: (: sign=0 rv>a),
3y>x
[y<=x]
34 flag=0
a=x
sign=flag
sign=0
[sign=0][flag==0]
Abstraction with Summariesmain(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1
main
2
4
Predicates: flag=0 , y>x , y<z
sign=0 , rv>a , rv<a
inc
: flag=0
: sign=0
rv>a
Summary: (: sign=0 rv>a),
(sign=0 rv<a)
3y>x
34 flag=0
a=x
sign=flag
sign=0
1 sign=0
2 3
4 rv<a
Summary Successormain(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1
main
2
4
Predicates: flag=0 , y>x , y<z
sign=0 , rv>a , rv<a
inc
: flag=0
: sign=0
rv>a
Summary: (: sign=0 rv>a),
(sign=0 rv<a)
3y>x
34 flag=0
1 sign=0
2 3
4 rv<a
a=x
sign=flag
assume rv<ay=rv
3 y<z
Abstraction with Summariesmain(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1
main
2
4
Predicates: flag=0 , y>x , y<z
sign=0 , rv>a , rv<a
inc
: flag=0
: sign=0
rv>a
Summary: (: sign=0 rv>a),
(sign=0 rv<a)
3y>x
34 flag=0
1 sign=0
2 3
4 rv<a
3 y<z
[y>=z]
Another Call …main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }6: y1 = inc(z1,1);7: if (y1<=z1) ERROR;return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }6: y1 = inc(z1,1);7: if (y1<=z1) ERROR;return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1
main
2
4
inc
: flag=0
: sign=0
rv>a
Summary: (: sign=0 rv>a),
(sign=0 rv<a)
3
6
y>x
34 flag=0
1 sign=0
2 3
4 rv<a
3 y<z
a=z1
sign=1: sign=0
6
Predicates: flag=0 ,y>x,y<z, y1>z1
sign=0 , rv>a , rv<a
Another Call …main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }6: y1 = inc(z1,1);7: if (y1<=z1) ERROR;return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }6: y1 = inc(z1,1);7: if (y1<=z1) ERROR;return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
1
2
1
main
2
4
Predicates: flag=0 ,y>x,y<z, y1>z1
sign=0 , rv>a , rv<a
inc
: flag=0
: sign=0
rv>a
Summary: (: sign=0 rv>a),
(sign=0 rv<a)
3
6
y>x
34 flag=0
1 sign=0
2 3
4 rv<a
3 y<z
7
a=z1
sign=1
assume rv>ay1=rv
6
y1>z1SAFE
Note: Predicates are well-scoped …
Lazy Abstraction + Procedure Summaries
Abstract
Refine
C Program
Safe
Trace
Yes
NoPropert
y
Q. How to find scoped predicates ?
pc1: x1 = 3
pc2: assume (x1>0)
pc3: x3 = f1(x1)pc4: y2 = y1
pc5: y3 = f2(y2)pc6: z2 = z1+1
pc7: z3 = 2*z2
pc8: return z3
pc9: return y3
pc10: x4 = x3+1
pc11: x5 = f3(x4)pc12: assume(w1<5)
pc13: return w1
pc14: assume x4>5
pc15: assume (x1=x3+2)
Traces with Procedure Calls
Trace Formula
i
Trace
i
Find predicate needed at point
i
pc1: x1 = 3
pc2: assume (x1>0)
pc3: x3 = f1(x1)pc4: y2 = y1
pc5: y3 = f2(y2)pc6: z2 = z1+1
pc7: z3 = 2*z2
pc8: return z3
pc9: return y3
pc10: x4 = x3+1
pc11: x5 = f3(x4)pc12: assume(w1<5)
pc13: return w1
pc14: assume x4>5
pc15: assume(x1=x3+2)
Interprocedural Analysis
Trace Formula
i
Trace
iRequire at each point i:
Scoped predicatesYES: Variables visible at iNO: Caller’s local variables
Find predicate needed at point
i
YES
NO
NO
Problems with Cutting
Trace Formula
i
Trace
i
-
+
Caller variables common to - and +
• Unsuitable interpolant: not well-scoped
Scoped Cuts
Trace Formula
i
Call begins
Trace
i
Scoped Cuts
-+
Trace Formula
i
Call begins
Trace
i
Predicate at pci = Interpolant from cut i
Common Variables
Formals
Current locals
Trace Formula
Predicate at pci = Interpolant from i-cut
i
Trace
i-+
Common Variables
Formals
Well-scoped
Example Trace
m1: assume(flag!=0)
m2: y=inc(x,flag)
i1: assume(sign!=0)
i2: rv = a+1
i4: return rv
m3: assume(y<=x)
ERROR:
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
main(){ 1: if (flag){2: y = inc(x,flag);3: if (y<=x) ERROR; } else {4: y = inc(z,flag);5: if (y>=z) ERROR; }return;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
inc(int a, int sign){ 1: if (sign){2: rv = a+1; } else {3: rv = a-1; }4: return rv;}
Trace Formula
Trace SSA Trace
m1: assume(flag!=0)
m2: y=inc(x,flag)
i1: assume(sign!=0)
i2: rv = a+1
i4: return rv
m3: assume(y<=x)
m1: assume(flag0!=0)
m2: a0=x0, sign0=flag0
i1: assume(sign0!=0)
i2: rv0=a0+1
i4: y0=rv0
m3: assume(y0 <= x0)
Trace Formula
Trace Trace Formula
m1: assume(flag!=0)
m2: y=inc(x,flag)
i1: assume(sign!=0)
i2: rv = a+1
i4: return rv
m3: assume(y<=x)
Æ flag0 0
Æ a0=x0 Æ sign0= flag0
Æ sign0 0
Æ rv0=a0+1
Æ y0=rv0
Æ y0 <= x0
i i
Call begins
Trace Formula
Trace Trace Formula
m1: assume(flag!=0)
m2: y=inc(x,flag)
i1: assume(sign!=0)
i2: rv = a+1
i4: return rv
m3: assume(y<=x)
Æ flag0 0
Æ a0=x0 Æ sign0= flag0
Æ sign0 0
Æ rv0=a0+1
Æ y0=rv0
Æ y0 <= x0
-+
i i
Trace Formula
Trace Trace Formula
m1: assume(flag!=0)
m2: y=inc(x,flag)
i1: assume(sign!=0)
i2: rv = a+1
i4: return rv
m3: assume(y<=x)
Æ flag0 0
Æ a0=x0 Æ sign0= flag0
Æ sign0 0
Æ rv0=a0+1
Æ y0=rv0
Æ y0 <= x0
i-+
irv0 a0
a0
rv0
rv0> a0
Interpolate
Lazy Abstraction + Procedure Summaries
Abstract
Refine
C Program
Safe
Trace
Yes
NoPropert
y
Q. How to find scoped predicates ?Solution: Scoped Cuts + Interpolation
Review : Procedures
Modular Analysis via Summaries– Summary = (In,Out) vertices’
formulas
Requires scoped predicates– Scoped cuts + Interpolation
This Lecture: Modular Analyses
Procedures- Summaries
Concurrency- Thread-Context Reasoning
This Lecture: Modular Analyses
Procedures- Summaries
Concurrency- Thread-Context Reasoning
Multithreaded Programs
OS, WebServers, Databases, Embedded Systems Curse of Interleaving• Non-deterministic scheduling• Exponentially many behaviors: hard to detect, reproduce errors
Testing exercises a fraction of possible behaviors
Thread Thread
SharedMemory
x Thread
Thread
Data Races
x:= x+1
x:= x+1
x:= x-5
x:= x-5
x
A data race on x is a state where:• Two threads can access x• One of the accesses is a write
Unpredictable, undesirable
Synchronization: Must hold lock when accessing x
lock(l)
unlock(l)
lock(l)
unlock(l)
Previous Work : Locks
x:= x+1
x:= x+1
lock(l)
unlock(l)
1. Infer some lock(s) that protect x2. Check lock(s) held when accessing x3. Report error if lock(s) not held
Static LockSet [Sterling 93], [Engler-Ashcraft 03]
[Flanagan-Freund 00] [Bacon et al.
00][Boyapati et al. 02]
[Dinning-Schonberg 90] [Savage et al. 97][Cheng et al. 98] [Choi et al. 02]
Type-based
Dynamic LockSet
Object Usage Graph [von Praun-Gross 03]
ScalableRestricted to locking
Other Synchronization Idioms
Producer-Consumer
atomic{ old:= state; if(state==0){ state:=1; }}if(old==0){ x++; state:=0;}
atomic{ old:= state; if(state==0){ state:=1; }}if(old==0){ x++; state:=0;}
State-based
Interrupt-toggling
x
Previous Work : Model Checking
Producer-Consumer
atomic{ old:= state; if(state==0){ state:=1; }}if(old==0){ x++; state:=0;}
atomic{ old:= state; if(state==0){ state:=1; }}if(old==0){ x++; state:=0;}
State-based
Interrupt-toggling
x
Model Checking(State Exploration)
[Godefroid 97][Holzmann][Havelund-Visser][Dwyer-Hatcliff][Avrunin-Clarke][Musuvathi-Dill-Engler 02][Yahav 01]
Any Synch. Idiom
Fixed #threadsManual
Abstraction
State Explosion
Data Race
Shared Memory
Initial
Race Checking by State Exploration
Is there a path fromInitial to Race ?
Problem: State Explosion
Shared Memory
Data Race
Initial
Is there a path fromInitial to Race ?
Problem: State Explosion
2. Controlk threads, m locations = mk - k=4,m=100, states = 1 billion
Unbounded threads ?
1. DataInfinitely many valuationsfor program variables
Data Race
Initial
LA for Multithreaded Programs1. Data Races
– Previous Work– State Explosion
2. Abstractions
3. Context Inference
1. Data Races– Previous Work– State Explosion
2. Abstractions
3. Context Inference
LA for Multithreaded Programs
Problem: State Explosion
2. Controlk threads, m locations = mk - k=4,m=100, states = 1 billion
Unbounded threads ?
1. DataInfinitely many valuationsfor program variables
Data Race
Initial
Solution: Abstract Irrelevant Detail
1. DataInfinitely many valuationsfor program variables
2. Controlk threads, m locations = mk - k=4,m=100, states = 1 billion
Unbounded threads ?
Observe- Analyze system as Thread + Context- Context: Summary of all other threads (w.r.t. property)
2. Thread-Context Analysis
Observe- Few relevant variables, relationships- Track predicates (relationships) instead of values
1. Predicate Abstraction
ExampleCheck for races on x:
Initially: s is 0
1st thread into atomic :- sets old to 0 (value of s)- sets s to 1 - passes test before access
Later threads: - set old to 1 (value set by 1st thread)
- fail test before access (until the 1st thread is done)
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1. Data Races– Previous Work– State Explosion
2. Abstractions– Data: Predicate Abstraction– Control: Thread-Context Reasoning
3. Verifying Multithreaded Programs
LA for Multithreaded Programs
Predicate Abstraction
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
Predicates on Variables
s=0, old=0
s=0
1
2
3
4
1
Reachability Graph
s=0
s=0, old=0
5
6
s=0, old=0: s=0, old=0
: s=0 old=
0
s=0 old=
0 Q: What about other threads ?
x++
1. Data Races– Previous Work– State Explosion
2. Abstractions– Data: Predicate Abstraction– Control: Contexts
• Thread-Context Reasoning
3. Context Inference
LA for Multithreaded Programs
Threads, Contexts
Q: What about other threads ?
Shared Memory
Assume threads run same code
Context: Summary of all other threads - Precise enough to check property
System = Thread + Context
Q: What does a Context look like ?
ContextContext
Thread, Contexts
Context: Summary of all other threads
1. Summarize a single thread
2. Multiple threads by counting
Q: What does a Context look like ?
Shared Memory
ContextContext
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
s=0
s
s,x
s0
s0
Thread Summary
Context
Many Threads by Counting
s=0
s
s,x
s0
s0
Context
True
1 11
0 0
0
s=0State
s 0s 0Æ s=0
Initial loc = 1 , other = 0Operations1. Pick edge w/ source counter >
0, 2. Source counter -1 Target counter +1
Havoc variables on edge, Assume predicate on target
Unbounded threadsk-Counter Abstraction:
Value > k abstracted to 1for k=1, values: 0,1,1
Q: What does a Context look like ?
1
Contra!
1
21
1. Data Races– Previous Work– State Explosion
2. Abstractions– Data: Predicate Abstraction– Control: Contexts
• Thread-Context Reasoning
3. Context Inference
LA for Multithreaded Programs
Thread-Context Reasoning
Q: How to check race-freedom ? Given an Abstraction: 1. Data:Predicates 2. Control: Summary, k
1 Use Context Build finite Reach Graph Check Race unreachable
2 Verify Context Sound Check Summary Overapproximates single Thread’s behavior
k
k
Shared Memory No Race
µReac
h Grap
h
Summarize
Computed Summary
Given Summary
Q: How to check race-freedom ? Given an Abstraction: 1. Data:Predicates 2. Control: Summary, k
1 2
Shared Memory
Assume-
Guarantee(Use) (Verify)
No Race
k
Shared Memory No Race
µReac
h Grap
h
Summarize
Thread-Context Reasoning
Computed Summary
Given Summary
1. Data Races– Previous Work– State Explosion
2. Abstractions– Data: Predicate Abstraction– Control: Thread-Context Reasoning
3. Context Inference
LA for Multithreaded Programs
1. Data Races– Previous Work– State Explosion
2. Abstractions– Data: Predicate Abstraction– Control: Thread-Context Reasoning
3. Context Inference
LA for Multithreaded Programs
Inference: Build Summary
1
Reach
Graph
2
; µ ;Summariz
e
1
Reach
Graph
No Race
Race
Trace
Abstraction Preds: P0 Ctr: k0
Inference: Trace Analysis
Trace
FeasibleInfeasible
Refine using Trace
Either:1. Add new predicates2. Increase k
Abstraction Preds: P0 Ctr: k0
Report Trace
Interleaved sequenceof threads’ ops
Abstraction Preds: P1 Ctr: k1
Inference: Build Summary
1
Reach
Graph
2
µ ;Summariz
e
Abstraction Preds: P0 Ctr: k0
Abstraction Preds: P1 Ctr: k1
1
Reach
Graph
2
µSummariz
e
1
Reach
Graph
2
µSummariz
e
;
Context Inferred
1Reac
h Grap
h
2
µSummariz
e
Shared Memory
Assume-
Guarantee
No Race
NO (trace)
Context Inference
Init. Abstraction Preds: P0 Ctr: k0
Init. Summary Summary: ;
1
Reach Graph
YES SummarizeSafe?
2
µ ?
YES
NO
Update Summary
Refine using Trace
Feasible?
YES
NO Output SAFENo Data Races
OutputData Race
TRACE ANALYSIS
BUILD SUMMARY
Plan1. Data Races
– Previous Work– State Explosion
2. Abstractions– Data: Predicate Abstraction– Control: Thread-Context Reasoning
3. Context Inference – Example
Ex: Races on x
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
;
Abstraction Preds =; k=1
1
2
3
4
5
6
Reach
Graph
T
7
x++;
Summarize
2
µ ;
1
x
Build Summary
x
Control-Flow Graph
Ex: Races on x
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
Abstraction Preds =; k=1
Reach
Graph
1
Build Summary
x
1
2
3
4
5
6
x++6
Racex
Thread 1
Ex: Races on x
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
Abstraction Preds =; k=1
Reach
Graph
1
Trace Analysis
x
1
2
3
4
5
6
x++6
Trace
x
Thread 0
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
x
assume (True)
old := sassume (s==0)
s:= 1
// do_work()
assume (old==0)
//write x enabled
1
2
3
4
5
6
T
7
x++;
assume (True)
old := s
assume (s==0)
s:= 1
// do_work()
assume (old==0)
//write x enabled
Thread 1
Ex: Races on x Trace Analysis
Trace Thread 0
assume (True)
old := sassume (s==0)
s:= 1
// do_work()
assume (old==0)
//write x enabled
assume (True)
old := s
assume (s==0)
s:= 1
// do_work()
assume (old==0)
//write x enabled
Time
s is set to 1
Infeasible branch
New Predicate
s = 0
Infeasible Trace
Ex: Races on x
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1: while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
;
Abstraction Preds: s=0 k=1
Reach
Graph
Summarize
2
µ ;
1
Build Summary
, old=0
s=0
1
2
3
4
s=0
s=0 old=
0
5
6
s=0 old=0
: s=0 old=
0
7
: s=0 old=
0 x++
s:=0
: s=0 old=
0
Local Pred. old=0 - Prunes infeasible paths - Invisible to other threads - Quantified away
s:=1
s=0
x
s0
s
s
s0
s=0
x
s0
s
s
s0
Ex: Races on x
1:while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1:while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
Abstraction Preds: s=0 k=1
Reach
Graph
Summarize
2
µ
1
Build Summary
, old=0
1
2
3
4
s=0 Ç s0
5
6
s=0 old=0
s0 old=0s0 old=0
x++
s:=0
s:=1
T
T
5
Context changes s
s0 old0
s=0s
s,x
s0
s0
s=0
x
s0
s
s
s0
Local Pred. old=0 - Cuts locally infeasible paths - Invisible to other threads - Quantified away
s=0
x
s0
s
s
s0
s=0s
s,x
s0
s0
s=0 Ç s0
Ex: Races on x
1:while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
1:while(1){ atomic{2: old := s;3: if(s==0){4: s := 1; } } // do_work() 5: if(old==0){6: x++;7: s:=0;}}
Abstraction Preds: s=0 k=1
Reach
Graph
Sumz
2
µ
1
Build Summary
, old=0
1
2
3
4
5
6
s=0 old=0
s0 old=0s0 old=0
x++
s:=0
s:=1
T
T
T
5
s0 old0
s=0s
s,x
s0
s0
s=0s
s,x
s0
s0
s=0s
s,x
s0
s0
SAFENo Races on x
Plan1. Data Races
– Previous Work– State Explosion
2. Abstractions– Data: Predicate Abstraction– Control: Thread-Context Reasoning
3. Context Inference – Example
4. Experiments
Data Races in NesC Programs
PL for Networked Embedded Systems [Gay et al. 03]
• Interrupts fire events, which fire other events
or post tasks which run asynchronously
• Race-freedom important– Non-trivial synchronization idioms – Flow-based analysis
• Compiled to C
Case Study: sense.nc
atomic{ old:= state; if(state==0){ state:=1; }}if(old==0){ x++;
atomic{ old:= state; if(state==0){ state:=1; }}if(old==0){ x++;
Interrupt 1 fires
old := stateif (state ==0){ state := 1
assume (old == 0){ about to write x
Interrupt 2 fires
state := 0 Interrupt 1 fires
old := stateassume (state ==0){ state := 1
If (old == 0){ about to write x
Interrupt 1 handler disables interrupt 2
BLAST finds information proves no races
Review : Multithreaded1. Multithreaded Verification is hard
– Data, Control Explosion– Abstract Irrelevant details
2.Combine Abstractions1. Data: Predicates2. Control: Contexts (Summary +
Counter)
3. Iterative Context Inference
Next lecture … Partial-program analysis: From verification to interfaces