Threadmodular Abstraction Refinement Thomas A Henzinger et al
Thread-modular Abstraction Refinement Thomas A. Henzinger, et al. CAV 2003 Seonggun Kim KAIST CS 750 b
Abstract of this paper We present an algorithm called Tar (“Thread-modular Abstraction The exponential complexity to Refinement") for model checking safety properties Due of concurrent software. The Tar algorithm uses thread-modular assume-guarantee in the control state of mt-programs interleaving reasoning to overcome the exponential complexity in the control state of multithreaded programs. Thread modularity means that Tar explores the. Thread-modularity state space of one thread at a Needs time, making assumptions about how assumptions about the environment can interfere. The Tar algorithm uses counterexample (one predicate-abstraction thread at a time)refinement the behavior of the other threads guided to overcome usually infinite complexity in the data state of C programs. A successive approximation scheme automatically infers the necessary precision on data variables as Assume-guarantee reasoning well as suitable environment assumptions. The scheme is novel in that transition relations are approximated from above, while at the same time environment assumptions are approximated from below. In our software verification tool Blast we have implemented a fully automatic Assumption Inference Iteratively weakening race checker for multithreaded C programs which is based on the Tar the assumptions until fix-point algorithm. This tool has verified a wide variety of commonly used locking idioms, including locking schemes that are not amenable to existing dynamic and static race checkers such as Eraser or Warlock. 2
Multithreaded Programs n Why multithreading? ¡ ¡ n Performance (esp, response time) Conceptual simplicity Why not multithreading? ¡ ¡ Race hazard Deadlock Thread x Thread Shared Memory 3
Race Hazard n A thread can be interfered by others 1: bal = get. Balance(); 2: bal += deposit; 3: set. Balance(bal); balance = 100 120 deposit = 20 bal = 100 bal = 120 1: bal = get. Balance(); 2: bal += deposit; 3: set. Balance(bal); bal = 120 3: set. Balance(bal); bal = 100 bal = 120 4
Detecting Race Hazard n Critical Section ¡ n A piece of code that must not be concurrently accessed by more than one thread Can be detected by safety checking ¡ “Is (T 1||T 2) reachable to states satisfying (pc 1 Crit pc 2 Crit) ? ” n n No safe, Yes unsafe But, it may be intractable 5
Curse of Interleaving n A 1 A 1 B 1 A 1 A 2 B 1 B 2 B 1 A 3 B 1 B 2 B 3 A 2 B 1 B 2 B 3 A 1 A 3 B 2 B 3 A 2 B 2 B 3 A 3 A 3 B 3 A 3 … State Explosion nk (n statements, k threads) Need to abstract away other threads ¡ ¡ Divide and Conquer (one thread at a time) Can we do the abstraction a priori? 6
Naïve Thread-modular Analysis n Conservative (pessimistic) Assumption ¡ “Others can access shared resources anytime” Simple, But rarely happens safe 7
Assume-Guarantee Reasoning Prove: S 1 u. S 2 v P 1 u. P 2 S 1 v. P 1 S 2 v. P 2 S 1 u. S 2 v P 1 u. P 2 Divide and Conquer n S 1 v. P 1 S 1, S 2: sub-systems P 1, P 2: sub-properties P 1 u. S 2 v. P 2 S 1 u. S 2 v P 1 u. P 2 u. S 1 v. P 1 u. S 2 v. P 2 S 1 u. S 2 v P 1 u. P 2 Assume-Guarantee reasoning 1. 2. 3. Make an assumption Use the assumption to prove required properties Ensure the assumption is correct 8
Circular Assume-Guarantee P 2 u. S 1 v. P 1 u. S 2 v. P 2 S 1 u. S 2 v P 1 u. P 2 u S 1 v u S 2 v S 1 u S 2 v u Circular Assume-Guarantee Cyclic Guarantee n ¡ ¡ To guarantee assuming P 2 is correct, we need to guarantee assuming P 1 is correct, vice versa Cycle-breaking condition is needed (beyond this paper) Is it sound? Is it complete? n ¡ ¡ Not sound, not complete for general cases Sound, but not complete for safety properties (beyond this paper) 9
Thread-modular AG Reasoning n n n A form of assume-guarantee reasoning P = S 1 | S 2 | … | Sn For each thread Si, specify two actions ¡ Ai: an environment assumption of Si n ¡ Gi: a guarantee of Si n n Transitions that may be performed by other threads Transitions of Si under Ai that can be seen by other threads Ensuring the assumption ¡ Check whether Gi is stronger than Aj for all j, j i 10
A Use Summaries (“Assume”) safe 11
G Verify Summaries (“Guarantee”) µ safe 12
Assume-Guarantee Reasoning µ µ safe 13
T-M Abstraction Refinement n n Step 0: Seed Assumption ¡ Set the assumption for each thread to false ( ) allows no transition to other threads Step 1: Reachability Analysis (same as LA) ¡ Compute an abstraction Ri of the reachable states of each thread i , based on the current assumptions about the behavior of the other threads Step 2: Counterexample Analysis (same as LA) ¡ Check if Ri contains error states n Yes: do trace analysis and abstraction refinement; goto step 0 n No: goto step 3 Step 3: Guarantee Assumptions allows transitions Ri ¡ Check if the assumptions are sound to other threads n Yes: report “safe” n No: update the assumptions w. r. t. the Ri ; goto step 1 14
Iter 1: Build Summary A Reach Graph Trace Local Predicate - Cuts locally infeasible paths - Invisible to other threads Race - Quantified away A ; G Reach Graph No Race Summarize µ ; 15
Iter 1: Trace Analysis Trace Infeasible Feasible Refine using Trace Report Trace Add new predicates Interleaved sequence of threads’ ops 16
Iter 2: Build Summary A Reach Graph G Summarize A ; Reach Graph µ µ G Summarize µ ; 17
Context arrives at Fix-point A Reach Graph G Summarize µ Assume-Guarantee Shared Memory No Race 18
Example: Producer-Consumer Thread Producer 1: while(1) { 2: while(flag != 0) {}; 3: data = produce_data(); 4: flag = 1; } n n Thread Consumer 1: while(1) { 2: while(flag != 1) {}; 3: copy = data; 4: flag = 0; } Shared Variables: data, flag , P, C Error State: pcp = 3 pcc = 3 P C Initial State: pcp = 1 pcc = 1 flag = 0 !P !C Implicit Local Predicate: pcp, pcc 19
Iteration 1 -1 Thread Producer 1: while(1) { 2: while(flag != 0) {}; 3: data = produce_data(); 4: flag = 1; } Thread Consumer 1: while(1) { 2: while(flag != 1) {}; 3: copy = data; 4: flag = 0; } !P Reach Graph !P !P Sum. P µ µ P !P !C Reach Graph !C C !C Sum. C !C 20
Iteration 1 -2 !C C Thread Producer 1: while(1) { 2: while(flag != 0) {}; 3: data = produce_data(); 4: flag = 1; } R. G. !P !C !P C P !C P C !P !C !P C Trace Analysis Add flag !P P Thread Consumer 1: while(1) { 2: while(flag != 1) {}; 3: copy = data; 4: flag = 0; } R. G. !C !P !C P C !P C P !C !P !C P Trace Analysis 21
Iteration 2 -1 Thread Producer 1: while(1) { 2: while(flag != 0) {}; 3: data = produce_data(); 4: flag = 1; } Thread Consumer 1: while(1) { 2: while(flag != 1) {}; 3: copy = data; 4: flag = 0; } !P R. G. !P !P S. P !F µ µ !P F !C R. G. !C !C S. C F !C !F 22
Iteration 2 -2 !C C F !C !F Thread Producer 1: while(1) { 2: while(flag != 0) {}; 3: data = produce_data(); 4: flag = 1; } R. G. !P !C !P C F !P !C !F P !F !C !P C F !P !C !F Sum !P Same for Consumer P !F !P !C !P C F !P !C !F P !F !C !P C F !P !C !F 23
Experimental Result 24
Thread-modular Analysis BUILD SUMMARY Update Summary A Init. Abstraction Preds: P 0 Ctr: k 0 Init. Summary: ; Reach Graph G Safe? YES Summarize NO (trace) Refine using Trace NO TRACE ANALYSIS Feasible? µ? NO YES Output SAFE No Data Races YES Output Data Race 25
Conclusion n Thread-Modular Abstraction Refinement ¡ n Overcome the exponential complexity in the control state of multithreaded programs Race Detection ¡ Verified a wide variety of commonly used locking idioms n Including locking schemes that are not amenable to existing race checkers such as Eraser or Warlock 26
Pros & Cons n Pros ¡ ¡ n Annotation-free thread-modular analysis Extends BLAST to concurrent programs Cons ¡ It still needs to compute an interleaving n n To check if the trace is feasible Does it really reduce the burden of interleaving? 27
References n Some figures and slides come from Ranjit Jhala’s slides ¡ “Three lectures on Lazy Abstraction” #2 n n ¡ http: //www. cse. ucsd. edu/~rjhala/blast. html p. 2, pp. 12~16 osq. cs. berkeley. edu/retreat 03/Jhala-TAR. ppt n p 6, pp. 8~10 28
- Slides: 28