1 / 26

Bounded Model Checking of Concurrent Programs

Bounded Model Checking of Concurrent Programs. Ishai Rabinovitz and Orna Grumberg CAV ‘05 Presented by Changki Hong. Software Model Checking. Main trends in formal verification SAT-based Bounded Model Checking (BMC) leading technique for model checking of hardware

lelandf
Download Presentation

Bounded Model Checking of Concurrent Programs

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Bounded Model Checking of Concurrent Programs Ishai Rabinovitz and Orna Grumberg CAV ‘05 Presented by Changki Hong

  2. Software Model Checking • Main trends in formal verification • SAT-based Bounded Model Checking (BMC) • leading technique for model checking of hardware • Software verification using formal method • Traditional testing method often fails to find bugs in concurrent programs • How about adopting BMC technique for software? • Error traces are typically long  large bound is needed • This results in a too large propositional formula handled by SAT solver • C-Bounded Model Checking (CBMC) • Handled problems stated above. • However, CBMC is only for verifying sequential programs  TCBMC

  3. CBMC in multi-threaded program thread 1 thread 2 thrd1_x1 = 0; thrd1_i1 = 0; if (thrd1_i1 < 3) { thrd1_x2 = thrd1_x1 + 1; thrd1_i2 = thrd1_i1 + 1; } if (thrd1_i2 < 3) { thrd1_x3 = thrd1_x2 + 1; thrd1_i3 = thrd1_i2 + 1; } if (thrd1_i3 < 3) { thrd1_x4 = thrd1_x3 + 1; thrd1_i4 = thrd1_i3 + 1; } thrd2_x1 = 0; thrd2_i1 = 0; if (thrd2_i1 < 3) { thrd2_x2 = thrd2_x1 + 1; thrd2_i2 = thrd2_i1 + 1; } if (thrd2_i2 < 3) { thrd2_x3 = thrd2_x2 + 1; thrd2_i3 = thrd2_i2 + 1; } if (thrd2_i3 < 3) { thrd2_x4 = thrd2_x3 + 1; thrd2_i4 = thrd2_i3 + 1; } int x; int i; thread1() { x=0; for (i=0; i<3; i++) x++; } thread2() { x=0; for (i=0; i<3; i++) x--; } • Can not extend CBMC’s approach to concurrent C programs • When there are assignments in two different threads to the same global variable, we can’t determine the order in which they will be executed.

  4. Contents • TCBMC • Modeling Synchronization Primitives • Verifying Race Conditions and Deadlocks • Experimental Results • Conclusions

  5. TCBMC • TCBMC (Threaded-C Bounded Model Checking) • TCBMC bounds the number of context switches • Claim : most bug patterns have only a few context switches. • TCBMC allows context switches to be anywhere in the code. • Different models are needed • We need to apply TCBMC for three times for detecting • regular bugs (assert) • data races • deadlocks

  6. TCBMC Thread 0 Thread 1 thread 1 thread 2 thrd1_x1 = 0; thrd1_i1 = 0; if (thrd1_i1 < 3) { thrd1_x2 = thrd1_x1 + 1; thrd1_i2 = thrd1_i1 + 1; } if (thrd1_i2 < 3) { thrd1_x3 = thrd1_x2 + 1; thrd1_i3 = thrd1_i2 + 1; } if (thrd1_i3 < 3) { thrd1_x4 = thrd1_x3 + 1; thrd1_i4 = thrd1_i3 + 1; } thrd2_x1 = 0; thrd2_i1 = 0; if (thrd2_i1 < 3) { thrd2_x2 = thrd2_x1 + 1; thrd2_i2 = thrd2_i1 + 1; } if (thrd2_i2 < 3) { thrd2_x3 = thrd2_x2 + 1; thrd2_i3 = thrd2_i2 + 1; } if (thrd2_i3 < 3) { thrd2_x4 = thrd2_x3 + 1; thrd2_i4 = thrd2_i3 + 1; } CSB 0 Context switch block 0 CSB 1 Context switch block 1 CSB 2 Context switch block 2 CSB 3 Context switch block 3 CSB 4 CSB 5 Context switch block 5 Context switch block 4 • Context switch block • A set of consecutive lines of code executed with no interleaving context switch

  7. Template variable threadt_cs • threadt_cs(l) • associate with each line l in the template a variable threadt_cs(l). • The value of threadt_cs(l) indicates the number of context switches that occurred before this line was executed. • threadt_cs(l) variables determine where the context switches occur. • The value of threadt_cs(l) will be decided by SAT solver using following constraints : • Monotonicity : 8l. threadt_cs(l) ·threadt_cs(l+1) • Interleaving bound : There is a bound on the number of context switches n. 8l. threadt_cs(l) ·n • Parity : For two threads, the value of threadt_cs(l) can be restricted to be even for t=0 and odd for t= 1. 8l. (threadt_cs(l) mod 2) = t • Extend the definition of threadt_cs(l) • threadt_cs(vj) = threadt_cs(lvj), wherelvj is the line in which vjis assigned.

  8. Context switch block Thread 1 Thread 0 thread0_cs thread1_cs 0 0 0 2 2 2 2 2 2 2 2 2 2 4 4 4 4 4 1 1 1 1 1 1 1 3 3 3 3 5 5 5 5 5 5 5 Context switch block 0 Context switch block 1 Context switch block 2 Context switch block 3 Context switch block 5 Context switch block 4

  9. The translation stages x1 = x2 + x3; x1 = x2 + x3; rax2; rbx3; rcra + rb; x1rc; y1=x2; y2=x3; x1=y1 + y2; • Translation process of TCBMC • Stage 1 - Preprocessing • A C statement which accesses more than one global variables is not always executed as an atomic statement. • Ex) Suppose each xiare global variables and ri are registers. • context switch may occur between these instructions • To allow such context switches in TCBMC, we need to break statements just as a complier does by introducing new temporary local variable.

  10. The translation stages global variables : each xi local variables : each yi, zi • Stage 2 - Applying CBMC seperately on each thread. • generates a list of constraints for each thread applying CBMC • template : a list of constraints generated for each thread • template has four types of statements: • local variable  local variable(s) • ex) y1=(guardr?z0:y0); • global variable  local variable(s) • ex) x1=(guardr?z0:x0); • local variable  global variable(s) • ex) y1=(guardr?x2:y0) • guard variable  guard variable and global variable(s) • ex) guard1=guard0 && (x1 > y0)

  11. Global variables • Stage 3 - Generating constraints for concurrency • Handling global variables using concept of context switch block • The bound n is the number of context switches • define n new variables x_vali for each global variable x (0· i<n) • x_vali is the value of variable x at the end of the i-th context switch block. • The value of x in context switch block i+1 is initialized to x_vali.

  12. The translation stages thread1() { if(y%2 == 0) y = z; else ; } guard0 = (y0%2 == 0); y1 = (guard0? z0 : y0); thread1_guard0 = (thread1_y0%2 == 0); thread1_y1 = (thread1_guard0? thread1_z0 : thread1_y0); global variables : each xi local variables : each yi, zi • Stage 3 - Generating constraints for concurrency (cond.) • Translate each statement in the template (stage 2) into a constraints. 1. local variable  local variable(s) - Simply add the thread prefix threadt. (to avoid name collision) - y1=(guardr?z0:y0);  threadt_y1=(threadt_guardr?threadt_z0:threadt_y0);

  13. The translation stages threadt_x1 = if (threadt_guardr)threadt_z0; else if (threadt_cs(x1) == threadt_cs(x0))threadt_x0 ; elsex_val; int x; thread1() { if(y%2 == 0) x = z; else ; } guard0 = (y0%2 == 0); x1 = (guard0? z0 : x0); (threadt_cs(x1)-1) thread1_guard0 = (thread1_y0%2 == 0); thread1_x1 = if (thread1_guard0) thread1_z0 ; else if (thread1_cs(x1) == thread1_cs(x0)) thread1_x0 ; else x_val ; 2. global variable  local variable(s) - If the assignment to x0 is in the same context switch block as the assignment x1, the thread prefix can simply be added. - Otherwise, the x_val of the previous context switch block should be used for the value of x0 - x1=(guardr?z0:x0);  (thread1_cs(x1)-1)

  14. The translation stages threadt_y1 = if (threadt_guardr) if (threadt_cs(y1) == threadt_cs(x2))threadt_x2 ; elsex_val ; else threadt_y0; (threadt_cs(y1)-1) 3. local variable  global variable(s) - If the assignment to y1 is in the same context switch block as the assignment x2, the thread prefix can simply be added. - Otherwise, the x_val of the previous context switch block should be used for the value of x2 - y1=(guardr?x2:y0)  4. guard variable  guard variable and global variable(s) - ex) guard1=guard0 && (x1 > y0) - treat as third item.

  15. Example thread1_x1 = 0; thread1_i1 = 0; thread1_guard1 = if (thread1_cs(thread1_guard1) == thread1_cs(thread1_i1)) (thread1_i1 < 3); else (i_val(thread1_cs(thread1_guard1)-1) < 3); thread1_x2 = if (thread1_guard1) if (thread1_cs(x2) == thread1_cs(x1)) thread1_x1 + 1; else x_val + 1; else if (thread1_cs(x2) == thread1_cs(x1)) thread1_x1; else x_val ; ... thread2_x1 = 0; thread2_i1 = 0; thread2_guard1 = if (thread2_cs(thread2_guard1) == thread2_cs(thread2_i1)) (thread2_i1 < 3); else (i_val(thread2_cs(thread2_guard1)-1) < 3); thread2_x2 = if (thread2_guard1) if (thread2_cs(x2) == thread2_cs(x1)) thread2_x1 - 1; else x_val - 1 ; else if (thread2_cs(x2) == thread2_cs(x1)) thread2_x1; else x_val ; ... int x; int i; thread1() { x=0; for (i=0; i<3; i++) x++; } thread2() { x=0; for (i=0; i<3; i++) x--; } (thread1_cs(x2)-1) (thread2_cs(x2)-1) + (thread1_cs(x2)-1) (thread2_cs(x2)-1) • Monotonicity :threadt_cs(l) ·threadt_cs(l+1) • Interleaving bound : threadt_cs(l) ·n • Parity : (threadt_cs(l) mod 2) = t

  16. Contents • TCBMC • Modeling Synchronization Primitives • Verifying Race Conditions and Deadlocks • Experimental Results • Conclusions

  17. Modeling synchronization primitives thread 1 add additional constraints: thread1_cs(1) = thread1_cs(2); thread1_cs(2) = thread1_cs(3); thread1_cs(3) = thread1_cs(4); • atomic { • x1 = y1; • x2 = y2; • } • Modeling atomic section • Do not allow context switch in the section marked with atomic. • just add constraints that force the threadt_cs values of the lines in an atomic section to be identical.

  18. Modeling synchronization primitives lock (mutex) unlock (mutex) atomic { assume(mutex==U); mutex = L; } atomic { assert(mutex==L); mutex = U; } • Modeling mutex • A mutex has two states, L(locked) and U(unlocked) • Lock operation : Lock waits until the mutex is in state U and changes its state to L. • Unlock operation : Unlock is applied to a mutex in state L and changes its state to U.

  19. Contents • TCBMC • Modeling Synchronization Primitives • Verifying Race Conditions and Deadlocks • Experimental Results • Conclusions

  20. Verifying race conditions atomic { assert(x_write_flag==0); x_write_flag=1; x=3; } x_write_flag=0; assert(x_write_flag==0); y = x; Translation of y =x Translation of x=3 • Race condition • A race condition is a state in which the next instruction of different threads access the same memory location and at least one of them is a write. • Detecting races • add to each global variable x a new global bit variable x_write_flag. • x_write_flag is raised whenever x is assigned to some value and lowered in the next instruction. • on every access to x we assert that its x_write_flag is low.

  21. Verifying Deadlocks • Deadlock • Global deadlocks • All the threads are waiting for a mutex • Local deadlocks • Some of threads form a waiting cycle • ex) thread1 is waiting for mutex ma which is held by thread2 which is waiting for mutex mb which is held by thread1 • Finding deadlocks • Model should be changed • Model of lock() function we learnt was implemented by assume() function • Global deadlock occurs when all threads are in a waiting state. • We must change the modeling of lock() function. • trds_in_wait : global counter for the number of threads in wait state. • When modeling lock(m), if mutex m is already in state L • increase trds_in_wait • assert that trds_in_wait < Total number of threads • If the assertion fails, a global deadlock was detected.

  22. Modeling of lock for deadlock detection if(!dd) {//dd = deadlock_detected atomic { unlocked = (mutex == U); if(unlocked) mutex = L else trds_in_wait++; } atomic { if(!unlocked) { dd = (trds_in_wait == T); assert(!dd); } } } lock(mutex)

  23. Contents • TCBMC • Modeling Synchronization Primitives • Verifying Race Conditions and Deadlocks • Experimental Results • Conclusions

  24. Experimental results ** * *Windows operating system, Pentium4 1.8Ghz with 1GB memory **Linux operating system, Pentium4 2Ghz with 250MB memory • TCBMC v.s. Zing • Concurrent implementation of bubble sort • Bugs are dependent on both data and the interleaving. • Two threads. • TCBMC scales better with respect to integer widths • TCBMC performs better for detecting bugs dependent on both data and interleavings

  25. Contents • TCBMC • Modeling Synchronization Primitives • Verifying Race Conditions and Deadlocks • Experimental Results • Conclusions

  26. Conclusions TCBMC extended CBMC to verify concurrent C programs. TCBMC bounds the number of context switches among threads. Using TCBMC, we can detect safety properties, races and deadlocks which is crucial for concurrent programs.

More Related