C and C++
C and C++ are ESBMC’s primary frontends, built on Clang/LLVM. ESBMC verifies C (up to C23) and C++ (up to C++20, with selected C++23 features), checking memory safety, arithmetic overflow, pointer safety, concurrency properties, and user assertions — or proving their absence.
To get started, see the Usage guide and the Constructs reference for the verification annotations. The pages below cover C/C++-specific tooling and support.
C language and library support
Beyond standard C, the frontend handles the GNU extensions that appear in real
code — statement expressions, __attribute__, typeof, computed goto
(goto *label_ptr over a void * label array), and __label__ local label
declarations.
On the library side, C11 concurrency is modelled as well as POSIX threads:
<threads.h> (thrd_*, mtx_*, cnd_*, tss_*) has an operational model
lowered onto the same pthread model, and the __c11_atomic_* builtins behind
<stdatomic.h> are modelled directly. The pthread model itself covers barriers,
spinlocks, read/write locks, and the recursive and error-checking mutex kinds
selected through pthread_mutexattr_settype — see
Concurrency.
Clang’s __builtin_ spellings of the memory and string routines — including
__builtin_memset, __builtin_memcmp, __builtin_strncpy and
__builtin_calloc — are rewritten to the names ESBMC models, so they behave as
the plain calls do instead of going nondeterministic. A rewritten call runs the
modelled loop, so a builtin applied to a large object needs an adequate
--unwind. The same holds for the __builtin_ spellings of <math.h>
functions (__builtin_frexp writes its exponent), and __builtin_abs,
__builtin_labs, __builtin_llabs, __builtin_popcountg, __builtin_clrsb,
the __builtin_rotateleft*/rotateright* and __builtin_bitreverse* families
are computed exactly. The __atomic_<op>_fetch, __sync_<op>_and_fetch,
__sync_bool_compare_and_swap, __sync_val_compare_and_swap,
__sync_lock_test_and_set, __sync_lock_release and __atomic_exchange
builtins update the object atomically and return the value C11 and GCC specify,
where they previously left it unchanged.
These C library functions gained operational models, so a call reads and writes memory and returns the value the standard specifies rather than a nondeterministic one:
qsort(an insertion sort that swaps whole elements) andbsearch. A comparator whose parameter types do not match the call is reported as undefined behaviour (C11 6.3.2.3p8)strnlen,strndup(copies at mostnbytes into amalloced buffer, so an over-read or a leaked copy is caught),strcasecmp,strncasecmplog10andcbrt/cbrtffrom musl,cbrtl, andilogb/logbwith theirfandlforms;atofasstrtod(nptr, NULL)pthread_once, which C11call_oncedelegates to: one caller runs the routine and the others wait for it to finish
Several existing models were corrected: strtol and its siblings parse digits
by base and set endptr and errno as C11 7.22.1.4 requires; strtod rounds
correctly when the digits and decimal exponent are exact; atan2, hypot,
ldexp/scalbn, nextafter and fesetround follow C11 for signed zeros,
infinities, NaNs, subnormals, overflow and unrecognised modes; and frexpl,
ldexpl and their relatives read long double in the binary128 layout ESBMC
encodes.
setjmp and longjmp transfer control: setjmp returns 0 when called
directly, and a later longjmp(env, v) resumes after the matching setjmp,
which then returns v (or 1 if v is 0), returning through the frames in
between; code after the longjmp is unreachable. The lowering is skipped under
--enable-unreachability-intrinsic
(#8312).
When main returns, the handlers registered with atexit run, and in C++ the
destructors of objects with static storage duration run after them —
constructed function-local statics first, then globals in reverse definition
order, skipping namespace std. An assertion in either is therefore checked,
and a global that frees memory in its destructor is not reported as a leak
(#8339).