Skip to content

Commit 2411dec

Browse files
author
Remi Delmas
committed
CONTRACTS: support slice operators in loop assigns clauses
Changes: - Drop support for __CPROVER_POINTER_OBJECT in assigns clauses in the front-end - Add methods to havoc __CPROVER_assignable, __CPROVER_object_whole, __CPROVER_object_from, __CPROVER_object_upto in havoc_assigns_targett. - update tests - add new tests
1 parent 42d5ce2 commit 2411dec

File tree

41 files changed

+488
-72
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+488
-72
lines changed

regression/contracts-dfcc/assigns_enforce_address_of/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--dfcc main --enforce-contract foo
44
^EXIT=(1|64)$
55
^SIGNAL=0$
6-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
6+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
77
^CONVERSION ERROR$
88
--
99
--

regression/contracts-dfcc/assigns_enforce_conditional_non_lvalue_target/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
main.c
33
--enforce-contract foo
4-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
4+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
55
^CONVERSION ERROR
66
^EXIT=(1|64)$
77
^SIGNAL=0$

regression/contracts-dfcc/assigns_enforce_conditional_non_lvalue_target_list/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
main.c
33
--enforce-contract foo
4-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
4+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
55
^CONVERSION ERROR
66
^EXIT=(1|64)$
77
^SIGNAL=0$

regression/contracts-dfcc/assigns_enforce_literal/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--dfcc main --enforce-contract foo
44
^EXIT=(1|64)$
55
^SIGNAL=0$
6-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
6+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
77
^CONVERSION ERROR$
88
--
99
--

regression/contracts-dfcc/assigns_enforce_side_effects_2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--dfcc main --enforce-contract foo
44
^EXIT=(1|64)$
55
^SIGNAL=0$
6-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
6+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
77
^CONVERSION ERROR$
88
--
99
--

regression/contracts-dfcc/assigns_enforce_side_effects_3/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--dfcc main --enforce-contract foo
44
^EXIT=(1|64)$
55
^SIGNAL=0$
6-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
6+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
77
^CONVERSION ERROR$
88
--
99
--

regression/contracts-dfcc/assigns_type_checking_invalid_case_01/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=(1|64)$
55
^SIGNAL=0$
66
^CONVERSION ERROR$
7-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
7+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
88
--
99
Checks whether type checking rejects literal constants in assigns clause.

regression/contracts-dfcc/reject_history_expr_in_assigns_clause/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
main.c
33
--enforce-contract foo
4-
^main.c.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
4+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
55
^CONVERSION ERROR$
66
^EXIT=(1|64)$
77
^SIGNAL=0$

regression/contracts/assigns_enforce_address_of/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--enforce-contract foo
44
^EXIT=(1|64)$
55
^SIGNAL=0$
6-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
6+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
77
^CONVERSION ERROR$
88
--
99
--

regression/contracts/assigns_enforce_conditional_non_lvalue_target/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
main.c
33
--enforce-contract foo
4-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
4+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
55
^CONVERSION ERROR
66
^EXIT=(1|64)$
77
^SIGNAL=0$

regression/contracts/assigns_enforce_conditional_non_lvalue_target_list/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
main.c
33
--enforce-contract foo
4-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
4+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
55
^CONVERSION ERROR
66
^EXIT=(1|64)$
77
^SIGNAL=0$

regression/contracts/assigns_enforce_literal/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--enforce-contract foo
44
^EXIT=(1|64)$
55
^SIGNAL=0$
6-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
6+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
77
^CONVERSION ERROR$
88
--
99
--

regression/contracts/assigns_enforce_side_effects_2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--enforce-contract foo
44
^EXIT=(1|64)$
55
^SIGNAL=0$
6-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
6+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
77
^CONVERSION ERROR$
88
--
99
--

regression/contracts/assigns_enforce_side_effects_3/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--enforce-contract foo
44
^EXIT=(1|64)$
55
^SIGNAL=0$
6-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
6+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
77
^CONVERSION ERROR$
88
--
99
--

regression/contracts/assigns_type_checking_invalid_case_01/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=(1|64)$
55
^SIGNAL=0$
66
^CONVERSION ERROR$
7-
^.*error: assigns clause target must be a non-void lvalue, a call to __CPROVER_POINTER_OBJECT or a call to a function returning void$
7+
^.*error: assigns clause target must be a non-void lvalue or a call to a function returning void$
88
--
99
Checks whether type checking rejects literal constants in assigns clause.

regression/contracts/invar_havoc_dynamic_array/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ void main()
1010

1111
for(unsigned i = 0; i < SIZE; i++)
1212
// clang-format off
13-
__CPROVER_assigns(i, __CPROVER_POINTER_OBJECT(data))
13+
__CPROVER_assigns(i, __CPROVER_object_whole(data))
1414
__CPROVER_loop_invariant(i <= SIZE)
1515
// clang-format on
1616
{

regression/contracts/invar_havoc_static_array/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ void main()
1010

1111
for(unsigned i = 0; i < SIZE; i++)
1212
// clang-format off
13-
__CPROVER_assigns(i, __CPROVER_POINTER_OBJECT(data))
13+
__CPROVER_assigns(i, __CPROVER_object_whole(data))
1414
__CPROVER_loop_invariant(i <= SIZE)
1515
// clang-format on
1616
{

regression/contracts/invar_havoc_static_multi-dim_array_partial_const_idx/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ void main()
1111
data[4][5][6] = 0;
1212

1313
for(unsigned i = 0; i < SIZE; i++)
14-
__CPROVER_assigns(i, __CPROVER_POINTER_OBJECT(data))
14+
__CPROVER_assigns(i, __CPROVER_object_whole(data))
1515
__CPROVER_loop_invariant(i <= SIZE)
1616
{
1717
data[4][i][6] = 1;

regression/contracts/loop_assigns-01/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void main()
1616
b->data[5] = 0;
1717
for(unsigned i = 0; i < SIZE; i++)
1818
// clang-format off
19-
__CPROVER_assigns(i, __CPROVER_POINTER_OBJECT(b->data))
19+
__CPROVER_assigns(i, __CPROVER_object_whole(b->data))
2020
__CPROVER_loop_invariant(i <= SIZE)
2121
// clang-format on
2222
{

regression/contracts/loop_assigns-03/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void main()
1616
b->data[5] = 0;
1717
for(unsigned i = 0; i < SIZE; i++)
1818
// clang-format off
19-
__CPROVER_assigns(__CPROVER_POINTER_OBJECT(b->data))
19+
__CPROVER_assigns(__CPROVER_object_whole(b->data))
2020
__CPROVER_loop_invariant(i <= SIZE)
2121
// clang-format on
2222
{

regression/contracts/loop_assigns-04/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ void main()
1717
b->data[5] = 0;
1818
for(unsigned i = 0; i < SIZE; i++)
1919
// clang-format off
20-
__CPROVER_assigns(i, __CPROVER_POINTER_OBJECT(b->data))
20+
__CPROVER_assigns(i, __CPROVER_object_whole(b->data))
2121
__CPROVER_loop_invariant(i <= SIZE)
2222
// clang-format on
2323
{
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
#define SIZE 5
5+
6+
struct blob
7+
{
8+
char *data;
9+
};
10+
11+
void main()
12+
{
13+
struct blob *b = malloc(sizeof(struct blob));
14+
b->data = malloc(SIZE);
15+
b->data[0] = 0;
16+
b->data[1] = 1;
17+
b->data[2] = 2;
18+
b->data[3] = 3;
19+
b->data[4] = 4;
20+
21+
char *start = b->data;
22+
char *end = b->data + SIZE;
23+
24+
for(unsigned i = 0; i < SIZE; i++)
25+
// clang-format off
26+
__CPROVER_assigns(i,
27+
__CPROVER_object_upto(b->data, SIZE),
28+
__CPROVER_typed_target(b->data))
29+
__CPROVER_loop_invariant(
30+
i <= SIZE &&
31+
start <= b->data && b->data < end)
32+
// clang-format on
33+
{
34+
b->data = b->data; // must pass
35+
*(b->data) = 0; // must pass
36+
}
37+
38+
// must pass
39+
assert(start <= b->data && b->data <= end);
40+
// must fail
41+
assert(b->data == start);
42+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.\d+\] .* Check that loop instrumentation was not truncated: SUCCESS$
9+
^\[main.assigns.\d+\] .* Check that i is assignable: SUCCESS$
10+
^\[main.assigns.\d+\] .* Check that i is valid: SUCCESS$
11+
^\[main.assigns.\d+\] .* Check that __CPROVER_object_upto\(\(.*\)b->data, \(.*\)5\) is valid: SUCCESS$
12+
^\[main.assigns.\d+\] .* Check that __CPROVER_assignable\(\(.*\)&b->data, (4|8).*, TRUE\) is valid: SUCCESS$
13+
^\[main.assigns.\d+\] .* Check that b->data is assignable: SUCCESS$
14+
^\[main.assigns.\d+\] .* Check that \*b->data is assignable: SUCCESS$
15+
^\[main.assertion.\d+\] .* assertion b->data == start: FAILURE$
16+
^\[main.assertion.\d+\] .* assertion start <= b->data && b->data <= end: SUCCESS$
17+
^VERIFICATION FAILED$
18+
--
19+
--
20+
This test checks that __CPROVER_typed_target(ptr) is supported in loop contracts
21+
for pointer typed targets and gets translated to
22+
__CPROVER_assignable(address_of(ptr), sizeof(ptr), TRUE).
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
#define SIZE 5
5+
6+
struct blob
7+
{
8+
char *data;
9+
};
10+
11+
void main()
12+
{
13+
struct blob *b = malloc(sizeof(struct blob));
14+
b->data = malloc(SIZE);
15+
b->data[0] = 0;
16+
b->data[1] = 0;
17+
b->data[2] = 0;
18+
b->data[3] = 0;
19+
b->data[4] = 0;
20+
21+
for(unsigned i = 0; i < SIZE; i++)
22+
// clang-format off
23+
__CPROVER_assigns(i, __CPROVER_typed_target(b->data[0]))
24+
__CPROVER_loop_invariant(i <= SIZE)
25+
// clang-format on
26+
{
27+
// must pass
28+
b->data[0] = 1;
29+
// must fail
30+
b->data[i] = 1;
31+
}
32+
33+
// must fail
34+
assert(b->data[0] == 0);
35+
// must pass
36+
assert(b->data[1] == 0);
37+
assert(b->data[2] == 0);
38+
assert(b->data[3] == 0);
39+
assert(b->data[4] == 0);
40+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.assigns.\d+\] .* Check that i is assignable: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that b->data\[\(.*\)0\] is assignable: SUCCESS$
9+
^\[main.assigns.\d+\] .* Check that b->data\[\(.*\)i\] is assignable: FAILURE$
10+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
11+
^\[main.assigns.\d+\] .* Check that __CPROVER_assignable\(\(.*\)&b->data\[\(.*\)0\], 1ul, FALSE\) is valid: SUCCESS$
12+
^\[main.assertion.\d+\] .* assertion b->data\[0\] == 0: FAILURE$
13+
^\[main.assertion.\d+\] .* assertion b->data\[1\] == 0: SUCCESS$
14+
^\[main.assertion.\d+\] .* assertion b->data\[2\] == 0: SUCCESS$
15+
^\[main.assertion.\d+\] .* assertion b->data\[3\] == 0: SUCCESS$
16+
^\[main.assertion.\d+\] .* assertion b->data\[4\] == 0: SUCCESS$
17+
^VERIFICATION FAILED$
18+
--
19+
^\[main.assigns.\d+\] .* Check that b->data\[(.*)i\] is assignable: FAILED$
20+
--
21+
This test shows that __CPROVER_typed_target is supported in loop contracts,
22+
and gets translated to __CPROVER_assignable(&target, sizeof(target), FALSE)
23+
for scalar targets.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
#define SIZE 5
5+
6+
struct blob
7+
{
8+
char *data;
9+
};
10+
11+
void main()
12+
{
13+
struct blob *b = malloc(sizeof(struct blob));
14+
b->data = malloc(SIZE);
15+
b->data[0] = 0;
16+
b->data[1] = 0;
17+
b->data[2] = 0;
18+
b->data[3] = 0;
19+
b->data[4] = 0;
20+
21+
for(unsigned i = 0; i < SIZE; i++)
22+
// clang-format off
23+
__CPROVER_assigns(i, __CPROVER_object_from(b->data))
24+
__CPROVER_loop_invariant(i <= SIZE)
25+
// clang-format on
26+
{
27+
// must pass
28+
b->data[i] = 1;
29+
}
30+
31+
// these should all fail
32+
assert(b->data[0] == 0);
33+
assert(b->data[1] == 0);
34+
assert(b->data[2] == 0);
35+
assert(b->data[3] == 0);
36+
assert(b->data[4] == 0);
37+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.assigns.\d+\] .* Check that i is assignable: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that b->data\[(.*)i\] is assignable: SUCCESS$
9+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
10+
^\[main.assertion.\d+\] .* assertion b->data\[0\] == 0: FAILURE$
11+
^\[main.assertion.\d+\] .* assertion b->data\[1\] == 0: FAILURE$
12+
^\[main.assertion.\d+\] .* assertion b->data\[2\] == 0: FAILURE$
13+
^\[main.assertion.\d+\] .* assertion b->data\[3\] == 0: FAILURE$
14+
^\[main.assertion.\d+\] .* assertion b->data\[4\] == 0: FAILURE$
15+
^VERIFICATION FAILED$
16+
--
17+
^\[main.assigns.\d+\] .* Check that b->data\[(.*)i\] is assignable: FAILURE$
18+
--
19+
This test shows that __CPROVER_object_from is supported in loop contracts.

0 commit comments

Comments
 (0)