Skip to content

Commit 740d1f4

Browse files
author
Remi Delmas
committed
CONTRACTS: allow is_fresh to fail in assume contexts
Restores sound behaviour for is_fresh in assumption contexts. Flip a coin to decide if the predicate must hold or not. If it must hold, enforce its post conditions by allocating a fresh object, otherwise, leave state undefined. This behaviour was present in the initial version of the predicate but was mistakenly erased when refatoring was made to add malloc failure modes due to size overflow, and we did not have a test covering that behaviour.
1 parent 36b2335 commit 740d1f4

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
void foo(int *x)
2+
// clang-format off
3+
__CPROVER_requires(
4+
/* Case A -- pointer is valid */
5+
__CPROVER_is_fresh(x, sizeof(*x))
6+
/* Case B -- pointer is invalid */
7+
|| 1)
8+
__CPROVER_assigns(*x)
9+
// clang-format on
10+
{
11+
*x = 0;
12+
}
13+
14+
void main()
15+
{
16+
int *x;
17+
foo(x);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
CORE dfcc-only
2+
main.c
3+
--dfcc main --enforce-contract foo
4+
^\[__CPROVER_contracts_car_set_insert.assertion.\d+\] line \d+ ptr NULL or writable up to size: FAILURE$
5+
^\[__CPROVER_contracts_car_set_insert.assertion.\d+\] line \d+ no offset bits overflow on CAR upper bound computation: FAILURE$
6+
^\[__CPROVER_contracts_write_set_check_assignment.assertion.\d+\] line \d+ ptr NULL or writable up to size: FAILURE$
7+
^\[__CPROVER_contracts_write_set_check_assignment.assertion.\d+\] line \d+ no offset bits overflow on CAR upper bound computation: FAILURE$
8+
^\[foo.assigns.\d+\] line 11 Check that *x is assignable: FAILURE$
9+
^\[foo.pointer_dereference.\d+\] line 11 dereference failure: pointer NULL in \*x: FAILURE$
10+
^\[foo.pointer_dereference.\d+\] line 11 dereference failure: pointer invalid in \*x: FAILURE$
11+
^\[foo.pointer_dereference.\d+\] line 11 dereference failure: deallocated dynamic object in \*x: FAILURE$
12+
^\[foo.pointer_dereference.\d+\] line 11 dereference failure: dead object in \*x: FAILURE$
13+
^\[foo.pointer_dereference.\d+\] line 11 dereference failure: pointer outside object bounds in \*x: FAILURE$
14+
^\[foo.pointer_dereference.\d+\] line 11 dereference failure: invalid integer address in \*x: FAILURE$
15+
^EXIT=10$
16+
^SIGNAL=0$
17+
^VERIFICATION FAILED$
18+
--
19+
--
20+
This test checks that when __CPROVER_is_fresh is disjunctions,
21+
the goto model accepts traces where __CPROVER_is_fresh evaluates to false
22+
and no object gets allocated, and pointers remains undefined.

src/ansi-c/library/cprover_contracts.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,10 @@ __CPROVER_HIDE:;
12041204
"__CPROVER_is_fresh max allocation size exceeded");
12051205
__CPROVER_assume(size <= __CPROVER_max_malloc_size);
12061206
}
1207-
1207+
if(__VERIFIER_nondet___CPROVER_bool())
1208+
{
1209+
return 0;
1210+
}
12081211
void *ptr = __CPROVER_allocate(size, 0);
12091212
*elem = ptr;
12101213

@@ -1258,7 +1261,10 @@ __CPROVER_HIDE:;
12581261
"__CPROVER_is_fresh requires size <= __CPROVER_max_malloc_size");
12591262
__CPROVER_assume(size <= __CPROVER_max_malloc_size);
12601263
}
1261-
1264+
if(__VERIFIER_nondet___CPROVER_bool())
1265+
{
1266+
return 0;
1267+
}
12621268
void *ptr = __CPROVER_allocate(size, 0);
12631269
*elem = ptr;
12641270

0 commit comments

Comments
 (0)