Previous approaches to systematic state-space exploration for testing multi-threaded programs have proposed context-bounding and depth-bounding to be effective ranking algorithms for testing multithreaded programs. This paper proposes two new metrics to rank thread schedules for systematic state-space exploration. Our metrics are based on characterization of a concurrency bug using v (the minimum number of distinct variables that need to be involved for the bug to manifest) and t (the minimum number of distinct threads among which scheduling constraints are required to manifest the bug). Our algorithm is based on the hypothesis that in practice, most concurrency bugs have low v (typically 1- 2) and low t (typically 2-4) characteristics. We iteratively explore the search space of schedules in increasing orders of v and t. We show qualitatively and empirically that our algorithm finds common bugs in fewer number of execution runs, compared with previous approaches. We also show that using v and t improves the lower bounds on the probability of finding bugs through randomized algorithms. Systematic exploration of schedules requires instrumenting each variable access made by a program, which can be very expensive and severely limits the applicability of this approach. Previous work [5, 19] has avoided this problem by interposing only on synchronization operations (and ignoring other variable accesses). We demonstrate that by using variable bounding (v) and a static imprecise alias analysis, we can interpose on all variable accesses (and not just synchronization operations) at 10-100x less overhead than previous approaches.
CHESS @cite_24 uses iterative context bounding to rank schedules. We borrow many ideas from CHESS, including iterative context bounding @cite_7 , using a happens-before graph for stateless model checking, and fair scheduling. We provide further ranking of schedules to uncover most bugs with a smaller number of schedules. While we consider all shared memory accesses as potential context-switch points, CHESS only allows pre-emptible context switches at explicit synchronization primitives. This restriction (first used in ExitBlock @cite_11 ) is justified if all shared memory accesses are protected by explicit synchronization (e.g., lock unlock ). CHESS relies on a data-race detector to separately check this property. Even if we assume a precise and efficient data-race detector, this approach still overlooks adhoc'' synchronization that do not involve known synchronization primitives @cite_17 .
@cite_24 @cite_17 @cite_7 @cite_11
178326370 2135948849 328544693
Many synchronizations in existing multi-threaded programs are implemented in an ad hoc way. The first part of this paper does a comprehensive characteristic study of ad hoc synchronizations in concurrent programs. By studying 229 ad hoc synchronizations in 12 programs of various types (server, desktop and scientific), including Apache, MySQL, Mozilla, etc., we find several interesting and perhaps alarming characteristics: (1) Every studied application uses ad hoc synchronizations. Specifically, there are 6-83 ad hoc synchronizations in each program. (2) Ad hoc synchronizations are error-prone. Significant percentages (22-67 ) of these ad hoc synchronizations introduced bugs or severe performance issues. (3) Ad hoc synchronization implementations are diverse and many of them cannot be easily recognized as synchronizations, i.e. have poor readability and maintainability. The second part of our work builds a tool called SyncFinder to automatically identify and annotate ad hoc synchronizations in concurrent programswritten in C C++ to assist programmers in porting their code to better structured implementations, while also enabling other tools to recognize them as synchronizations. Our evaluation using 25 concurrent programs shows that, on average, SyncFinder can automatically identify 96 of ad hoc synchronizations with 6 false positives. We also build two use cases to leverage SyncFinder's auto-annotation. The first one uses annotation to detect 5 deadlocks (including 2 new ones) and 16 potential issues missed by previous analysis tools in Apache, MySQL and Mozilla. The second use case reduces Valgrind data race checker's false positive rates by 43-86 . Multithreaded programs are difficult to get right because of unexpected interaction between concurrently executing threads. Traditional testing methods are inadequate for catching subtle concurrency errors which manifest themselves late in the development cycle and post-deployment. Model checking or systematic exploration of program behavior is a promising alternative to traditional testing methods. However, it is difficult to perform systematic search on large programs as the number of possible program behaviors grows exponentially with the program size. Confronted with this state-explosion problem, traditional model checkers perform iterative depth-bounded search. Although effective for message-passing software, iterative depth-bounding is inadequate for multithreaded software. This paper proposes iterative context-bounding, a new search algorithm that systematically explores the executions of a multithreaded program in an order that prioritizes executions with fewer context switches. We distinguish between preempting and nonpreempting context switches, and show that bounding the number of preempting context switches to a small number significantly alleviates the state explosion, without limiting the depth of explored executions. We show both theoretically and empirically that context-bounded search is an effective method for exploring the behaviors of multithreaded programs. We have implemented our algorithmin two model checkers and applied it to a number of real-world multithreaded programs. Our implementation uncovered 9 previously unknown bugs in our benchmarks, each of which was exposed by an execution with at most 2 preempting context switches. Our initial experience with the technique is encouraging and demonstrates that iterative context-bounding is a significant improvement over existing techniques for testing multithreaded programs. We present a practical testing algorithm called ExitBlock that systematically and deterministically nds program errors resulting from unintended timing dependencies. ExitBlock executes a program or a portion of a program on a given input multiple times, enumerating meaningful schedules in order to cover all program behaviors. Previous work on systematic testing focuses on programs whose concurrent elements are processes that run in separate memory spaces and explicitly declare what memory they will be sharing. ExitBlock extends previous approaches to multithreaded programs in which all of memory is potentially shared. A key challenge is to minimize the number of schedules executed while still guaranteeing to cover all behaviors. Our approach relies on the fact that for a program following a mutual-exclusion locking discipline, enumerating possible orders of the synchronized regions of the program covers all possible behaviors of the program. We describe in detail the basic algorithm and extensions to take advantage of readwrite dependency information and to detect deadlocks.