Keywords

These keywords were added by machine and not by the authors. This process is experimental and the keywords may be updated as the learning algorithm improves.

1 Verification Approach

Ultimate Automizer is a software verifier of the Ultimate program analysis frameworkFootnote 1. The tool implements the automata-theoretic verification approach [3, 4] that is outlined in Fig. 1 and is able to analyze reachability of error functions, memory safety, absence of overflows and termination. In this section, we briefly explain the overall algorithm and discuss a feature that speeded up the tool significantly, namely the on-demand construction of Floyd-Hoare automata, in detail.

Fig. 1.
figure 1

Overall verification algorithm

We initially construct an automaton, called control flow automaton (CFA), that resembles the control flow graph and whose acceptance condition reflects the property that is checked. E.g., for reachability problems, the error location of the program is the accepting state of the CFA. The alphabet \(\varSigma \) of the CFA consists of all program statements that occur in the control flow graph. We call a word over the alphabet \(\varSigma \) a trace and a word that is accepted by the CFA an error trace. The input program violates the given property if and only if there exists a feasible error trace, i.e., an error trace that corresponds to a real program execution. In our algorithm we construct automata \(\mathcal {A}^\mathsf {abs}_i\) that overapproximate the set of feasible error traces. Our initial abstraction \(\mathcal {A}^\mathsf {abs}_0\) is the CFA. All subsequent abstractions \(\mathcal {A}^\mathsf {abs}_i\) are constructed in a CEGAR-style refinement loop (depicted in Fig. 1).

A central step of this algorithm is the construction of the automaton \(\mathcal {A}^\mathsf {fh}_i\) in line 8. This automaton defines the set of (spurious) error traces that are eliminated in the current iteration. If this automaton accepts only few traces, the overall algorithm is more likely to diverge. For soundness, we require that \(\mathcal {A}^\mathsf {fh}_i\) does not accept any feasible error trace. To account for that we construct \(\mathcal {A}^\mathsf {fh}_i\) as a Floyd-Hoare automaton [4] which is a kind of automaton over the alphabet of program statements that accepts only infeasible traces. More details on the construction are given below.

Construction of Difference. In line 9 of the algorithm we construct a new abstraction for the set of feasible error traces. This new abstraction is an automaton \(\mathcal {A}^\mathsf {abs}_{i+1}\) whose set of traces is the set-theoretic difference of the traces from the old abstraction \(\mathcal {A}^\mathsf {abs}_{i}\) and the traces from the Floyd-Hoare automaton \(\mathcal {A}^\mathsf {fh}_i\). The automaton \(\mathcal {A}^\mathsf {fh}_i\) is deterministic and total. We construct \(\mathcal {A}^\mathsf {abs}_{i+1}\) as the product automaton of \(\mathcal {A}^\mathsf {abs}_{i}\) and \(\mathcal {A}^\mathsf {fh}_i\) where a state of the product is accepting iff its first component is accepting and the second component is not accepting. In our implementation, we construct this product incrementally. We start with the initial state of the product and construct successively all reachable states and transitions. This allows us to construct the Floyd-Hoare automaton \(\mathcal {A}^\mathsf {fh}_i\) on-demand as we explain next.

Fig. 2.
figure 2

Definition of Floyd-Hoare automaton for i-th iteration

On-Demand Construction of Floyd-Hoare Automata. The input for the construction is a set of predicates \(\mathsf {Pred}\). We obtain this set by computing sequences of interpolants along infeasible error traces. Conceptually, the Floyd-Hoare automaton \(\mathcal {A}^\mathsf {fh}_i\) is the automaton (defined in Fig. 2) whose states are the input predicates and all conjunctions of the input predicates. By construction, this automaton accepts only infeasible traces.

Usually, the automaton \(\mathcal {A}^\mathsf {abs}_{i}\) is very sparse and hence only few transitions of \(\mathcal {A}^\mathsf {fh}_i\) contribute to the difference operation (line 9). Since we construct the reachable state-space of the difference incrementally, we can construct the Floyd-Hoare automaton \(\mathcal {A}^\mathsf {fh}_i\) on-demand. At the beginning, we construct only the initial state. Whenever the difference operation asks for successors of a state \(\varphi \) under a symbol \({s\!t}\), we check if this transition was already added. If not, we compute the successor state and add transition and successor state if necessary. The successor state is the conjunction of all input predicates \(p\in \mathsf {Pred}\) such that the Hoare triple \(\{\varphi \}{s\!t}\{p\}\) is valid.

Checking Hoare Triples Using a Cache and Unified Predicates. We can check Hoare triples using an SMT solver. However, these calls to an SMT solver can be costly and we try to reduce their number as follows. First, we keep a cache in which we store for each Hoare triple that has been checked so far whether it was valid or not. In order to have only one representative for logically equivalent predicates, we unify all predicates and all conjunctions of predicates that were constructed as states of the Floyd-Hoare automaton \(\mathcal {A}^\mathsf {fh}_i\). In this unification process, we check for all pairs of formulas \(\varphi ,\psi \) whether the implications \(\varphi \,\models \,\psi \) and \(\psi \,\models \,\varphi \) hold and store the results. If we now have to check the validity of a Hoare triple, we first check if one of the rules depicted in Fig. 3 is applicable. Only if none of these rules is applicable we use an SMT solver for the Hoare triple check.

Fig. 3.
figure 3

Rules that allow us to infer validity of Hoare triples without calling an SMT solver. The set \(\mathsf {vars}(\varphi )\) contains all variables that occur in the formula \(\varphi \), the sets \(\mathsf {read}({s\!t})\) and \(\mathsf {write}({s\!t})\) contain all variables that are read (resp. written) by the statement \({s\!t}\).

2 Software Architecture

Ultimate Automizer uses several SMT solvers. For the unification of predicates, the simplification of formulas and the Hoare triple checks we use Z3Footnote 2 because this solver can handle several SMT theories in combination with quantifiers. For the analysis of error traces we use CVC4Footnote 3, MathSATFootnote 4, SMTInterpolFootnote 5, and Z3. These solvers each provide interpolants or unsatisfiable cores, which both can be used by Ultimate to extract predicates from infeasible traces. Furthermore, Ultimate Automizer uses several components of the Ultimate program analysis framework. The termination analysis is performed by the Buchi Automizer [5] component. This component requires ranking functions [6] and nontermination arguments [7] which are provided by LassoRanker Footnote 6. LassoRanker uses SMTInterpol for the synthesis of ranking functions and Z3 for the synthesis of nontermination arguments. For our interprocedural analysis, we use nested word automata; in the termination analysis these automata have a Büchi acceptance condition. Data structures and algorithms for these automata are provided by the Automata Library. Ultimate also provides support for violation witnesses [2] and correctness witnesses [1]. Our competition candidate is able to produce and to validate both kinds of witnessesFootnote 7.

3 Tool Setup and Configuration

A zip archive that contains the tool and all above mentioned SMT solvers is available at the website of Ultimate Automizer Footnote 8. The tool can be started by the following command,

./Ultimate.py prop.prp inputfile 32bit|64bit simple|precise

where Ultimate.py is a Python script, prop.prp the SV-COMP property file, and inputfile a C program. The other parameters determine the architecture and the memory model, respectively.

4 Software Project

The Ultimate program analysis framework is mainly developed at the University of Freiburg and received contributions from more than 50 people. The framework is written in Java and the source code is available on GithubFootnote 9.