Skip to content

Commit 9afaa18

Browse files
author
Remi Delmas
committed
CONTRACTS: Add test suite for DFCC
Tests are ported from regression/contracts. They only include function contracts for now, at the exclusion of loop contracts.
1 parent d50ecfa commit 9afaa18

File tree

512 files changed

+10051
-0
lines changed

Some content is hidden

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

512 files changed

+10051
-0
lines changed

regression/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ add_subdirectory(goto-analyzer-simplify)
6565
add_subdirectory(statement-list)
6666
add_subdirectory(systemc)
6767
add_subdirectory(contracts)
68+
add_subdirectory(contracts-dfcc)
6869
add_subdirectory(acceleration)
6970
add_subdirectory(k-induction)
7071
add_subdirectory(goto-harness)

regression/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ DIRS = cbmc \
3838
statement-list \
3939
systemc \
4040
contracts \
41+
contracts-dfcc \
4142
acceleration \
4243
k-induction \
4344
goto-harness \
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
if(WIN32)
2+
set(is_windows true)
3+
else()
4+
set(is_windows false)
5+
endif()
6+
7+
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
8+
set(gcc_only -X gcc-only)
9+
set(gcc_only_string "-X;gcc-only;")
10+
else()
11+
set(gcc_only "")
12+
set(gcc_only_string "")
13+
endif()
14+
15+
16+
add_test_pl_tests(
17+
"${CMAKE_CURRENT_SOURCE_DIR}/chain.sh $<TARGET_FILE:goto-cc> $<TARGET_FILE:goto-instrument> $<TARGET_FILE:cbmc> ${is_windows}"
18+
)
19+
20+
## Enabling these causes a very significant increase in the time taken to run the regressions
21+
22+
#add_test_pl_profile(
23+
# "cbmc-z3"
24+
# "${CMAKE_CURRENT_SOURCE_DIR}/chain.sh $<TARGET_FILE:goto-cc> $<TARGET_FILE:goto-instrument> '$<TARGET_FILE:cbmc> --z3' ${is_windows}"
25+
# "-C;-X;broken-smt-backend;-X;thorough-smt-backend;-X;broken-z3-backend;-X;thorough-z3-backend;${gcc_only_string}-s;z3"
26+
# "CORE"
27+
#)
28+
29+
#add_test_pl_profile(
30+
# "cbmc-cprover-smt2"
31+
# "${CMAKE_CURRENT_SOURCE_DIR}/chain.sh $<TARGET_FILE:goto-cc> $<TARGET_FILE:goto-instrument> '$<TARGET_FILE:cbmc> --cprover-smt2' ${is_windows}"
32+
# "-C;-X;broken-smt-backend;-X;thorough-smt-backend;-X;broken-cprover-smt2-backend;-X;thorough-cprover-smt2-backend;${gcc_only_string}-s;cprover-smt2"
33+
# "CORE"
34+
#)
35+
36+
# solver appears on the PATH in Windows already
37+
#if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
38+
# set_property(
39+
# TEST "cbmc-cprover-smt2-CORE"
40+
# PROPERTY ENVIRONMENT
41+
# "PATH=$ENV{PATH}:$<TARGET_FILE_DIR:smt2_solver>"
42+
# )
43+
#endif()

regression/contracts-dfcc/Makefile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
default: test
2+
3+
include ../../src/config.inc
4+
include ../../src/common
5+
6+
ifeq ($(BUILD_ENV_),MSVC)
7+
exe=../../../src/goto-cc/goto-cl
8+
is_windows=true
9+
GCC_ONLY = -X gcc-only
10+
else
11+
exe=../../../src/goto-cc/goto-cc
12+
is_windows=false
13+
GCC_ONLY =
14+
endif
15+
16+
test:
17+
@../test.pl -e -p -c '../chain.sh $(exe) ../../../src/goto-instrument/goto-instrument ../../../src/cbmc/cbmc $(is_windows)' -X smt-backend $(GCC_ONLY)
18+
19+
test-cprover-smt2:
20+
@../test.pl -e -p -c '../chain.sh $(exe) ../../../src/goto-instrument/goto-instrument "../../../src/cbmc/cbmc --cprover-smt2" $(is_windows)' \
21+
-X broken-smt-backend -X thorough-smt-backend \
22+
-X broken-cprover-smt-backend -X thorough-cprover-smt-backend \
23+
-s cprover-smt2 $(GCC_ONLY)
24+
25+
test-z3:
26+
@../test.pl -e -p -c '../chain.sh $(exe) ../../../src/goto-instrument/goto-instrument "../../../src/cbmc/cbmc --z3" $(is_windows)' \
27+
-X broken-smt-backend -X thorough-smt-backend \
28+
-X broken-z3-smt-backend -X thorough-z3-smt-backend \
29+
-s z3 $(GCC_ONLY)
30+
31+
tests.log: ../test.pl test
32+
33+
34+
clean:
35+
@for dir in *; do \
36+
$(RM) tests.log; \
37+
if [ -d "$$dir" ]; then \
38+
cd "$$dir"; \
39+
$(RM) *.out *.gb *.smt2; \
40+
cd ..; \
41+
fi \
42+
done
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <stdlib.h>
2+
3+
// returns the index at which the write was performed if any
4+
// -1 otherwise
5+
int foo(char *a, int size)
6+
// clang-format off
7+
__CPROVER_requires(0 <= size && size <= __CPROVER_max_malloc_size)
8+
__CPROVER_requires(a == NULL || __CPROVER_is_fresh(a, size))
9+
__CPROVER_assigns(a: __CPROVER_object_whole(a))
10+
__CPROVER_ensures(
11+
a && __CPROVER_return_value >= 0 ==> a[__CPROVER_return_value] == 0)
12+
// clang-format on
13+
{
14+
if(!a)
15+
return -1;
16+
int i;
17+
if(0 <= i && i < size)
18+
{
19+
a[i] = 0;
20+
return i;
21+
}
22+
return -1;
23+
}
24+
25+
int main()
26+
{
27+
size_t size;
28+
char *a;
29+
foo(a, size);
30+
return 0;
31+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--dfcc main --enforce-contract foo _ --malloc-may-fail --malloc-fail-null
4+
^\[foo.assigns.\d+\] line 19 Check that a\[\(signed long (long )?int\)i\] is assignable: SUCCESS$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
^VERIFICATION SUCCESSFUL$
8+
--
9+
This test checks that objects of size zero or __CPROVER_max_malloc_size
10+
do not cause spurious falsifications in assigns clause instrumentation
11+
in contract enforcement mode.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
struct st1
2+
{
3+
int a;
4+
int arr[10];
5+
};
6+
7+
struct st2
8+
{
9+
int a;
10+
struct st1 arr[10];
11+
};
12+
13+
struct st3
14+
{
15+
struct st1 *s1;
16+
struct st2 *s2;
17+
struct st1 arr1[10];
18+
struct st2 arr2[10];
19+
};
20+
21+
enum tagt
22+
{
23+
CHAR,
24+
INT,
25+
CHAR_PTR,
26+
INT_ARR,
27+
STRUCT_ST1_ARR
28+
};
29+
30+
// clang-format off
31+
struct taggedt {
32+
enum tagt tag;
33+
union {
34+
struct{ char a; };
35+
struct{ int b; };
36+
struct{ char *ptr; };
37+
struct{ int arr[10]; };
38+
struct{ struct st1 arr1[10]; };
39+
};
40+
};
41+
// clang-format on
42+
43+
int foo(int i) __CPROVER_assigns()
44+
{
45+
// all accesses to locals should pass
46+
int arr[10];
47+
struct st1 s1;
48+
struct st2 s2;
49+
struct st1 dirty_s1;
50+
struct st3 s3;
51+
s3.s1 = &dirty_s1;
52+
s3.s2 = malloc(sizeof(struct st2));
53+
54+
if(0 <= i && i < 10)
55+
{
56+
arr[i] = 0;
57+
s1.a = 0;
58+
s1.arr[i] = 0;
59+
s2.a = 0;
60+
s2.arr[i].a = 0;
61+
s2.arr[i].arr[i] = 0;
62+
s3.s1->a = 0;
63+
s3.s1->arr[i] = 0;
64+
s3.s2->a = 0;
65+
s3.s2->arr[i].a = 0;
66+
s3.s2->arr[i].arr[i] = 0;
67+
*(&(s3.s2->arr[i].arr[0]) + i) = 0;
68+
(&(s3.arr1[0]) + i)->arr[i] = 0;
69+
(&((&(s3.arr2[0]) + i)->arr[i]))->a = 0;
70+
}
71+
72+
struct taggedt tagged;
73+
switch(tagged.tag)
74+
{
75+
case CHAR:
76+
tagged.a = 0;
77+
break;
78+
case INT:
79+
tagged.b = 0;
80+
break;
81+
case CHAR_PTR:
82+
tagged.ptr = 0;
83+
break;
84+
case INT_ARR:
85+
if(0 <= i && i < 10)
86+
tagged.arr[i] = 0;
87+
break;
88+
case STRUCT_ST1_ARR:
89+
if(0 <= i && i < 10)
90+
{
91+
tagged.arr1[i].a = 0;
92+
tagged.arr1[i].arr[i] = 0;
93+
}
94+
break;
95+
}
96+
97+
return 0;
98+
}
99+
100+
void main()
101+
{
102+
int i;
103+
foo(i);
104+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--dfcc main --enforce-contract foo
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Checks that assigns clause checking explicitly checks assignments to locally
10+
declared symbols with composite types, when they are dirty.
11+
Out of bounds accesses to locally declared arrays, structs, etc.
12+
will be detected by assigns clause checking.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <stdbool.h>
2+
#include <stdlib.h>
3+
4+
int bar(int l, int r) __CPROVER_requires(0 <= l && l <= 10)
5+
__CPROVER_requires(0 <= r && r <= 10) __CPROVER_assigns() __CPROVER_ensures(
6+
__CPROVER_return_value == __CPROVER_old(l) + __CPROVER_old(r))
7+
{
8+
return l + r;
9+
}
10+
11+
int *baz(int l, int r) __CPROVER_requires(0 <= l && l <= 10)
12+
__CPROVER_requires(0 <= r && r <= 10) __CPROVER_assigns() __CPROVER_ensures(
13+
*__CPROVER_return_value == __CPROVER_old(l) + __CPROVER_old(r))
14+
{
15+
int *res = malloc(sizeof(int));
16+
*res = l + r;
17+
return res;
18+
}
19+
20+
int foo(int l, int r) __CPROVER_requires(0 <= l && l <= 10)
21+
__CPROVER_requires(0 <= r && r <= 10) __CPROVER_assigns() __CPROVER_ensures(
22+
__CPROVER_return_value == __CPROVER_old(l) + __CPROVER_old(r))
23+
{
24+
bar(l, r);
25+
bar(l, r);
26+
baz(l, r);
27+
baz(l, r);
28+
return l + r;
29+
}
30+
31+
int main()
32+
{
33+
int l;
34+
int r;
35+
foo(l, r);
36+
return 0;
37+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--dfcc main --replace-call-with-contract bar --replace-call-with-contract baz --enforce-contract foo
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^\[.*assigns.*\].*ignored_return_value.*FAILURE
9+
--
10+
This test checks that when replacing a call by a contract for a call that
11+
ignores the return value of the function, the temporary introduced to
12+
receive the call result does not trigger errors with assigns clause Checking
13+
in the function under verification.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <stdlib.h>
2+
3+
// returns the index at which the write was performed if any
4+
// -1 otherwise
5+
int foo(char *a, int size)
6+
// clang-format off
7+
__CPROVER_requires(0 <= size && size <= __CPROVER_max_malloc_size)
8+
__CPROVER_requires(a == NULL || __CPROVER_rw_ok(a, size))
9+
__CPROVER_assigns(__CPROVER_object_whole(a))
10+
__CPROVER_ensures(
11+
a && __CPROVER_return_value >= 0 ==> a[__CPROVER_return_value] == 0)
12+
// clang-format on
13+
{
14+
if(!a)
15+
return -1;
16+
int i;
17+
if(0 <= i && i < size)
18+
{
19+
a[i] = 0;
20+
return i;
21+
}
22+
return -1;
23+
}
24+
25+
int main()
26+
{
27+
int size;
28+
if(size < 0)
29+
size = 0;
30+
if(size > __CPROVER_max_malloc_size)
31+
size = __CPROVER_max_malloc_size;
32+
char *a = malloc(size * sizeof(*a));
33+
int res = foo(a, size);
34+
if(a && res >= 0)
35+
__CPROVER_assert(a[res] == 0, "expecting SUCCESS");
36+
return 0;
37+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--dfcc main --replace-call-with-contract foo _ --malloc-may-fail --malloc-fail-null
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
\[main\.assertion\.1\] line 35 expecting SUCCESS: SUCCESS$
7+
^VERIFICATION SUCCESSFUL$
8+
--
9+
This test checks that objects of size zero or of __CPROVER_max_malloc_size
10+
do not cause spurious falsifications in assigns clause instrumentation
11+
in contract replacement mode.

0 commit comments

Comments
 (0)