Constructs

Constructs

This page describes the verification constructs that ESBMC supports. These can be used in harness files to aid with the verification of ESBMC.

ℹ️

ESBMC is compatible with the SV-COMP constructs as well. They can be used instead of these constructs. However, the ESBMC constructs are more powerful. It is recommended to use the ESBMC constructs if you’re planning to verify your code with only ESBMC.

SV-COMP Document: https://sv-comp.sosy-lab.org/2025/rules.php

Non-Deterministic Functions

nondet_X() where X is a primitive C data type. This will mark the variable as non-deterministic, meaning it can have any value.

In this example, ESBMC will find a verification failed outcome because x is marked as being able to hold any value:

#include <assert.h>
int main() {
    unsigned int x = nondet_uint();
    assert(x < 10);
    return 0;
}

Assert and Assume

__ESBMC_assert(cond, reason) can be used instead of assert(), this brings the benefit of not needing to use #include <assert.h>.

int main() {
    unsigned int x = nondet_uint();
    __ESBMC_assert(x < 10, "X needs to be less than 10.");
    return 0;
}

__ESBMC_assume(int) can be used to narrow down the possible values of x. In this case the verification will succeed because it narrows the possible values of x to be less than 5.

#include <assert.h>
int main() {
    unsigned int x = nondet_uint();
    __ESBMC_assume(x < 5);
    assert(x < 10);
    return 0;
}

Ensure and Requires

The constructs __ESBMC_ensure(...), __ESBMC_requires(...), __ESBMC_return_value and __ESBMC_old(...) are detailed in the Function Contracts article.

Pragma Utils

The verification paramters can be modified using #pragma keyword. The following constructs are made available.

Unroll

Unroll can be used to set the loop unwind bound for a loop. This is equivalent to using --unwindset id:bound where id is the loop ID and bound is N. This inlining however, allows us to specify the paramter in a more stable manner as the id won’t shift as the code changes. It also frees us from needing to specify the loop bound when invoking ESBMC.

#pragma unroll [N] sets the next loop to be unwinded N times. In the following example, the loop will be unwound 80 times max.

int main() {
    unsigned int x = nondet_uint();
    __ESBMC_assume(x > 50 && x < 100);
    unsigned int y = 0;
    #pragma unroll 80
    for (int i = x - 1; x >= 0; x--) {
        y += x;
    }
    assert(y > 100);
    return 0;
}

You can also use #pragma unroll without N to make the loop unroll fully in the cases where --unwind is set. In this example, the loop will unroll fully regardless of the global unwind bound set.

⚠️
Be careful that the loop you use this construct to terminates, otherwise ESBMC will never stop verifying it.
int main() {
    unsigned int x = nondet_uint();
    __ESBMC_assume(x > 50 && x < 100);
    #pragma unroll
    for (int i = x - 1; x >= 0; x--) {
        y += x;
    }
    assert(y > 100);
    return 0;
}

N can also specified as a #define macro, however, if a value isn’t found, it will throw a parsing error.

#define LOOP_BOUND 80
int main() {
    unsigned int x = nondet_uint();
    __ESBMC_assume(x > 50 && x < 100);
    #pragma unroll LOOP_BOUND
    for (int i = x - 1; x >= 0; x--) {
        y += x;
    }
    assert(y > 100);
    return 0;
}