330 likes | 468 Views
Thread-modular Abstraction Refinement. Tom Henzinger Ranjit Jhala Rupak Majumdar [UC Berkeley] Shaz Qadeer [Microsoft Research]. Introduction. Model Checking Software “Little theorems about big programs” “automatic”, Path sensitive properties Limited to sequential programs
E N D
Thread-modularAbstraction Refinement Tom Henzinger Ranjit Jhala Rupak Majumdar [UC Berkeley] Shaz Qadeer [Microsoft Research]
Introduction • Model Checking Software • “Little theorems about big programs” • “automatic”, Path sensitive properties • Limited to sequential programs • Thread-modular Reasoning • Efficiently decompose checks • Requires manual (or divine) intervention • TAR: Thread-modular Abstraction Refinement • Eliminate the divine using abstraction-refinement • Safety checking for concurrent programs
Check Is model safe ? Seed Abstraction • Program • YES • NO! (Trace) • explanation SAFE infeasible feasible Why infeasible ? Refine BUG The story so far ... • Analyzing Sequential programs • BLAST/SLAM/… • Iterative Abstraction-Refinement [Kurshan ’93] Abstract
… and what of Concurrent Programs? • Shared Memory (multithreaded) • Message Passing • Hard to analyze ! • Interleavings / State explosion • One approach: Thread-modular analysis • Analyse threads separately • Compose analyses • [Jones ’83, CALVIN (FQS ’02), Assume-Guarantee]
The Problem • Safety checking: • Is an ERROR state reachable ? • boxes = threads • white denotes shared variables
safe safe safe Thread-modular analysis (take1)
safe safe Thread-modular analysis (take1) • If only… ! Threads are correct in constrained environments
Second Attempt: Summaries • “Summarize” each thread’s behavior • Use/verify summaries (circular)
Use Summaries (“Assume”) safe safe
Verify Summaries (“Guarantee”) µ µ safe safe
safe Thread-modular analysis (take 2) µ µ safe safe
? ? Our Contribution • Problem with TM Reasoning: • Divining (small) summaries • Algorithm TAR • Compute/use/verify summaries • Using iterative abstraction-refinement
An Example: Race Detection Producer { 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } } Consumer { 1: while (*) { 2: while (!flag) {}; 3: read = data; 4: flag = false; } } • Shared variables: data, flag, P, C • Error states: P Æ C • Initial states: : P Æ: C (Æ: flag) P´ ´ C
An Example: Race Detection Producer { 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } } Consumer { 1: while (*) { 2: while (!flag) {}; 3: read = data; 4: flag = false; } } • Correctness Invariant: • Producer ensures:P ):flag • Consumer ensures:C ) flag P´ ´ C
Summaries Producer { 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } } • Summary: Set of (present state, next state) pairs SProducer{ : flag !(flag’ Ç :flag’)Æ :P’ |: flag !: flag’Æ P’ } Consumer { 1: while (*) { 2: while (!flag) {}; 3: read = data; 4: flag = false; } } SConsumer{ flag !(flag’ Ç:flag’) Æ:C’ | flag ! flag’ Æ C’ }
µ while(*){sConsumer ();} safe while(*){sConsumer ();} while(*){sConsumer ();} Checking Safety [CALVIN] • [use] Sequential program: Producer+ use BLAST/SLAM/ESC/… • [verify] Every action of Producer+ is in SProducer • Where do summaries come from? Producer+{ 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } Producer { 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; }
Abstraction & Reachability Error Initial • Abstraction gives finite state space • Conservative • Abstraction safe ) System safe • Too coarse ) spurious counterexample
Refinement • Using “spurious” error traces
Refinement • Using “spurious” error traces • Add information to rule out spurious trace • e.g. Track more variables or predicates • Repeat reachability • Till safe or real trace is found
Abstraction & Reachability safe • Using “spurious” error traces • Add information to rule out spurious trace • e.g. Track more variables or predicates • Repeat reachability • Till safe or real trace is found
To Summarize ’ Reachability Tree • Nodes labeled by abstract states • Each parent-child pair ! (present, next) pair • Quantify out local state (e.g. program counter) • Take pairs where global state changes
Producer+{ 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } while(*){sConsumer ();} while(*){sConsumer ();} while(*){sConsumer ();} Tying up the threads Not yet the reachable set! Refine using “spurious” error traces ; ; Summarize
Refined System Fixpoint safe ; ;
Running TAR on Example Producer { 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } } Consumer { 1: while (*) { 2: while (!flag) {}; 3: read = data; 4: flag = false; } } • Shared variables: data, flag, P, C • Error states: P Æ C • Initial states: : P Æ: C Æ: flag P´ ´ C
Init: :P Æ:C Error: P Æ C Abs: P, C Running TAR 1 Producer{ 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } } Consumer { 1: while (*) { 2: while (!flag) {}; 3: read = data; 4: flag = false; } } P´ ´ C Reach: : P Æ: C P Æ: C Reach: : P Æ: C : P Æ C P Æ C P Æ C ; ; Summary: : P Æ: C ! P’ Æ : C’ P Æ: C !: P’Æ: C’ Summary: : P Æ: C !: P’ Æ C’ : P Æ C !: P’ Æ : C’
:flag flag Init: :P Æ:CÆ:flag Error: P Æ C Abs: P, C, flag Running TAR 2 Producer{ 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } } Consumer { 1: while (*) { 2: while (!flag) {}; 3: read = data; 4: flag = false; } } P´ ´ C Reach: : P Æ: C Æ: flag P Æ: C Æ: flag : P Æ: C Æ flag Reach: : P Æ: C Æ: flag : P Æ C Æ flag : C Æ flag : C Æ: flag : P ; ; Summary: : P Æ: flag ! P‘Æ: flag’ !: P’ Æ flag’ P Æ: flag !: P Æ: flag Summary: Summary: C Æ flag !: C’ Æ flag’ : C Æ flag !: C’ Æ: flag’ ! C’Æ flag Fixpoint Only change if flag Only change if :flag Track flag
Running TAR 2 Producer{ 1: while (*) { 2: while (flag) {}; 3: data = newdata(); 4: flag = true; } } Consumer { 1: while (*) { 2: while (!flag) {}; 3: read = data; 4: flag = false; } } P´ ´ C Reach: P Æ: C Æ: flag : P Reach: : P Æ C Æ flag : C safe ; ; Summary: : flag ! (flag’ Ç: flag’) Æ:P’ !: flag Æ P’ Summary: flag ! ( flag’ Ç: flag’) Æ: C’ ! flag’ Æ C’ Fixpoint SUMMARIES LEARNT !
Bells and Whistles • Havoc Abstractions: • Track only when the environment changes a variable • Not what new value it changes it to • For every global x, x denotes states where thread writes x • Summary: if (x) then x = * • No explicit global variables • Sharing via pointers that escape
Race Detection w/ Pointers Producer { p = &buf; while (*) { while (p->flag) {}; p->data = newdata(); p->flag = true; p = p->next; } } Consumer { q = &buf; while (*) { while (!q->flag) {}; read = q->data; q->flag = false; q = q->next; } } data flag
Conclusions • The moral … • TAR can check concurrent software • w/o (really) exploring all interleavings • The devil … • Shared memory via pointers • Explicating local state • Need to track some local state of “other” threads • Approximate Counterexample analysis • Implemented TAR in BLAST • Race checking for drivers (each client is a thread) • Linux/Windows drivers 1-10 Kloc • Looking for examples and properties …
BLAST Berkeley Lazy Abstraction Software * Tool www.eecs.berkeley.edu/~tah/blast/
Use Summaries (“Assume”) safe safe
Verify Summaries (“Guarantee”) µ µ safe safe