Results 1 - 10
of
24
Static and precise detection of concurrency errors in systems code using SMT solvers
- In CAV
, 2009
"... Abstract. Context-bounded analysis is an attractive approach to verification of concurrent programs. Bounding the number of contexts executed per thread not only reduces the asymptotic complexity, but also the complexity increases gradually from checking a purely sequential program. Lal and Reps [14 ..."
Abstract
-
Cited by 19 (4 self)
- Add to MetaCart
Abstract. Context-bounded analysis is an attractive approach to verification of concurrent programs. Bounding the number of contexts executed per thread not only reduces the asymptotic complexity, but also the complexity increases gradually from checking a purely sequential program. Lal and Reps [14] provided a method for reducing the context-bounded verification of a concurrent boolean program to the verification of a sequential boolean program, thereby allowing sequential reasoning to be employed for verifying concurrent programs. In this work, we adapt the encoding to work for systems programs written in C with the heap and accompanying low-level operations such as pointer arithmetic and casts. Our approach is completely automatic: we use a verification condition generator and SMT solvers, instead of a boolean model checker, in order to avoid manual extraction of boolean programs and false alarms introduced by the abstraction. We demonstrate the use of field slicing for improving the scalability and (in some cases) coverage of our checking. We evaluate our tool STORM on a set of real-world Windows device drivers, and has discovered a bug that could not be detected by extensive application of previous tools. 1
A Precise Yet Efficient Memory Model For C
, 2008
"... Verification for OO programs typically starts from a strongly typed object model in which distinct objects/fields are guaranteed not to overlap. This model simplifies verification by eliminating all “uninteresting” aliasing and allowing the use of more efficient frame axioms. Unfortunately, this mod ..."
Abstract
-
Cited by 12 (9 self)
- Add to MetaCart
Verification for OO programs typically starts from a strongly typed object model in which distinct objects/fields are guaranteed not to overlap. This model simplifies verification by eliminating all “uninteresting” aliasing and allowing the use of more efficient frame axioms. Unfortunately, this model is unsound and incomplete for languages like C, where “objects ” can overlap almost arbitrarily. Sound verification for C therefore typically starts from an untyped memory model, where memory is just an array of bytes). The untyped model, however, adds substantial annotation burden, and reasoning in the untyped model is computationally expensive. We propose a sound typed semantics for C that provides the annotational and computational advantages of the typed object model while remaining sound and complete for C. We maintain in ghost state a predicate identifying where the “valid ” objects are, and introduce invariants and proof obligations that guarantee that the valid objects are suitably antialiased, and that (almost) all objects appearing in the program are valid. We describe the implementation of this approach in VCC (a sound verifier for C being used to verify the Microsoft Hypervisor) and the resulting performance gains.
A scalable memory model for low-level code
- In Conf. on Verification, Model Checking and Abstract Interpretation (VMCAI
, 2009
"... Abstract. Because of its critical importance underlying all other software, lowlevel system software is among the most important targets for formal verification. Low-level systems software must sometimes make type-unsafe memory accesses, but because of the vast size of available heap memory in today ..."
Abstract
-
Cited by 6 (2 self)
- Add to MetaCart
Abstract. Because of its critical importance underlying all other software, lowlevel system software is among the most important targets for formal verification. Low-level systems software must sometimes make type-unsafe memory accesses, but because of the vast size of available heap memory in today’s computer systems, faithfully representing each memory allocation and access does not scale when analyzing large programs. Instead, verification tools rely on abstract memory models to represent the program heap. This paper reports on two related investigations to develop an accurate (i.e., providing a useful level of soundness and precision) and scalable memory model: First, we compare a recently introduced memory model, specifically designed to more accurately model low-level memory accesses in systems code, to an older, widely adopted memory model. Unfortunately, we find that the newer memory model scales poorly compared to the earlier, less accurate model. Next, we investigate how to improve the soundness of the less accurate model. A direct approach is to add assertions to the code that each memory access does not break the assumptions of the memory model, but this causes verification complexity to blow-up. Instead, we develop a novel, extremely lightweight static analysis that quickly and conservatively guarantees that most memory accesses safely respect the assumptions of the memory model, thereby eliminating almost all of these extra type-checking assertions. Furthermore, this analysis allows us to create automatically memory models that flexibly use the more scalable memory model for most of memory, but resorting to a more accurate model for memory accesses that might need it. 1
Low-Level Liquid Types ∗
"... We present Low-Level Liquid Types, a refinement type system for C based on Liquid Types. Low-Level Liquid Types combine refinement types with three key elements to automate verification of critical safety properties of low-level programs: First, by associating refinement types with individual heap l ..."
Abstract
-
Cited by 4 (3 self)
- Add to MetaCart
We present Low-Level Liquid Types, a refinement type system for C based on Liquid Types. Low-Level Liquid Types combine refinement types with three key elements to automate verification of critical safety properties of low-level programs: First, by associating refinement types with individual heap locations and precisely tracking the locations referenced by pointers, our system is able to reason about complex invariants of in-memory data structures and sophisticated uses of pointer arithmetic. Second, by adding constructs which allow strong updates to the types of heap locations, even in the presence of aliasing, our system is able to verify properties of in-memory data structures in spite of temporary invariant violations. By using this strong update mechanism, our system is able to verify the correct initialization of newly-allocated regions of memory. Third, by using the abstract interpretation framework of Liquid Types, we are able to use refinement type inference to automatically verify important safety properties without imposing an onerous annotation burden. We have implemented our approach in CSOLVE, a tool for Low-Level Liquid Type inference for C programs. We demonstrate through several examples that CSOLVE is able to precisely infer complex invariants required to verify important safety properties, like the absence of array bounds violations and null-dereferences, with a minimal annotation overhead.
Intra-module inference
- In Computer-Aided Verification (CAV ’09), LNCS
"... Abstract. Contract-based property checkers hold the potential for precise, scalable, and incremental reasoning. However, it is difficult to apply such checkers to large program modules because they require programmers to provide detailed contracts, including an interface specification, module invari ..."
Abstract
-
Cited by 3 (2 self)
- Add to MetaCart
Abstract. Contract-based property checkers hold the potential for precise, scalable, and incremental reasoning. However, it is difficult to apply such checkers to large program modules because they require programmers to provide detailed contracts, including an interface specification, module invariants, and internal specifications. We argue that given a suitably rich assertion language, modest effort suffices to document the interface specification and the module invariants. However, the burden of providing internal specifications is still significant and remains a deterrent to the use of contract-based checkers. Therefore, we consider the problem of intra-module inference, which aims to infer annotations for internal procedures and loops, given the interface specification and the module invariants. We provide simple and scalable techniques to search for a broad class of desired internal annotations, comprising quantifiers and Boolean connectives, guided by the module specification. We have validated our ideas by building a prototype verifier and using it to verify several properties on Windows device drivers with zero false alarms and small annotation overhead. These drivers are complex; they contain thousands of lines and use dynamic data structures such as linked lists and arrays. Our technique significantly improves the soundness, precision, and coverage of verification of these programs compared to earlier techniques. 1
Separating Shape Graphs
"... Abstract. Detailed memory models that expose individual fields are necessary to precisely analyze code that makes use of low-level aspects such as, pointers to fields and untagged unions. Yet, higher-level representations that collect fields into records are often used because they are typically mor ..."
Abstract
-
Cited by 3 (3 self)
- Add to MetaCart
Abstract. Detailed memory models that expose individual fields are necessary to precisely analyze code that makes use of low-level aspects such as, pointers to fields and untagged unions. Yet, higher-level representations that collect fields into records are often used because they are typically more convenient and efficient in modeling the program heap. In this paper, we present a shape graph representation of memory that exposes individual fields while largely retaining the convenience of an object-level model. This representation has a close connection to particular kinds of formulas in separation logic. Then, with this representation, we show how to extend the Xisa shape analyzer for low-level aspects, including pointers to fields, C-style nested structures and unions, malloc and free, and array values, with minimal changes to the core algorithms (e.g., materialization and summarization). 1
Shape Analysis of Low-level C with Overlapping Structures
"... Abstract. Device drivers often keep data in multiple data structures simultaneously while embedding list or tree related records into the records containing the actual data; this results in overlapping structures. Shape analyses have traditionally relied on a graph-based representation of memory whe ..."
Abstract
-
Cited by 3 (0 self)
- Add to MetaCart
Abstract. Device drivers often keep data in multiple data structures simultaneously while embedding list or tree related records into the records containing the actual data; this results in overlapping structures. Shape analyses have traditionally relied on a graph-based representation of memory where a node corresponds to a whole record and edges to pointers. As this is ill-suited for encoding overlapping structures, we propose and formally relate two refined memory models. We demonstrate the appropriateness of these models by implementing shape analyses based on them within the TVLA framework. The implementation is exemplified using code extracted from cache managing kernel modules. 1
Conditional equivalence
, 2010
"... A typical software module evolves through many versions over the course of its development. To maintain compatibility with module clients, it is crucial that a module’s behavior at its interface does not change in an undesirable manner across versions. The problem of introducing changes which break ..."
Abstract
-
Cited by 3 (1 self)
- Add to MetaCart
A typical software module evolves through many versions over the course of its development. To maintain compatibility with module clients, it is crucial that a module’s behavior at its interface does not change in an undesirable manner across versions. The problem of introducing changes which break interface behavior remains one of the most daunting challenges in the maintenance of large software modules. Static equivalence checking of sequential programs is a useful mechanism to validate semantic equivalence across refactoring changes. However, most changes corresponding to bug fixes and feature additions change the behavior of programs; equivalence checking tools are of limited help in such cases. In this work, we propose the notion of conditional (partial) equivalence, a more practical notion of equivalence in which two versions of a program need only be semantically equivalent under a subset of all inputs. We provide a compositional method for checking conditional domain for synthesizing non-trivial conditions under which two programs are equivalent. Additionally, we propose a method called differential inlining to lazily construct summaries of behavioral differences along differential paths interprocedurally, for recursionfree programs. We discuss preliminary experience of a prototype implementation on a set of medium sized C benchmarks.
Complexity and algorithms for monomial and clausal predicate abstraction
- In CADE
, 2009
"... Abstract. In this paper, we investigate the asymptotic complexity of various predicate abstraction problems relative to the asymptotic complexity of checking an annotated program in a given assertion logic. Unlike previous approaches, we pose the predicate abstraction problem as a decision problem, ..."
Abstract
-
Cited by 2 (1 self)
- Add to MetaCart
Abstract. In this paper, we investigate the asymptotic complexity of various predicate abstraction problems relative to the asymptotic complexity of checking an annotated program in a given assertion logic. Unlike previous approaches, we pose the predicate abstraction problem as a decision problem, instead of the traditional inference problem. For assertion logics closed under weakest (liberal) precondition and Boolean connectives, we show two restrictions of the predicate abstraction problem where the two complexities match. The restrictions correspond to the case of monomial and clausal abstraction. For these restrictions, we show a symbolic encoding that reduces the predicate abstraction problem to checking the satisfiability of a single formula whose size is polynomial in the size of the program and the set of predicates. We also provide a new iterative algorithm for solving the clausal abstraction problem that can be seen as the dual of the Houdini algorithm for solving the monomial abstraction problem. 1
Z3 10: Applications, Enablers, Challenges and Directions
"... Abstract. Modern program analysis and model-based tools are increasingly complex and multi-faceted software systems. However, at their core is invariably a component using a logic for describing states and transformations between system states. Logic inferences engines are then critical for the func ..."
Abstract
-
Cited by 1 (0 self)
- Add to MetaCart
Abstract. Modern program analysis and model-based tools are increasingly complex and multi-faceted software systems. However, at their core is invariably a component using a logic for describing states and transformations between system states. Logic inferences engines are then critical for the functionality of these systems. A commonly adapted approach has been to use a custom solver, built and tailored for the specific application. Custom solvers come with custom limitations: extending and scaling these often require a high investment. Taking as a starting point the solver Z3, developed at Microsoft Research; we describe how an efficient, scalable and expressive solver for Satisfiability Modulo Theories (SMT) is part of changing this landscape. Tools can now use the SMT solver with advantage to solve logic-related problems at a relatively highlevel of abstraction while attaining scalability and features that custom solvers would have to duplicate. We summarize 10 current applications of the Z3 solver and relate these to 10 main technological enabling factors. With every application there is a new opportunity, and with every solution there is a new challenge problem. Thus, we also summarize 10 challenges and 10 aspiring directions in the context of Z3 in particular, and for SMT solvers in general. 1

