290 likes | 662 Views
Model Checking Multithreaded C Code with SPIN Anna Zaks & Rajeev Joshi SPIN 2008 10 August, Los Angeles, USA. The Goal: Check Multithreaded C Code. /* Peterson's algorithm (adapted from Wikipedia) */ static int sh_f0, sh_f1, sh_last; void * run_thread0 () {
E N D
Model Checking Multithreaded C Code with SPIN Anna Zaks & Rajeev Joshi SPIN 2008 10 August, Los Angeles, USA
Checking Multithreaded C Code The Goal: Check Multithreaded C Code /* Peterson's algorithm (adapted from Wikipedia) */ static int sh_f0, sh_f1, sh_last; void * run_thread0 () { struct pa_desc d;d.f0 = &sh_f0; d.f1 = &sh_f1; d.last = 1; for (;;) { *(d.f0)=1; sh_last=d.last ; while (*(d.f1)==1 && (last==d.last)) { ; /* busy wait */ } /* critical section */ d.f0=0; } } … bool turn, flag[2]; active proctype run_thread0 () { again: flag[0] = 1; turn = 1; (flag[1] == 0 || turn == 0) -> /* busy wait */ /* critical section */ flag[0] = 0; goto again; }... express design as a PROMELA model Limitations • need to redo manual translation whenever implementation changes • the absence of errors in the design does not guarantee that the implementation (the executable) is error free
Checking Multithreaded C Code Model-Driven Verification Embed C code within PROMELA - C code is executed by SPIN during search static int sh_f0, sh_f1, sh_last; void * run_thread0 () { struct pa_desc d;d.f0 = &sh_f0; d.f1 = &sh_f1; d.last = 1; for (;;) { *(d.f0)=1; sh_last=d.last ; while (*(d.f1)==1 && (last==d.last)) { ; /* busy wait */ } /* critical section */ d.f0=0; } } … c_decl { extern void * run_thread0 (void *); extern void * run_thread1 (void *); } ; ...active proctype main() { init() ; do :: choose(thread0) -> c_code {run_thread0 (); } :: choose(thread1) -> c_code {run_thread1 (); } ... od} • Main drawback: • Not useful for verification of multithreaded C programs • Need to explore the interleavings within the function Ref: Model-Driven Software Verification, G.J.Holzmann & R.Joshi, SPIN 2004
Checking Multithreaded C Code Our Solution – Introducing pancam Build pancam interpreter that can be embedded within an existing model checker pancam inherits all SPIN optimizations and future enhancements: • bit-state verification • hash compression • multi-core checking pancam does not rely on any customization of SPIN
Checking Multithreaded C Code The LLVM Compiler Infrastructure pancam interprets optimized LLVM bytecode (a typed bytecode language) catches errors that manifest themselves only after the optimization phase /* Peterson's algorithm (adapted from Wikipedia) */ static volatileint sh_f0, sh_f1, sh_last; void * run_thread0 () { struct pa_desc d;d.f0 = &sh_f0; d.f1 = &sh_f1; d.last = 1; for (;;) { *(d.f0)=1; sh_last=d.last ; while (*(d.f1)==1 && (sh_last==d.last)) { ; /* busy wait */ } /* critical section */ d.f0=0; }} Ref:LLVM compiler (originated from University of Illinois Urbana-Champaign), http://llvm.org
Checking Multithreaded C Code The pancam Checker Spin (pan.c) take_step (thread_id, granularity, &state) pancam SPIN orchestrates the state space search - decides which thread to execute next - stores visited states in the hash - restores to the previous step during DFS backtracking pancam computes the transition by code interpretation - can execute any number of instructions of a specific thread - can check predicates at any point &state
Checking Multithreaded C Code Spin Model for pancam • active proctype main() { • c_code { pancam_init(“petersons.bc”); • init_thread(0, “run_thread0”); • init_thread(1, “run_thread1”); • }; • do • :: c_expr { is_enabled(0)} -> c_code { take_step(0);} • :: c_expr { is_enabled(1)} -> c_code { take_step(1);} • od • }
Checking Multithreaded C Code Program State cs[N] enabled global state system heap FREE program stack c_track “cs” “N” “Matched”; active proctype main() { c_code { pancam_init(“petersons.bc”); init_thread(0, “run_thread0”); init_thread(1, “run_thread1”); }; do :: c_expr { is_enabled(0)} -> c_code { take_step(0);} :: c_expr { is_enabled(1)} -> c_code { take_step(1);} od }
Checking Multithreaded C Code Addressing State Space Explosion Three Strategies • support user-defined abstraction functions • use context-bounded checking • do on-the-fly partial-order reduction
Checking Multithreaded C Code User Defined Abstractions enabled global state system heap FREE program stack user defined Concrete State cs[N] Abstract Stateas[K] asis populated through the user defined function compute_abst(void *as) • cs is stored on Spin’s stack, which is used for DFS backtracking • as is used for state hashing c_track “cs” “N” “UnMatched”; c_track “as” “K” “Matched”;
Checking Multithreaded C Code Context-Bounded Checking Enforce upper bound on number of allowed preemptivecontext-switches • a switch from p to q is preemptive provided p is enabled • explore state space exhaustively with increasingly larger bounds • works well in practice - most concurrency bugs can be triggered with a small number of switches Ref:Iterative context bounding for systematic testing of multithreaded programs, M. Musuvathi, S. Qadeer, POPL 2007
Checking Multithreaded C Code pancam Implementation of Context Bounding • Implemented as an optional extension • requires no modification to Spin
Checking Multithreaded C Code Experimental Results: Context Bounding peterson.c without abstraction
Checking Multithreaded C Code On-the-fly Partial-order Reduction take_step (th_id, s) Spin pancam • pancam “transitions” have no structure : c_code { take_step (th_id, s); } Spin’s traditional partial-order reduction doesn’t apply • even if we modified Spin, computing independence relation is too hard • Shift the burden to pancam by • increasing the granularity of a “pancam step” • hiding unnecessary states from Spin s’
Checking Multithreaded C Code On-the-fly Partial-order Reduction take_step (th_id, s) Spin pancam • pancam “transitions” have no structure : c_code { take_step (th_id, s); } Spin’s traditional partial-order reduction doesn’t apply • even if we modified Spin, computing independence relation is too hard • Shift the burden to pancam by • increasing the granularity of a “pancam step” • hiding unnecessary states from Spin • Example • execute a thread until it accesses a global variable or the shared heap • Can we do better? s’
Checking Multithreaded C Code Superstep Reduction: Key Ideas S 2 • Unlike classical POR, which considers subsets of enabled transitions from state s, we consider subsets of enabled finite paths from s 1
Checking Multithreaded C Code Superstep Reduction: Key Ideas S 2 • Unlike classical POR, which considers subsets of enabled transitions from state s, we consider subsets of enabled finite paths from s • Each selected path is replaced with a single superstep transition 1
Checking Multithreaded C Code Superstep Reduction: Key Ideas S 2 • Unlike classical POR, which considers subsets of enabled transitions from state s, we consider subsets of enabled finite paths from s • Each selected path is replaced with a single superstep transition • The conflicts (dependencies) are computed dynamically 1
Checking Multithreaded C Code Superstep Requirments Compute superstep ifor each enabled thread i • a superstep is finite and nonempty • only the last transition in a superstepmay conflict with transitions in other supersteps • only the last transition of a superstepcan be visible From these, we can show thatsuperstep reduction is sound and complete for checking any LTL property without the next-time operator Can be seen as an extension of the Cartesian partial-order reduction to LTL Ref:Cartesian partial-order reduction, G. Gueta, C. Flanagan, E. Yahav, M. Sagiv, SPIN 2007
Checking Multithreaded C Code Efficient DFS Implementation • DFS is essential for liveness support • Precomputing the supersteps leads to run time overhead • Supersteps are computed on-the-fly using a scheme that maintains bookkeeping information across Spin backtracking steps • no modification to SPIN is required
Checking Multithreaded C Code Experimental Results: Superstep Reduction robots.c benchmark
Checking Multithreaded C Code Other Related Work • Modex tool extracts PROMELA models from C implementations A practical method for verifying event-driven software, G. Holzmann, M. Smith, SE1999 • Java Pathfinder integrates model checking with the virtual machine Model checking programs, W. Visser, K. Havelund, G. Brat, S. Park, F. Lerda, ASE 2003 • VeriSoft [God97] and Inspect [YCGK07] tools are state-less model checkers for C Model checking for programming languages using VeriSoft, P. Godefroid, POPL 1997 Dynamic partial-order reduction for model checking software, C. Flanagan, P. Godefroid, POPL 2005 • CHESS model checker for concurrent C code checks for livelocks Fair stateless model checking, M. Musuvathi, S. Qadeer, PLDI 2008 • CMC explicit-state model checking requires manual translation from C A pragmatic approach to model checking real code, M. Musuvathi, et al., OSDI 2002 • In CodeSurfer tool, program analysis is applied to a model constructed from an executable Wysinwyx : What you see is not what you execute, G. Balakrishnan, et al., VSTTE 2005
Checking Multithreaded C Code Summary • First version of pancam completed • implements abstraction support, context-bounding, superstep reduction • applied to several small programs (~200 lines of C) • applied to an inter-process communication module (~2800 lines of C) • fixed bug in Wikipedia implementation of Peterson’s protocol • extended the tool to support liveness properties • Ongoing work • reduce the size of a concrete state • combine superstep reduction with static POR • make some conservative approximations to reduce overhead of POR • reduce run time overhead
Checking Multithreaded C Code Questions?
S 2 1 Cap Sets • Unlike classical POR, which looks at subsets of enabled transitions from state s, we look at subsets of enabled finite paths from s • Given a state s, choose Cap(s) - a subset of finite prefixes of paths from s: : paths from s : ( , : Cap(s) ext(): )
Reduced System • Given a transition state graph M = S, T, S0, L • The reduced graphM‘ = S, T’, S0, L,such that T’ = { s :sS, Cap(s) } , where s is a superstep transition summarizing execution of path • If M and M' are stuttering equivalent, for any LTL formulaAf without the next time operator, and every initial state s: s╞Af in M if and only if s╞Af in M'
r’ r Independence Requirement [: paths from s : ( , : Cap(s) ext(): ); let = ] Independence Requirement: transitions of are independent from • is enabled at s, and results in the same state as • then choose = s
r’ r Visibility Requirement [ have to show that( )( )] Visibility Requirement: bothandhave the same visible transition and at most one is allowed • All states on the paths and can be partitioned into two sets Seq and Req: • s’Seq: L(s) = L(s’) • r’Req: L(r) = L(r’) L(s) L(s) s L(r) L(r)
r’ r Visibility Requirement [ have to show that( )( s )] Visibility Requirement: bothandhave the same visible transition and at most one is allowed • All states on the paths and can be partitioned into two sets Seq and Req: • s’Seq: L(s) = L(s’) • r’Req: L(r) = L(r’) • No need to show the intermediate states • Path is substituted by one superstep transition L(s) s s L(r) L(r)