Goto programs
The goto program is the intermediate representation of a program used by
CBMC to do bounded model checking.
CBMC comes with a compiler called goto-cc
that is intended to be a
drop-in replacement for gcc
. The difference is that goto-cc
produces
a goto program instead of the executable binary produced by gcc
.
We've already touched on these topics
in our overview of how to use CBMC.
Most important, we've demonstrated how to use goto-cc
to produce the
goto program and how to run CBMC on the goto program.
Sometimes, however, it is helpful (and just plain interesting) to look at
the goto program produced by goto-cc
. Two commands are particularly
helpful:
cbmc program.goto --list-goto-functions
displays the function names of all the functions appearing in the goto programprogram.goto
cbmc program.goto --show-goto-functions
displays function bodies of all the functions appearing in the goto programprogram.goto
.
A goto program
Consider a little program function-pointer.c
that declares two functions alpha
and beta
,
assigns nondeterministically
one of alpha
and beta
to a function pointer function
,
and then invokes the function pointed to by function
.
#include <assert.h>
int alpha(int x) {
return x+1;
}
int beta(int x) {
return x+2;
}
int main() {
int (*function)();
int bool;
function = bool ? alpha : beta;
int x;
int rc = function(x);
}
Let's compile the program into a goto program.
goto-cc function-pointer.c -o function-pointer.goto
The function names
Let's print the function names:
cbmc function-pointer.goto --list-goto-functions
__CPROVER__start /* __CPROVER__start */
__CPROVER_initialize /* __CPROVER_initialize */
alpha /* alpha */
beta /* beta */
main /* main */
The second initialize
function initializes some CBMC internal variables.
The first start
function is the entry point for the goto program.
It calls the initialize
function followed by the main
function.
You can print the function bodies and see this for yourself.
The function bodies
Let's print the function bodies:
cbmc function-pointer.goto --show-goto-functions
The result is a little too long to include here, but in the middle
of the function body for main
we find
// 7 file function-pointers.c line 18 function main
IF main::1::function = cast(address_of(beta), code*) THEN GOTO 1
// 8 file function-pointers.c line 18 function main
IF main::1::function = cast(address_of(alpha), code*) THEN GOTO 2
// 9 file function-pointers.c line 18 function main
ASSUME false
// 10 file function-pointers.c line 18 function main
1: CALL main::$tmp::return_value := beta(main::1::x)
// 11 file function-pointers.c line 18 function main
GOTO 3
// 12 file function-pointers.c line 18 function main
2: CALL main::$tmp::return_value := alpha(main::1::x)
// 13 no location
3: ASSIGN main::1::rc := main::$tmp::return_value
This is interesting because it demonstrates how CBMC handles
function pointers. What we see is essentially a switch statement
that compares the function pointer function
with pointers to
each of the functions whose address has been taken anywhere in the program.
In this case, pointers to the functions alpha
and beta
. Depending on
the outcome of the comparison, either alpha
or beta
is invoked
and its return value is assigned to rc
.
We include this discussion as an example of how looking at the goto program
can help debug issues with CBMC. If, for example, CBMC were surprisingly
slow to terminate, you might look at the goto program and discover that
there is another function gamma
that is being considered as a possible value for function
.
This is impossible in our example, but if gamma
is defined in another
source file that was accidentally included in the build of the goto program,
one solution might be simply to omit that source file from the build for
this proof.