Closed
Description
I have created the following test case:
#include <stddef.h>
#include <assert.h>
int* add(int* ptr, size_t offset) {
return ptr + offset;
}
int spurious() {
int* pin_0 = 32;
int* pin_1 = add(pin_0, 0);
assert(pin_0 == pin_1);
}
int expected() {
int* pin_0 = 32;
int* pin_1 = pin_0 + 0;
assert(pin_0 == pin_1);
}
The functions expected
and spurious
are functionally equivalent. One wraps the sum into an aux function and the other one performs the sum in-place. The results of CBMC proofs are rather different for these two functions:
$ cbmc test.c --pointer-overflow-check --function spurious | tail -n 18
** Results:
test.c function add
[add.pointer_arithmetic.1] line 5 pointer arithmetic: pointer NULL in ptr + (signed long int)offset: FAILURE
[add.pointer_arithmetic.2] line 5 pointer arithmetic: pointer invalid in ptr + (signed long int)offset: SUCCESS
[add.pointer_arithmetic.3] line 5 pointer arithmetic: deallocated dynamic object in ptr + (signed long int)offset: FAILURE
[add.pointer_arithmetic.4] line 5 pointer arithmetic: dead object in ptr + (signed long int)offset: FAILURE
[add.pointer_arithmetic.5] line 5 pointer arithmetic: pointer outside object bounds in ptr + (signed long int)offset: FAILURE
[add.pointer_arithmetic.6] line 5 pointer arithmetic: invalid integer address in ptr + (signed long int)offset: FAILURE
test.c function expected
[expected.pointer_arithmetic.1] line 16 pointer arithmetic: invalid integer address in pin_0 + (signed long int)0: SUCCESS
[expected.assertion.1] line 17 assertion pin_0 == pin_1: SUCCESS
test.c function spurious
[spurious.assertion.1] line 11 assertion pin_0 == pin_1: SUCCESS
** 5 of 9 failed (2 iterations)
VERIFICATION FAILED
The result below seems more reasonable:
$ cbmc test.c --pointer-overflow-check --function expected | tail -n 18
** Results:
test.c function add
[add.pointer_arithmetic.1] line 5 pointer arithmetic: pointer NULL in ptr + (signed long int)offset: SUCCESS
[add.pointer_arithmetic.2] line 5 pointer arithmetic: pointer invalid in ptr + (signed long int)offset: SUCCESS
[add.pointer_arithmetic.3] line 5 pointer arithmetic: deallocated dynamic object in ptr + (signed long int)offset: SUCCESS
[add.pointer_arithmetic.4] line 5 pointer arithmetic: dead object in ptr + (signed long int)offset: SUCCESS
[add.pointer_arithmetic.5] line 5 pointer arithmetic: pointer outside object bounds in ptr + (signed long int)offset: SUCCESS
[add.pointer_arithmetic.6] line 5 pointer arithmetic: invalid integer address in ptr + (signed long int)offset: SUCCESS
test.c function expected
[expected.pointer_arithmetic.1] line 16 pointer arithmetic: invalid integer address in pin_0 + (signed long int)0: FAILURE
[expected.assertion.1] line 17 assertion pin_0 == pin_1: SUCCESS
test.c function spurious
[spurious.assertion.1] line 11 assertion pin_0 == pin_1: SUCCESS
** 1 of 9 failed (2 iterations)
VERIFICATION FAILED
CBMC version: 5.50.0
Operating system: Ubuntu 18.04
Exact command line resulting in the issue: cbmc test.c --pointer-overflow-check --function spurious
What behaviour did you expect: Only one failure due to "pointer arithmetic: pointer invalid".
What happened instead: Checks like NULL pointer are failing even though the pointer is not NULL.