39 research outputs found
Software Model Checking with Explicit Scheduler and Symbolic Threads
In many practical application domains, the software is organized into a set
of threads, whose activation is exclusive and controlled by a cooperative
scheduling policy: threads execute, without any interruption, until they either
terminate or yield the control explicitly to the scheduler. The formal
verification of such software poses significant challenges. On the one side,
each thread may have infinite state space, and might call for abstraction. On
the other side, the scheduling policy is often important for correctness, and
an approach based on abstracting the scheduler may result in loss of precision
and false positives. Unfortunately, the translation of the problem into a
purely sequential software model checking problem turns out to be highly
inefficient for the available technologies. We propose a software model
checking technique that exploits the intrinsic structure of these programs.
Each thread is translated into a separate sequential program and explored
symbolically with lazy abstraction, while the overall verification is
orchestrated by the direct execution of the scheduler. The approach is
optimized by filtering the exploration of the scheduler with the integration of
partial-order reduction. The technique, called ESST (Explicit Scheduler,
Symbolic Threads) has been implemented and experimentally evaluated on a
significant set of benchmarks. The results demonstrate that ESST technique is
way more effective than software model checking applied to the sequentialized
programs, and that partial-order reduction can lead to further performance
improvements.Comment: 40 pages, 10 figures, accepted for publication in journal of logical
methods in computer scienc
Separating computation from communication: a design approach for concurrent program verification
We describe an approach to design static analysis and verification tools for concurrent programs that separates intra-thread computation from inter-thread communication by means of a shared memory abstraction (SMA). We formally characterize the concept of thread-asynchronous transition systems that underpins our approach and that allows us to design tools as two independent components, the intra-thread analysis, which can be optimized separately, and the implementation of the SMA itself, which can be exchanged easily (e.g., from the SC to the TSO memory model). We describe the SMA’s API and show that several concurrent verification techniques from the literature can easily be recast in our setting and thus be extended to weak memory models. We give SMA implementations for the SC, TSO, and PSO memory models that are based on the idea of individual memory unwindings. We instantiate our approach by developing a new, efficient BMC-based bug finding tool for multi-threaded C programs under SC, TSO, or PSO based on these SMAs, and show experimentally that it is competitive to existing tools
Embedding weak memory models within eager sequentialization
Sequentialization is one of the most promising approaches for the symbolic analysis of concurrent programs. However, existing sequentializations assume sequential consistency, which modern hardware architectures no longer guarantee. In this paper we describe an approach to embed weak memory models within eager sequentializations (a la Lal/Reps). Our approach is based on the separation of intra-thread computations from inter-thread communications by means of a shared memory abstraction (SMA). We give details of SMA implementations for the SC, TSO, and PSO memory models that are based on the idea of individual memory unwindings, and sketch an extension to the Power memory model. We use our approach to implement a new, efficient BMC-based bug finding tool for multi-threaded C programs under SC, TSO, or PSO based on these SMAs, and show experimentally that it is competitive to existing tools
Lazy-CSeq-SP: Boosting Sequentialization-Based Verification of Multi-threaded C Programs via Symbolic Pruning of Redundant Schedules
Abstract. Sequentialization has been shown to be an effective symbolic verification technique for concurrent C programs using POSIX threads. Lazy-CSeq, a tool that applies a lazy sequentialization scheme, has won the Concurrency division of the last two editions of the Competition on Software Verification. The tool encodes all thread schedules up to a given bound into a single non-deterministic sequential C program and then invokes a C model checker. This paper presents a novel optimized imple-mentation of lazy sequentialization, which integrates symbolic pruning of redundant schedules into the encoding. Experimental evaluation shows that our tool outperforms Lazy-CSeq significantly on many benchmarks
IST Austria Thesis
Designing and verifying concurrent programs is a notoriously challenging, time consuming, and error prone task, even for experts. This is due to the sheer number of possible interleavings of a concurrent program, all of which have to be tracked and accounted for in a formal proof. Inventing an inductive invariant that captures all interleavings of a low-level implementation is theoretically possible, but practically intractable. We develop a refinement-based verification framework that provides mechanisms to simplify proof construction by decomposing the verification task into smaller subtasks.
In a first line of work, we present a foundation for refinement reasoning over structured concurrent programs. We introduce layered concurrent programs as a compact notation to represent multi-layer refinement proofs. A layered concurrent program specifies a sequence of connected concurrent programs, from most concrete to most abstract, such that common parts of different programs are written exactly once. Each program in this sequence is expressed as structured concurrent program, i.e., a program over (potentially recursive) procedures, imperative control flow, gated atomic actions, structured parallelism, and asynchronous concurrency. This is in contrast to existing refinement-based verifiers, which represent concurrent systems as flat transition relations. We present a powerful refinement proof rule that decomposes refinement checking over structured programs into modular verification conditions. Refinement checking is supported by a new form of modular, parameterized invariants, called yield invariants, and a linear permission system to enhance local reasoning.
In a second line of work, we present two new reduction-based program transformations that target asynchronous programs. These transformations reduce the number of interleavings that need to be considered, thus reducing the complexity of invariants. Synchronization simplifies the verification of asynchronous programs by introducing the fiction, for proof purposes, that asynchronous operations complete synchronously. Synchronization summarizes an asynchronous computation as immediate atomic effect. Inductive sequentialization establishes sequential reductions that captures every behavior of the original program up to reordering of coarse-grained commutative actions. A sequential reduction of a concurrent program is easy to reason about since it corresponds to a simple execution of the program in an idealized synchronous environment, where processes act in a fixed order and at the same speed.
Our approach is implemented the CIVL verifier, which has been successfully used for the verification of several complex concurrent programs. In our methodology, the overall correctness of a program is established piecemeal by focusing on the invariant required for each refinement step separately. While the programmer does the creative work of specifying the chain of programs and the inductive invariant justifying each link in the chain, the tool automatically constructs the verification conditions underlying each refinement step
Verification and Enforcement of Safe Schedules for Concurrent Programs
Automated software verification can prove the correctness of a
program with respect to a given specification and may be a valuable
support in the difficult task of ensuring the quality of large
software systems. However, the automated verification of concurrent
software can be particularly challenging due to the vast complexity
that non-deterministic scheduling causes.
This thesis is concerned with techniques that reduce the complexity
of concurrent programs in order to ease the verification task. We
approach this problem from two orthogonal directions: state space
reduction and reduction of non-determinism in executions of
concurrent programs.
Following the former direction, we present an algorithm for dynamic
partial-order reduction, a state space reduction technique that
avoids the verification of redundant executions. Our algorithm,
EPOR, eagerly creates schedules for program fragments. In
comparison to other dynamic partial-order reduction algorithms, it
avoids redundant race and dependency checks. Our experiments show
that EPOR runs considerably faster than a state-of-the-art
algorithm, which allows in several cases to analyze programs with a
higher number of threads within a given timeout.
In the latter direction, we present a formal framework for using
incomplete verification results to extract safe schedulers. As
incomplete verification results do not need to proof the correctness
of all possible executions of a program, their complexity can be
significantly lower than complete verification results. Hence, they
can be faster obtained. We constrain the scheduling of programs but
not their inputs in order to preserve their full functionality. In
our framework, executions under the scheduling constraints of an
incomplete verification result are safe, deadlock-free, and fair. We
instantiate our framework with the Impact model checking algorithm
and find in our evaluation that it can be used to model check
programs that are intractable for monolithic model checkers,
synthesize synchronization via assume statements, and
guarantee fair executions.
In order to safely execute a program within the set of executions
covered by an incomplete verification, scheduling needs to be
constrained. We discuss how to extract and encode schedules from
incomplete verification results, for both finite and infinite
executions, and how to efficiently enforce scheduling constraints,
both in terms of reducing the time to look up permission of
executing the next event and executing independent events
concurrently (by applying partial-order reduction).
A drawback of enforcing scheduling constraints is a potential
overhead in the execution time. However, in several cases,
constrained executions turned out to be even faster than
unconstrained executions. Our experimental results show that
iteratively relaxing a schedule can significantly reduce this
overhead. Hence, it is possible to adjust the incurred execution
time overhead in order to find a sweet spot with respect to the
amount of effort for creating schedules (i.e., the duration of
verification). Interestingly, we found cases in which a much earlier
reduction of execution time overhead is obtained by choosing
favorable scheduling constraints, which suggests that execution time
performance does not simply rely on the number of scheduling
constraints but to a large extend also on their structure