Skip to content

Commit d49ea09

Browse files
author
klaas
committed
Added an initial set of tests for contracts, which (expectedly) either fail or
will need to be redone once the new flags are added in. Fixed test descriptions to put comments in the correct place and updated some stylistic issues with test cases. Enabled tests that work (if with different flag name) in the current state to give a better sense of the initial state.
1 parent d17c990 commit d49ea09

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)