Model checking safety and liveness via k-induction and witness refinement with constraint generation

https://doi.org/10.1016/j.scico.2020.102532Get rights and content

Highlights

  • Automatic SAT-based model checking of concurrent software systems.

  • Incremental and complete bounded model checking based on k-induction.

  • Multi-model abstraction refinement technique that constructs global and local models.

  • Refinement based on path constraints derived from unsatisfiable cores.

  • Support of model checking liveness properties based on a reduction to safety.

Abstract

In this article, we revise our constraint-based abstraction refinement technique for checking temporal logic properties of concurrent software systems. Our technique employs predicate abstraction and SAT-based three-valued bounded model checking. In contrast to classical refinement techniques where a single state space model is iteratively explored and refined with predicates, our approach is as follows: We use a coarsely-abstracted global state space model where we check for abstract witness paths for the property of interest. For each detected abstract witness we construct a local model whose state space is restricted to refinements of the witness only. On the local models we check whether the witness is real or spurious. We eliminate spurious witnesses in the global model via spurious segment constraints, which do not increase the state space complexity. Our technique is complete and terminates when a real witness in a local model can be detected, or no more witnesses in the global model exist.

While our technique was originally restricted to the verification of safety properties, we extend it here to the verification of liveness properties. For this, we make use of the state recording translation of the input system, which reduces liveness model checking to safety checking. Another restriction of our original approach was its incompleteness due to the nature of bounded model checking. Here we show how abstraction refinement-based bounded model checking can be combined with the k-induction principle, which enables unbounded model checking. Our approach is iterative with regard to the bound. The extended approach also allows us to define enhanced concepts for strengthening the constraints that we use to rule out spurious behaviour and for reusing constraints between bound iterations. We demonstrate that our approach enables the complete verification of safety and liveness properties with a reduced state space complexity and a better solving time in comparison to classical abstraction refinement techniques.

Introduction

Three-valued abstraction (3VA) [1] is an established technique for reducing the complexity of software verification. It proceeds by generating an abstract representation of an input software system over predicates with the possible truth values true, false and unknown, where the latter value is used to express the loss of information due to abstraction. The state space of an abstract software system can then be represented as a three-valued model. The evaluation of temporal logic properties on such models is known as three-valued model checking (3MC) [2]. Under three-valued abstraction both true and false model checking results can be transferred to the modelled software system, whereas an unknown result indicates that the current model is too coarse for a definite outcome. In the latter case a so-called unconfirmed witness is produced, which is an execution path in the abstract state space with some unknown transitions or predicates that characterises a potential violation of the property of interest. Witness-guided abstraction refinement [3] then iteratively adds further predicates to the abstract model until a previously unconfirmed witness turns out to be definite, or no more witnesses exist. The described approach follows the classical abstract–check–refine paradigm [4] where a single model that represents the entire system is iteratively refined. Since each refinement iteration involves an exponential growth of the state space to be explored, this approach can easily suffer from state explosion.

In [5] we introduced a novel abstraction refinement technique that facilitates the verification of safety properties of concurrent software systems with an improved state space complexity. In this approach we make use of two kinds of state space models: We use a global model that considers all parts of the underlying system, and we use local models that are restricted to previously detected unconfirmed witness paths. Both global and local models are subject to three-valued abstraction. But only the local models are refined by adding predicates, whereas the global model is iteratively pruned via spurious witness constraints derived from local models. Our technique proceeds as follows: In the same manner as in a classical abstract–check–refine approach, we start with a coarsely-abstracted global model of the input system and we check whether the safety property of interest can be proven or refuted. If the check returns unknown along with an unconfirmed witness, then we derive new predicates for refinement. Now instead of refining the global model, we construct a new local model that is narrowed down to refinements of the unconfirmed witness only. Checking the local model either proves the previously unconfirmed witness to be definite or to be spurious. In the first case we are done. In the latter case we generate a constraint for ruling out the spurious witness. In the subsequent pruning iteration we return to the global model and prune its state space via the generated spurious witness constraint. The procedure terminates when either no more witnesses in the global model exist or a definite witness in a local model can be detected. In contrast to standard approaches to constraint reusing in bounded model checking [6] our technique not only enables the reuse of constraints between bound iterations but also between different levels of abstraction. A constraint generated based on a refined local model is also admissible for the more abstract global model. Our approach reduces the state space complexity in two ways. Refinement is only applied to local models whose state space is already strongly limited by being restricted to refinements of a certain unconfirmed witness. The state space of the global model is pruned by spurious witness constraints derived from local models. But the refinement predicates that were used in the local model in order to derive these constraints do not have to be added to the global model. Hence, we gain precision in the global model without enlarging its state space. The price that we pay is an increased number of global pruning iterations and local refinement iterations until a definite result can be obtained. The actual number depends on the strength of the generated constraints in terms of ruling out spurious behaviour. The spuriousness of a witness typically originates from a spurious segment of the path that it represents. A constraint that rules out all paths that exhibit the spurious segment is naturally stronger than a constraint that only rules out the spurious witness itself.

As a background technique we use satisfiability-based three-valued bounded model checking [7] in order to process the model checking problems to be solved within our abstraction refinement approach. We have shown that the abstracted input systems together with the safety property to be checked can be directly encoded into propositional logic such that the construction of an explicit state space model is avoided [7]. Encoded three-valued bounded model checking problems can be solved via two Boolean satisfiability checks. The first check considers an over-approximating completion of the encoding where all unknowns are assumed to be true. The second check considers an under-approximating completion where all unknowns are assumed to be false. If both completions are satisfiable, then the corresponding model checking result is true. If both completions are unsatisfiable, then the corresponding model checking result is false. Otherwise the result is unknown. In [5] we demonstrated that in the satisfiability-based approach a spurious segment of a witness is characterised by a part of an unsatisfiable core of the SAT-encoded problem. The constraint for ruling out the spurious segment corresponds to the negation of this part. This enables us to efficiently generate spurious segment constraints via unsatisfiable core extraction [8]. Bounded model checking, as we used it in [3], [5], [7], is inherently incomplete. The bound

restricts the length of execution paths of the modelled system, which makes this technique only usable for detecting property violations but not for proving their absence. Completeness for finite-state systems can be theoretically established by iterating over the bound until a completeness threshold is reached [9]. However, the determination of minimal or tight (close to minimal) completeness thresholds is a computationally hard problem by itself and even tight thresholds are mostly still impractical for efficient verification. In [5] we added a bound iteration loop around our abstraction refinement technique. The loop is incremental [10] in the sense that clauses learned by the solver for a particular model M in iteration k can be reused for pruning the search space of the same model in iteration k+1. In addition, our novel approach allows for further pruning based on spurious segment constraints. We proved that iteration-independent spurious segment constraints derived from any local model can be used for restricting the search space of the global model in all bound iterations. The admissibility of reusing constraints between different models gives us pruning capabilities that are beyond what is feasible with standard incremental SAT solving [10]. The approach allows us to avoid computational overhead caused by repeating constraint generation that has been already conducted based on local models in previous iterations.

While our novel refinement approach [5] already revealed promising results in terms of reducing the state space complexity of verification tasks in comparison to classical abstraction refinement [3], it was still subject to a number of drawbacks and limitations. Our original definition of iteration-independence was overly restrictive and resulted in a very limited reusability of constraints. In this extended article we define seven different types of independence (resp. dependence) of spurious segment constraints and we prove an admissible form of reuse for each type. This also includes the additional strengthening of fully-independent constraints and the adaptation of initial state-independent constraints for reuse in higher bound iterations. The type of independence of a constraint follows immediately from unsatisfiable core extraction. Our enhanced constraint reusing concept facilitates a more extensive pruning of spurious behaviour, and thus, a better verification performance.

A second limitation of [5] is that it is incomplete due to the nature of bounded model checking. Although we use a bound iteration loop, this does not allow us to prove the absence of property violations in large-scale state space models. Completeness of bounded model checking can be established via k-induction [11]. This technique was originally introduced for the verification of safety properties of hardware systems. It proceeds as follows: Given a state space model of the system to be analysed and a safety predicate safe, it is checked whether all paths of length k that start in an initial state of the model are safe, i.e. whether safe holds in each state along the paths. This is the base case of k-induction, which is equivalent to standard bounded model checking. If the base case holds, then the inductive step is checked: Assuming k consecutive states where safe holds in each state, then safe also has to hold in every (k+1)-st successor state. The inductive step does not restrict the k consecutive states to start in an initial state. If the inductive step holds as well, then it can be concluded that all unbounded execution paths of the modelled system are also safe. Otherwise the procedure needs to be repeated with an incremented k. For finite-state models termination is guaranteed and the final bound is typically considerably smaller than a precomputed approximation of a completeness threshold. In [12] we already demonstrated that k-induction is compatible with three-valued bounded model checking. In this article we show that the k-induction technique can be also combined with our novel abstraction refinement approach. For this, we introduce a shared bound iteration loop and within this loop two separate refinement loops, one for the base case and one for the inductive step. This combination enables us to conduct complete verification of safety properties via SAT-based model checking. The base case and the inductive step are two distinct problems to be solved. Although they exhibit certain similarity, constraint reuse between the two is not admissible in general. However, we show that generated initial state-independent constraints can be reused between the base case and the inductive step, which gives us further pruning capabilities.

k-induction is limited to the verification of safety properties and so is our original approach presented in [5]. For concurrent systems also liveness properties are of great importance. Liveness model checking under fairness involves a considerably higher complexity than safety checking and many safety checking techniques are not compatible with liveness. In order to facilitate the verification of liveness properties with our approach, we adopt the state recording translation [13]. This translation transfers an original state space model into a state recording model, which reduces an original liveness model checking problem to a safety problem. The translation comes at the cost of a quadratic increase of the number of states, but it gives us the benefit to utilise efficient safety checking techniques in order to solve liveness problems. We show that the state recording translation can be already applied to our abstracted systems before the corresponding state space models are encoded in propositional logic.

The main contributions of this work are the establishment of considerably enhanced constraint reusing capabilities for our automatic abstraction refinement approach proposed in [5], the completion of previously incomplete verification techniques [3], [5], [7], and the extension of a pure safety checking technique to a technique that also supports liveness checking under fairness. Table 1 provides an overview on how this article, denoted as SCP 2020, extends and combines our previous work on SAT-based three-valued bounded model checking.

[7] and [3] support liveness model checking based on an explicit encoding of the liveness property to be checked, which turned out to be inefficient in experiments. Thus, in subsequent papers we focussed on safety model checking only. SCP 2020 re-introduces liveness support based on a reduction to safety. In [3] we introduced a fully-automatic abstraction refinement technique. Predicates for refinement are derived from unsatisfied clauses. Refined models are generated with the help of the prover Z3 [14]. The originally single-model approach to abstraction refinement has been extended to a multi-model approach in [5]. This also involved the introduction of path constraint reusing, which we enhance in SCP 2020. Based on thresholds, complete model checking is theoretically conceivable but practically infeasible in [7], [3], [5]. The k-induction approach allows for the feasibility of complete verification in [12] and SCP 2020.

We have implemented our approach. In experiments we demonstrate that our constraint-based refinement technique allows for significant performance improvements in comparison to classical abstraction refinement. Moreover, we show that our implemented tool can compete with the Spin model checker [15] for certain verification tasks.

The remainder of this article is organised as follows. In Section 2 we introduce the concurrent software systems that we consider in our approach and the three-valued abstraction technique that we employ. Section 3 provides the background on three-valued bounded model checking. In Section 4 we show how the state recording translation can be applied to our abstracted systems in order to reduce liveness to safety model checking. In Section 5 we show how k-induction can be combined with three-valued bounded model checking in order to establish completeness. Section 6 reviews basic three-valued abstraction refinement. In Section 7 we introduce our novel witness refinement technique with constraint reuse. We show in this section how the novel refinement technique can be combined with k-induction. Moreover, we define the different types of constraints that occur in our approach and we prove an admissible form of reuse and strengthening for each type. In Section 8 we introduce our propositional logic encoding of three-valued bounded model checking problems. Furthermore, we show how constraint types can be determined based on unsatisfiable core extraction. In Section 9 we introduce the implementation of our approach and we present experimental results. Section 10 discusses related work. We conclude this paper in Section 11 and give an outlook on future work.

Section snippets

Concurrent software systems

We start with a brief introduction to the systems that we want to verify and the abstraction technique that we use in our work. Our approach supports integer arithmetic-based concurrent systems with the data types int, bool and semaphore (but no arrays and pointers). Moreover, almost all control structures of the C language are supported, such as if-then-else, while-do, for and goto. A concurrent software system Sys consists of a number of possibly non-uniform processes P1 to Pn composed in

Three-valued bounded model checking

CFGs allow us to model the control flow of a concurrent system. The verification of a system additionally requires to explore a corresponding state space model. Since we use three-valued abstraction, we need a model that incorporates the truth values true, false and unknown. Three-valued Kripke structures are models with a three-valued domain for transitions and labellings of states:

Definition 4 Three-Valued Kripke Structure

A three-valued Kripke structure over a set of atomic predicates A is a tuple M=(S,I,R,L,F) where

  • S is a finite set

From liveness to safety via state recording

In this section, we review the state recording technique originally introduced in [13] which allows to reduce model checking liveness to model checking safety. In particular, we show that state recording can be implemented based on a transformation of our concurrent systems to be verified. For the purpose of an easier understanding, we divide the transformation into two steps: a first step that enables loop detection and a second step that allows for model checking liveness under fairness. The

Unbounded model checking via k-induction

In the previous section we have shown that liveness model checking problems can be translated into safety model checking problems. Hence, we can assume that all our verification problems to be solved are of the form[M,IGsafe]A where safe is an arbitrary predicate expression over the set of atomic predicates A. This unbounded model checking problem requires the consideration of all infinite paths of the model in order to prove that no property violations exist. The k-induction approach [11]

Basic three-valued abstraction refinement

Solving a three-valued bounded model checking problem [M,Iψ]kA, where the temporal logic formula ψ characterises the violation of a safety property, has the possible outcomes false, true and unknown. A false result indicates that there exists no k-prefix in M that is a witness for ψ. A true result indicates that there exists a k-prefix ω in M that is a definite witness for ψ (Definition 11). An unknown result indicates that there exists a k-prefix ω in M that is an unconfirmed witness for ψ (

Witness refinement and constraint generation

Abstraction refinement-based model checking is still challenged by the state explosion problem. Each additional predicate involves an exponential growth of the state space to be explored. In the following, we introduce an enhanced abstraction refinement algorithm that allows to reduce the number of predicates that are actually considered during model checking. Our enhancement is based on restricting the search space of the model checking problem by path constraints that can be formulated as

Reduction to propositional logic satisfiability

In our previous work [7] we showed how a three-valued bounded model checking problem [M,Iψ]kA can be encoded as a propositional logic formula AM,I,ψ,k. The encoding corresponds to an implicit problem representation such that the construction of an explicit Kripke structure is avoided. The formula AM,I,ψ,k is defined over a set of Boolean atoms Atoms, the constants true, false, and a special atom ⊥ that is used to represent the unknowns due to abstraction. The atom ⊥ occurs solely

Implementation and experiments

We have prototypically implemented our novel refinement approach on top of the SAT-based three-valued bounded model checker Tvamcus. 2 Our tool takes a concurrent system Sys within integer arithmetic as a first input. It supports almost all control structures of the C language as well as int, bool and semaphore as data types. The second input is a temporal logic formula that is either of the form G safe (safety) or GF progress (liveness) where safe

Related work

Some of the earliest work on the application of three-valued reasoning about software specifications and their properties is [21]. There, however, no reasoning algorithm was provided to deal with the unknown in a constructive manner. More recent work on three-valued reasoning about system specifications can be found in [22], whereby techniques of theorem-proving are used additionally to deal with unknown model checking results. Other interesting applications of three-valued model checking can

Conclusion and outlook

We presented an iterative abstraction refinement technique for the verification of temporal logic properties of concurrent software systems. The novelty of our approach is that we use separate models for producing abstract witness paths and for checking whether witnesses are definite or spurious. Our local models are restricted to refinements of particular witnesses only. The abstract state space of our global model is pruned via constraints derived from local models. We hereby gain precision

CRediT authorship contribution statement

Nils Timm: Conceptualization, Investigation, Supervision, Writing - review & editing. Stefan Gruner: Writing - review & editing. Madoda Nxumalo: Software. Josua Botha: Investigation, Software.

Declaration of Competing Interest

The authors declare that they have no known competing financial interests or personal relationships that could have appeared to influence the work reported in this paper.

References (49)

  • O. Strichman

    Accelerating bounded model checking of safety properties

    Form. Methods Syst. Des.

    (2004)
  • N. Timm et al.

    A bounded model checker for three-valued abstractions of concurrent software systems

  • A. Nadel

    Boosting minimal unsatisfiable core extraction

  • D. Kroening et al.

    Linear completeness thresholds for bounded model checking

  • A. Nadel et al.

    Ultimately incremental sat

  • N. Timm et al.

    Constraint reusing and k-induction for three-valued bounded model checking

  • L. Moura et al.

    Z3: an efficient SMT solver

  • G.J. Holzmann

    The model checker spin

    IEEE Trans. Softw. Eng.

    (1997)
  • N. Timm et al.

    Heuristic-guided abstraction refinement for concurrent systems

  • M. Fitting

    Kleene's three valued logics and their children

    Fundam. Inform.

    (1994)
  • H. Wehrheim

    Bounded model checking for partial Kripke structures

  • A. Nadel

    Boosting minimal unsatisfiable core extraction

  • N. Sorensson et al.

    MiniSat v1. 13 – A SAT solver with conflict-clause minimization

    SAT

    (2005)
  • D.G. Kourie

    An approach to defining abstractions, refinements and enrichments

    Quaest. Inform.

    (1989)
  • Cited by (7)

    • Trace Diagnostics for Signal-Based Temporal Properties

      2023, IEEE Transactions on Software Engineering
    • Synthesis of Cost-Optimal Multi-Agent Systems for Resource Allocation

      2022, Electronic Proceedings in Theoretical Computer Science, EPTCS
    • A K-Induction Method Extended with Value Analysis for C Program Safety Verification

      2022, Proceedings - 2022 IEEE 21st International Conference on Trust, Security and Privacy in Computing and Communications, TrustCom 2022
    View all citing articles on Scopus
    View full text