Predicate abstraction is a key enabling technology for applying finitestate model checkers to programs written in mainstream languages. It has been used very successfully for debugging sequential system-level C code. Although model checking was originally designed for analyzing concurrent systems, there is little evidence of fruitful applications of predicate abstraction to shared-variable concurrent software. The goal of this paper is to close this gap. We have developed a symmetry-aware predicate abstraction strategy: it takes into account the replicated structure of C programs that consist of many threads executing the same procedure, and generates a Boolean program template whose multithreaded execution soundly overapproximates the concurrent C program. State explosion during model checking parallel instantiations of this template can now be absorbed by exploiting symmetry. We have implemented our method in the SATABS predicate abstraction framework, and demonstrate its superior performance over alternative approaches on a large range of synchronization programs.
IntroductionConcurrent software model checking is one of the most challenging problems facing the verification community today. Not only does software generally suffer from data state explosion. Concurrent software in particular is susceptible to state explosion due to the need to track arbitrary thread interleavings, whose number grows exponentially with the number of executing threads.Predicate abstraction [1] was introduced as a way of dealing with data state explosion: the program state is approximated via the values of a finite number of predicates over the program variables. Predicate abstraction turns C programs into finite-state Boolean programs [2], which can be model checked. Since insufficiently many predicates can cause spurious verification results, predicate abstraction is typically embedded into a counterexample-guided abstraction refinement (CEGAR) framework [3]. The feasibility of the overall approach has been convincingly demonstrated for sequential software by the success of the SLAM project at Microsoft, which was able to discover numerous control-dominated errors in low-level operating system code [4].The majority of concurrent software is written using mainstream APIs such as POSIX threads (pthreads) in C/C++, or using a combination of language and library support, such as the Thread class, Runnable interface and synchronized construct in Java. Typically, multiple threads are spawned -up front or dynamically, in response to varying system load levels -to execute a given procedure in parallel, communicating via shared global variables. For such shared-variable concurrent programs, predicate abstraction success stories similar to that of SLAM are few and far between. The bottleneck is the exponential dependence of the generated state space on the number of running threads, which, if not addressed, permits exhaustive exploration of such programs only for trivial thread counts. The key to obtaining scalability is to exploit the symm...