CPROVER Manual TOC

## Modeling with Assertions and Assumptions

### Assertions

Assertions are statements within the program that attempt to capture the programmer's intent. The ANSI-C standard defines a header file assert.h, which offers a macro `assert(cond)`. When executing a statement such as

      assert(p!=NULL);

the execution is aborted with an error message if the condition evaluates to false, i.e., if `p` is NULL in the example above. The CPROVER tools can check the validity of the programmer-annotated assertions statically. Specifically, the CPROVER tools will check that the assertions hold for any nondeterministic choice that the program can make. The static assertion checks can be disabled using the `--no-assertions` command line option.

In addition, there is a CPROVER-specific way to specify assertions, using the built-in function __CPROVER_assert:

      __CPROVER_assert(p!=NULL, "p is not NULL");

The (mandatory) string that is passed as the second argument provides an informal description of the assertion. It is shown in the list of properties together with the condition.

The assertion language of the CPROVER tools is identical to the language used for expressions. Note that nondeterminism can be exploited in order to check a range of choices. As an example, the following code fragment asserts that all elements of the array are zero:

      int a[100], i;

      ...

      i=nondet_uint();
      if(i>=0 && i<100)
        assert(a[i]==0);

The nondeterministic choice will guess the element of the array that is nonzero. The code fragment above is therefore equivalent to

      int a[100], i;

      ...

      for(i=0; i<100; i++)
        assert(a[i]==0);

Future CPROVER releases will support explicit quantifiers with a syntax that resembles Spec#:

`
__CPROVER_forall { type identifier ; expression }
__CPROVER_exists { type identifier ; expression }
`

### Assumptions

Assumptions are used to restrict nondeterministic choices made by the program. As an example, suppose we wish to model a nondeterministic choice that returns a number from 1 to 100. There is no integer type with this range. We therefore use __CPROVER_assume to restrict the range of a nondeterministically chosen integer:

    unsigned int nondet_uint();

    unsigned int one_to_hundred()
    {
      unsigned int result=nondet_uint();
      __CPROVER_assume(result>=1 && result<=100);
      return result;
    }

The function above returns the desired integer from 1 to 100. You must ensure that the condition given as an assumption is actually satisfiable by some nondeterministic choice, or otherwise the model checking step will pass vacuously.

Also note that assumptions are never retroactive: They only affect assertions (or other properties) that follow them in program order. This is best illustrated with an example. In the following fragment, the assumption has no effect on the assertion, which means that the assertion will fail:

      x=nondet_uint();
      assert(x==100);
      __CPROVER_assume(x==100);

Assumptions do restrict the search space, but only for assertions that follow. As an example, the following program will pass:

    int main() {
      int x;

      __CPROVER_assume(x>=1 && x<=100000);

      x*=-1;

      __CPROVER_assert(x<0, "x is negative");
    }

Beware that nondeterminism cannot be used to obtain the effect of universal quantification in assumptions. As an example,

    int main() {
      int a[10], x, y;

      x=nondet_int();
      y=nondet_int();
      __CPROVER_assume(x>=0 && x<10 && y>=0 && y<10);

      __CPROVER_assume(a[x]>=0);

      assert(a[y]>=0);
    }

fails, as there is a choice of x and y which results in a counterexample (any choice in which x and y are different).