23 research outputs found
On Verifying Complex Properties using Symbolic Shape Analysis
One of the main challenges in the verification of software systems is the
analysis of unbounded data structures with dynamic memory allocation, such as
linked data structures and arrays. We describe Bohne, a new analysis for
verifying data structures. Bohne verifies data structure operations and shows
that 1) the operations preserve data structure invariants and 2) the operations
satisfy their specifications expressed in terms of changes to the set of
objects stored in the data structure. During the analysis, Bohne infers loop
invariants in the form of disjunctions of universally quantified Boolean
combinations of formulas. To synthesize loop invariants of this form, Bohne
uses a combination of decision procedures for Monadic Second-Order Logic over
trees, SMT-LIB decision procedures (currently CVC Lite), and an automated
reasoner within the Isabelle interactive theorem prover. This architecture
shows that synthesized loop invariants can serve as a useful communication
mechanism between different decision procedures. Using Bohne, we have verified
operations on data structures such as linked lists with iterators and back
pointers, trees with and without parent pointers, two-level skip lists, array
data structures, and sorted lists. We have deployed Bohne in the Hob and Jahob
data structure analysis systems, enabling us to combine Bohne with analyses of
data structure clients and apply it in the context of larger programs. This
report describes the Bohne algorithm as well as techniques that Bohne uses to
reduce the ammount of annotations and the running time of the analysis
Automated verification of shape, size and bag properties.
In recent years, separation logic has emerged as a contender for formal reasoning of heap-manipulating imperative programs. Recent works have focused on specialised provers that are mostly based on fixed sets of predicates. To improve expressivity, we have proposed a prover that can automatically handle user-defined predicates. These shape predicates allow programmers to describe a wide range of data structures with their associated size properties. In the current work, we shall enhance this prover by providing support for a new type of constraints, namely bag (multi-set) constraints. With this extension, we can capture the reachable nodes (or values) inside a heap predicate as a bag constraint. Consequently, we are able to prove properties about the actual values stored inside a data structure
A Logic of Reachable Patterns in Linked Data-Structures
We define a new decidable logic for expressing and checking invariants of
programs that manipulate dynamically-allocated objects via pointers and
destructive pointer updates. The main feature of this logic is the ability to
limit the neighborhood of a node that is reachable via a regular expression
from a designated node. The logic is closed under boolean operations
(entailment, negation) and has a finite model property. The key technical
result is the proof of decidability. We show how to express precondition,
postconditions, and loop invariants for some interesting programs. It is also
possible to express properties such as disjointness of data-structures, and
low-level heap mutations. Moreover, our logic can express properties of
arbitrary data-structures and of an arbitrary number of pointer fields. The
latter provides a way to naturally specify postconditions that relate the
fields on entry to a procedure to the fields on exit. Therefore, it is possible
to use the logic to automatically prove partial correctness of programs
performing low-level heap mutations
Shape Analysis via Monotonic Abstraction
We propose a new formalism for reasoning about dynamic memory heaps, using monotonic abstraction and symbolic backward reachability analysis. We represent the heaps as graphs, and introduce an ordering on these graphs. This enables us to represent the violation of a given safety property as the reachability of a finitely representable set of bad graphs. We also describe how to symbolically compute the reachable states in the transition system induced by a program
Bounded Quantifier Instantiation for Checking Inductive Invariants
We consider the problem of checking whether a proposed invariant
expressed in first-order logic with quantifier alternation is inductive, i.e.
preserved by a piece of code. While the problem is undecidable, modern SMT
solvers can sometimes solve it automatically. However, they employ powerful
quantifier instantiation methods that may diverge, especially when is
not preserved. A notable difficulty arises due to counterexamples of infinite
size.
This paper studies Bounded-Horizon instantiation, a natural method for
guaranteeing the termination of SMT solvers. The method bounds the depth of
terms used in the quantifier instantiation process. We show that this method is
surprisingly powerful for checking quantified invariants in uninterpreted
domains. Furthermore, by producing partial models it can help the user diagnose
the case when is not inductive, especially when the underlying reason
is the existence of infinite counterexamples.
Our main technical result is that Bounded-Horizon is at least as powerful as
instrumentation, which is a manual method to guarantee convergence of the
solver by modifying the program so that it admits a purely universal invariant.
We show that with a bound of 1 we can simulate a natural class of
instrumentations, without the need to modify the code and in a fully automatic
way. We also report on a prototype implementation on top of Z3, which we used
to verify several examples by Bounded-Horizon of bound 1
Automata-Based Termination Proofs
This paper describes our generic framework for detecting termination of programs handling infinite and complex data domains, such as pointer structures. The framework is based on a counterexample-driven abstraction refinement loop. We have instantiated the framework for programs handling tree-like data structures, which allowed us to prove automatically termination of programs such as the depth-first tree traversal, the Deutsch-Schorr-Waite tree traversal, or the linking leaves algorithm
Simulating reachability using first-order logic with applications to verification of linked data structures
This paper shows how to harness existing theorem provers for first-order
logic to automatically verify safety properties of imperative programs that
perform dynamic storage allocation and destructive updating of pointer-valued
structure fields. One of the main obstacles is specifying and proving the
(absence) of reachability properties among dynamically allocated cells.
The main technical contributions are methods for simulating reachability in a
conservative way using first-order formulas--the formulas describe a superset
of the set of program states that would be specified if one had a precise way
to express reachability. These methods are employed for semi-automatic program
verification (i.e., using programmer-supplied loop invariants) on programs such
as mark-and-sweep garbage collection and destructive reversal of a singly
linked list. (The mark-and-sweep example has been previously reported as being
beyond the capabilities of ESC/Java.)Comment: 30 pages, LMC