Skip to content

Commit 37c0b83

Browse files
authored
Merge pull request diffblue#2309 from qaphla/regression
Regression tests for code contracts
2 parents be6f3c9 + d49ea09 commit 37c0b83

File tree

30 files changed

+710
-1
lines changed

30 files changed

+710
-1
lines changed

regression/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ DIRS = cbmc \
1818
goto-cc-cbmc \
1919
cbmc-cpp \
2020
goto-cc-goto-analyzer \
21-
systemc
21+
systemc \
22+
contracts \
2223
# Empty last line
2324

2425
# Tests under goto-gcc cannot be run on Windows, so appveyor.yml unlinks

regression/contracts/CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
if(WIN32)
2+
set(is_windows true)
3+
else()
4+
set(is_windows false)
5+
endif()
6+
7+
add_test_pl_tests(
8+
"${CMAKE_CURRENT_SOURCE_DIR}/chain.sh $<TARGET_FILE:goto-cc> $<TARGET_FILE:goto-instrument> $<TARGET_FILE:cbmc> ${is_windows}"
9+
)

regression/contracts/Makefile

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
default: tests.log
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+
else
10+
exe=../../../src/goto-cc/goto-cc
11+
is_windows=false
12+
endif
13+
14+
test:
15+
@../test.pl -p -c '../chain.sh $(exe) ../../../src/goto-instrument/goto-instrument ../../../src/cbmc/cbmc $(is_windows)'
16+
17+
tests.log:
18+
@../test.pl -p -c '../chain.sh $(exe) ../../../src/goto-instrument/goto-instrument ../../../src/cbmc/cbmc $(is_windows)'
19+
20+
show:
21+
@for dir in *; do \
22+
if [ -d "$$dir" ]; then \
23+
vim -o "$$dir/*.c" "$$dir/*.out"; \
24+
fi; \
25+
done;
26+
27+
clean:
28+
@for dir in *; do \
29+
$(RM) tests.log; \
30+
if [ -d "$$dir" ]; then \
31+
cd "$$dir"; \
32+
$(RM) *.out *.gb; \
33+
cd ..; \
34+
fi \
35+
done

regression/contracts/chain.sh

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
goto_cc=$1
6+
goto_instrument=$2
7+
cbmc=$3
8+
is_windows=$4
9+
10+
name=${*:$#}
11+
name=${name%.c}
12+
13+
args=${*:5:$#-5}
14+
15+
if [[ "${is_windows}" == "true" ]]; then
16+
$goto_cc "${name}.c"
17+
mv "${name}.exe" "${name}.gb"
18+
else
19+
$goto_cc -o "${name}.gb" "${name}.c"
20+
fi
21+
22+
$goto_instrument ${args} "${name}.gb" "${name}-mod.gb"
23+
if [ ! -e "${name}-mod.gb" ] ; then
24+
cp "$name.gb" "${name}-mod.gb"
25+
elif echo $args | grep -q -- "--dump-c" ; then
26+
mv "${name}-mod.gb" "${name}-mod.c"
27+
28+
if [[ "${is_windows}" == "true" ]]; then
29+
$goto_cc "${name}-mod.c"
30+
mv "${name}-mod.exe" "${name}-mod.gb"
31+
else
32+
$goto_cc -o "${name}-mod.gb" "${name}-mod.c"
33+
fi
34+
35+
rm "${name}-mod.c"
36+
fi
37+
$goto_instrument --show-goto-functions "${name}-mod.gb"
38+
$cbmc "${name}-mod.gb"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// function_apply_01
2+
3+
// Note that this test is supposed to have an incorrect contract.
4+
// We verify that applying (without checking) the contract yields success,
5+
// and that checking the contract yields failure.
6+
7+
#include <assert.h>
8+
9+
int foo()
10+
__CPROVER_ensures(__CPROVER_return_value == 0)
11+
{
12+
return 1;
13+
}
14+
15+
int main()
16+
{
17+
int x = foo();
18+
assert(x == 0);
19+
return 0;
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
KNOWNBUG
2+
main.c
3+
--apply-code-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Applying code contracts currently also checks them.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// function_check_01
2+
3+
// This tests a simple example of a function with requires and
4+
// ensures which should both be satisfied.
5+
6+
#include <assert.h>
7+
8+
int min(int a, int b)
9+
__CPROVER_requires(a >= 0 && b >= 0)
10+
__CPROVER_ensures(__CPROVER_return_value <= a &&
11+
__CPROVER_return_value <= b &&
12+
(__CPROVER_return_value == a || __CPROVER_return_value == b)
13+
)
14+
{
15+
if(a <= b)
16+
{
17+
return a;
18+
}
19+
else
20+
{
21+
return b;
22+
}
23+
}
24+
25+
int main()
26+
{
27+
int x, y, z;
28+
__CPROVER_assume(x >= 0 && y >= 0);
29+
z = min(x, y);
30+
assert(z <= x);
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--apply-code-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
--check-code-contracts not implemented yet.
10+
--apply-code-contracts is the current name for the flag. This should be
11+
updated as the flag changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// function_check_02
2+
3+
// This test checks the use of quantifiers in ensures clauses.
4+
// A known bug (resolved in PR #2278) causes the use of quantifiers
5+
// in ensures to fail.
6+
7+
int initialize(int *arr)
8+
__CPROVER_ensures(
9+
__CPROVER_forall {int i; (0 <= i && i < 10) ==> arr[i] == i}
10+
)
11+
{
12+
for(int i = 0; i < 10; i++)
13+
{
14+
arr[i] = i;
15+
}
16+
17+
return 0;
18+
}
19+
20+
int main()
21+
{
22+
int arr[10];
23+
initialize(arr);
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
KNOWNBUG
2+
main.c
3+
--check-code-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Ensures statements currently do not allow quantified predicates unless the
10+
function has void return type.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// function_check_03
2+
3+
// This extends function_check_02's test of quantifiers in ensures
4+
// and adds in a loop invariant which can be used to prove the ensures.
5+
// This currently fails because side-effect checking in loop invariants is
6+
// incorrect.
7+
8+
void initialize(int *arr, int len)
9+
__CPROVER_ensures(
10+
__CPROVER_forall {int i; (0 <= i && i < len) ==> arr[i] == i}
11+
)
12+
{
13+
for(int i = 0; i < len; i++)
14+
__CPROVER_loop_invariant(
15+
__CPROVER_forall {int j; (0 <= j && j < i) ==> arr[j] == j}
16+
)
17+
{
18+
arr[i] = i;
19+
}
20+
}
21+
22+
int main()
23+
{
24+
int arr[10];
25+
initialize(arr, 10);
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
KNOWNBUG
2+
main.c
3+
--check-code-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Loop invariants currently do not support memory reads in at least some
10+
circumstances.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// function_check_04
2+
3+
// Note that this test is supposed to have an incorrect contract.
4+
// We verify that checking this faulty contract (correctly) yields a failure.
5+
6+
#include <assert.h>
7+
8+
int foo()
9+
__CPROVER_ensures(__CPROVER_return_value == 0)
10+
{
11+
return 1;
12+
}
13+
14+
int main()
15+
{
16+
int x = foo();
17+
assert(x == 0);
18+
return 0;
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--apply-code-contracts
4+
^\[main.assertion.1\] assertion x == 0: SUCCESS$
5+
^\[foo.1\] : FAILURE$
6+
^VERIFICATION FAILED$
7+
--
8+
--
9+
--check-code-contracts not implemented yet.
10+
--apply-code-contracts is the current name for the flag. This should be
11+
updated as the flag changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// function_check_05
2+
3+
// This test checks that when a function call is replaced by an invariant,
4+
// it adequately havocs the locations modified by the function.
5+
// This test currently fails because the analysis of what is modified by
6+
// a function is flawed.
7+
8+
#include <assert.h>
9+
10+
int foo(int *x)
11+
__CPROVER_ensures(__CPROVER_return_value == 1)
12+
{
13+
*x = 1;
14+
return 1;
15+
}
16+
17+
int main()
18+
{
19+
int y = 0;
20+
int z = foo(&y);
21+
// This assert should fail.
22+
assert(y == 0);
23+
// This one should succeed.
24+
assert(z == 1);
25+
return 0;
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
KNOWNBUG
2+
main.c
3+
--check-code-contracts
4+
^\[main.assertion.1\] assertion y == 0: FAILURE$
5+
^\[main.assertion.2\] assertion z == 1: SUCCESS$
6+
^\[foo.1\] : SUCCESS$
7+
^VERIFICATION SUCCESSFUL$
8+
--
9+
--
10+
Contract checking does not properly havoc function calls.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// function_check_mem_01
2+
3+
// This test checks the use of pointer-related predicates in assumptions and
4+
// requires.
5+
// This test currently fails because of the lack of support for assuming
6+
// pointer predicates.
7+
8+
#include <stddef.h>
9+
10+
#define __CPROVER_VALID_MEM(ptr, size) \
11+
__CPROVER_POINTER_OBJECT((ptr)) != __CPROVER_POINTER_OBJECT(NULL) && \
12+
!__CPROVER_invalid_pointer((ptr)) && \
13+
__CPROVER_POINTER_OBJECT((ptr)) != \
14+
__CPROVER_POINTER_OBJECT(__CPROVER_deallocated) && \
15+
__CPROVER_POINTER_OBJECT((ptr)) != \
16+
__CPROVER_POINTER_OBJECT(__CPROVER_dead_object) && \
17+
(__builtin_object_size((ptr), 1) >= (size) && \
18+
__CPROVER_POINTER_OFFSET((ptr)) >= 0l || \
19+
__CPROVER_DYNAMIC_OBJECT((ptr))) && \
20+
(__CPROVER_POINTER_OFFSET((ptr)) >= 0 && \
21+
__CPROVER_malloc_size >= (size) + __CPROVER_POINTER_OFFSET((ptr)) || \
22+
__CPROVER_POINTER_OBJECT((ptr)) != \
23+
__CPROVER_POINTER_OBJECT(__CPROVER_malloc_object))
24+
25+
typedef struct bar
26+
{
27+
int x;
28+
int y;
29+
int z;
30+
} bar;
31+
32+
void foo(bar *x)
33+
__CPROVER_requires(__CPROVER_VALID_MEM(x, sizeof(bar)))
34+
{
35+
x->x += 1;
36+
return
37+
}
38+
39+
int main()
40+
{
41+
bar *y;
42+
__CPROVER_assume(__CPROVER_VALID_MEM(y, sizeof(bar)));
43+
y->x = 0;
44+
return 0;
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
KNOWNBUG
2+
main.c
3+
--check-code-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
CBMC currently does not support assumptions about pointers in the general way
10+
that other assumptions are supported.
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// invar_check_01
2+
3+
// This test checks that a basic loop invariant can be proven and used in
4+
// combination with the negation of the loop guard to get a result.
5+
6+
#include <assert.h>
7+
8+
int main()
9+
{
10+
int r;
11+
__CPROVER_assume(r >= 0);
12+
while(r > 0)
13+
__CPROVER_loop_invariant(r >= 0)
14+
{
15+
--r;
16+
}
17+
assert(r == 0);
18+
19+
return 0;
20+
}

0 commit comments

Comments
 (0)