1 Verification Approach

Bounded model checking [3] verifies programs up to a finite execution length. Hence it can find errors effectively but not prove properties. To overcome this limitation, we present a tool called VeriAbs that implements a loop abstraction technique to transform a source C program to an abstract program called a target. By this, loops in the source are replaced with abstract loops of small known bounds in the target. Due to the known bounds of the abstract loops, the target has a finite execution length and bounded model checking can then prove properties over this program. The following two techniques are applied to abstract loops in the source:

Numerical Loop Abstraction. VeriAbs abstracts a loop by over-approximating the values of numerical variables modified by that loop [5]. The variables modified by a loop are called output variables and are classified as (i) input-output (IO) - variables that are read and modified in the loop body, and (ii) pure output (PO) - variables that are modified but never read in the loop body. We explain the abstraction of outputs as follows.

The IO variables are abstracted using abstract acceleration [5] which captures the effect of several loop iterations. It comprises of assignments to all IO variables using closed form expressions, like those computed for recurrence relations. This generates an abstraction of the IO variables at the start of a non-deterministically chosen \(k^{th}\) iteration of the loop. VeriAbs then executes the loop body to generate an abstraction of the IO variables at the end of the \(k^{th}\) iteration. A pure output on the other hand cannot be accelerated, as it is never read in the loop body but only modified through assignments. So to abstract one pure output, VeriAbs non-deterministically selects and executes an iteration that assigns to the pure output. Before executing this iteration VeriAbs applies abstract acceleration to the IO variables. Executing the loop body in this manner abstracts the pure output because all variables controlling the execution of the assignment to the pure output or read in the assignment to the pure output were abstracted using acceleration. So to abstract all outputs of a loop, VeriAbs applies abstract acceleration followed by loop body execution, then repeats this as many times as the number of pure outputs. This generates an abstract loop of a known small bound.

To improve precision, VeriAbs applies induction whenever the input property lies within the loop [5]. The base case of the induction consists of the original loop body with the property check; and the induction step consists of the abstract loop assuming the property holds (the induction hypothesis), followed by the original loop body with the property check. VeriAbs extends this to incremental k-induction in order to refine the abstraction as explained in Sect. 1.1. VeriAbs for the first time implements k-induction wherein the induction hypothesis is generated using numerical loop abstraction. This technique can lead to a better precision than others which only assign non-deterministic values to the outputs in the hypothesis. VeriAbs also generates loop invariants using a light weight value analysis [8]. These invariants are further strengthened by loop abstraction and k-induction.

Array Loop Abstraction. The abstraction differs for loops that process arrays of large or unknown sizes [9]. In such cases, the abstraction over-approximates the behavior of the original program by substituting the loop with an abstract loop that executes over a small non-deterministically chosen sequence of array elements. We call this chosen sequence as a witness sequence of the original loop. The witness sequence guides the abstract loop to execute iterations that correspond to specific iterations of the original loop. This abstraction ensures that if the program is incorrect, the abstract program will also be incorrect and the same will be demonstrated by some witness sequence. The size of witness sequence depends on the input property and loop body characteristics.

1.1 Verification Process

VeriAbs accepts C code with user defined properties and outputs its verification result as successful (if all properties hold), failure (if any property fails), or unknown (if any property is unresolved). For this, VeriAbs first transforms the source to generate a target with abstract arrays and loops of known small bounds. Since the target is an over-approximation of the source, if the property holds in the target, it holds in the source as well. VeriAbs verifies the input property using the following steps:

  • Step 1: It passes the target to a bounded model checker while ensuring that each loop in the target is unrolled up to its known small bound. So if the model checker proves the property, VeriAbs reports the verification status as successful. If it generates a counter example due to over-approximation, Step 2 is executed.

  • Step 2: In this step, VeriAbs computes bounds of loops which have a constant number of iterations in the source. For this it uses a light weight value analysis [8]. Then the source along with these bounds are passed to the bounded model checker while ensuring that the model checker is inconclusive if any loop is not unrolled up to its maximum bound. Accordingly, VeriAbs reports the verification status if the model checker is able to (in)validate the property. If the model checker is inconclusive due to loops of unknown or infinite bounds, Step 3 is executed.

  • Step 3: In this step, VeriAbs iteratively refines the target by incrementally applying k-induction to the loops in which the input property lies. k-induction implemented by VeriAbs consists of k base cases of the original loop followed by the induction step as explained in Sect. 1. In each refinement iteration, VeriAbs generates a target with an incremented value of k starting from 2. It then passes this abstraction to the bounded model checker while ensuring that each abstract loop is unrolled up to its known bound. Thus VeriAbs reports the verification status as successful if the model checker proves the property. Otherwise it continues to refine the target till the property is proved or k reaches a threshold value of 150 (chosen heuristically) and the property remains unresolved.

VeriAbs generates safety witnesses from the target, and violation witnesses from the source using an off-the-shelf witness generator.

Fig. 1.
figure 1

The architecture of VeriAbs

2 Software Architecture

Figure 1 shows the architecture of VeriAbs. It implements a static analysis in Java to perform loop and array abstraction, compute loop bounds, and generate target code. It uses a program analysis framework called PRISM [7] to implement this analysis. It implements iterative refinement in Java and Perl. It uses the C Bounded Model Checker (CBMC) version 5.4 [4] with a SAT solver, MiniSat version 2.2 [6]. It uses CPAchecker version 1.6.1 [2] for generating witnesses in the graphml format.

3 Strengths and Weaknesses

The main strength of VeriAbs is that it is sound. All transformations implemented by the tool are abstractions and hence if the tool reports that a property holds then it indeed holds. Another key strength is that it transforms all loops in a program to abstract loops with a known finite number of iterations, enabling the use of bounded model checkers for property proving. The main weakness of the tool is that it does not implement a refinement process that is well suited to find errors. VeriAbs uses bounded model checkers directly to find errors by unrolling loops a small finite number of times.

4 Tool Setup and Configuration

The VeriAbs executable for SV-COMP 2017 is available for download at the URL http://115.113.148.49/VeriAbs.htm. To install the tool, download the archive, extract its contents, and follow the installation instructions in VeriAbs/INSTALL.txt. To execute VeriAbs, the user needs to specify the property file of the respective verification category using the property-file option. The witness is generated in the current working directory as witness.graphml. A sample command is as follows:

VeriAbs executes CBMC with the unwinding-assertions option to ensure soundness. It is participating in the Arrays, ControlFlow, ECA, Loops, ProductLines, Recursive and Sequentialized sub-categories of the ReachSafety category.

5 Software Project and Contributors

VeriAbs and the PRISM program analysis framework are maintained by TCS Research [1]. VeriAbs has been developed by Bharti Chimdyalwar, Priyanka Darke, Avriti Chauhan and Punit Shah under the guidance of R Venkatesh and Shrawan Kumar. We would like to thank graduate and under-graduate interns who have contributed to the development of the numerical loop abstraction module in VeriAbs.