Skip to content

Commit c144993

Browse files
author
Remi Delmas
committed
CONTRACTS: support pointer_in_range_dfcc predicate
Adds support for pointer_in_range_dfcc in ensures and requires clauses and user-defined predicates. This is a temporary workaround to the fact that pointer_in_range is lowered by the front-end.
1 parent a465b98 commit c144993

File tree

23 files changed

+451
-11
lines changed

23 files changed

+451
-11
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <stdbool.h>
2+
#include <stdlib.h>
3+
4+
// A vtable is a struct containing function pointers
5+
typedef struct vtable_s
6+
{
7+
int (*f)(void);
8+
} vtable_t;
9+
10+
int return_0()
11+
{
12+
return 0;
13+
}
14+
15+
int return_1()
16+
{
17+
return 1;
18+
}
19+
20+
// we have two possible vtables
21+
vtable_t vtable_0 = {.f = &return_0};
22+
vtable_t vtable_1 = {.f = &return_1};
23+
24+
// foo takes a vtable and calls f
25+
int foo(vtable_t *vtable)
26+
// clang-format off
27+
__CPROVER_requires(
28+
// vtable is nondeterministic pointer to one of two objects
29+
__CPROVER_pointer_in_range_dfcc(&vtable_0, vtable, &vtable_0) ||
30+
__CPROVER_pointer_in_range_dfcc(&vtable_1, vtable, &vtable_1))
31+
__CPROVER_ensures(__CPROVER_return_value == 0 || __CPROVER_return_value == 1)
32+
// clang-format on
33+
{
34+
CALL:
35+
return vtable->f();
36+
}
37+
38+
int main()
39+
{
40+
vtable_t *vtable;
41+
foo(vtable);
42+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--restrict-function-pointer foo.CALL/return_0,return_1 --nondet-static-exclude vtable_0 --nondet-static-exclude vtable_1 --dfcc main --enforce-contract foo _ --pointer-check --pointer-primitive-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Demonstrates the use of __CPROVER_pointer_in_range_dfcc to define nondeterministic
10+
pointers to one or more targets.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void foo(char *arr, size_t size, char *cur)
5+
// clang-format off
6+
__CPROVER_requires(
7+
(0 < size && size < __CPROVER_max_malloc_size) &&
8+
__CPROVER_is_fresh(arr, size) &&
9+
__CPROVER_pointer_in_range_dfcc(arr, cur, arr + size))
10+
__CPROVER_ensures(__CPROVER_pointer_in_range_dfcc(arr, cur, arr + size))
11+
// clang-format on
12+
{
13+
assert(__CPROVER_r_ok(arr, size));
14+
assert(__CPROVER_same_object(arr, cur));
15+
assert(arr <= cur && cur <= arr + size);
16+
}
17+
18+
int main()
19+
{
20+
char *arr;
21+
size_t size;
22+
char *cur;
23+
foo(arr, size, cur);
24+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--dfcc main --enforce-contract foo _ --pointer-check --pointer-primitive-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Checks that assuming pointer-in-range as preconditions establishes a state
10+
in which the definition of the predicate holds.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void foo(char *arr, size_t size, char *cur)
5+
// clang-format off
6+
__CPROVER_requires(
7+
(0 < size && size < __CPROVER_max_malloc_size) &&
8+
__CPROVER_is_fresh(arr, size) &&
9+
__CPROVER_pointer_in_range_dfcc(arr, cur, arr + size))
10+
__CPROVER_ensures(__CPROVER_pointer_in_range_dfcc(
11+
arr, cur /*, arr + size missing arg */))
12+
// clang-format on
13+
{
14+
assert(__CPROVER_r_ok(arr, size));
15+
assert(__CPROVER_same_object(arr, cur));
16+
assert(arr <= cur && cur <= arr + size);
17+
}
18+
19+
int main()
20+
{
21+
char *arr;
22+
size_t size;
23+
char *cur;
24+
foo(arr, size, cur);
25+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--dfcc main --enforce-contract foo _ --pointer-check --pointer-primitive-check
4+
^.*error: __CPROVER_pointer_in_range_dfcc expects three arguments$
5+
^EXIT=(1|64)$
6+
^SIGNAL=0$
7+
^CONVERSION ERROR$
8+
--
9+
--
10+
Checks that badly typed occurrences of __CPROVER_pointer_in_range_dfcc are detected.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void foo(char *arr, size_t size, char *cur)
5+
// clang-format off
6+
__CPROVER_requires(
7+
(0 < size && size < __CPROVER_max_malloc_size) &&
8+
__CPROVER_is_fresh(arr, size) &&
9+
__CPROVER_pointer_in_range_dfcc(arr, cur, arr + size))
10+
__CPROVER_ensures(__CPROVER_pointer_in_range_dfcc(
11+
arr, cur, 2 /* wrong type arg */))
12+
// clang-format on
13+
{
14+
assert(__CPROVER_r_ok(arr, size));
15+
assert(__CPROVER_same_object(arr, cur));
16+
assert(arr <= cur && cur <= arr + size);
17+
}
18+
19+
int main()
20+
{
21+
char *arr;
22+
size_t size;
23+
char *cur;
24+
foo(arr, size, cur);
25+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--dfcc main --enforce-contract foo _ --pointer-check --pointer-primitive-check
4+
^.*error: __CPROVER_pointer_in_range_dfcc expects pointer-typed arguments$
5+
^EXIT=(1|64)$
6+
^SIGNAL=0$
7+
^CONVERSION ERROR$
8+
--
9+
--
10+
Checks that badly typed occurrences of __CPROVER_pointer_in_range_dfcc are detected.

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2334,6 +2334,29 @@ exprt c_typecheck_baset::do_special_functions(
23342334
// returning nil leaves the call expression in place
23352335
return nil_exprt();
23362336
}
2337+
else if(identifier == CPROVER_PREFIX "pointer_in_range_dfcc")
2338+
{
2339+
// same as pointer_in_range with experimental support for DFCC contracts
2340+
// -- do not use
2341+
if(expr.arguments().size() != 3)
2342+
{
2343+
throw invalid_source_file_exceptiont{
2344+
CPROVER_PREFIX "pointer_in_range_dfcc expects three arguments",
2345+
expr.source_location()};
2346+
}
2347+
2348+
for(const auto &arg : expr.arguments())
2349+
{
2350+
if(arg.type().id() != ID_pointer)
2351+
{
2352+
throw invalid_source_file_exceptiont{
2353+
CPROVER_PREFIX
2354+
"pointer_in_range_dfcc expects pointer-typed arguments",
2355+
arg.source_location()};
2356+
}
2357+
}
2358+
return nil_exprt();
2359+
}
23372360
else if(identifier == CPROVER_PREFIX "same_object")
23382361
{
23392362
if(expr.arguments().size()!=2)

src/ansi-c/cprover_builtin_headers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ __CPROVER_bool __CPROVER_is_freeable(const void *mem);
5050
__CPROVER_bool __CPROVER_was_freed(const void *mem);
5151
__CPROVER_bool __CPROVER_is_fresh(const void *mem, __CPROVER_size_t size);
5252
__CPROVER_bool __CPROVER_obeys_contract(void (*)(void), void (*)(void));
53+
// same as pointer_in_range with experimental support in contracts
54+
__CPROVER_bool __CPROVER_pointer_in_range_dfcc(void *lb, void *ptr, void *ub);
5355
void __CPROVER_old(const void *);
5456
void __CPROVER_loop_entry(const void *);
5557

0 commit comments

Comments
 (0)