Skip to content

Commit 078b659

Browse files
committed
Check subset relationship of assigns clause during replacement
Signed-off-by: Felipe R. Monteiro <[email protected]>
1 parent 3948798 commit 078b659

File tree

7 files changed

+82
-14
lines changed

7 files changed

+82
-14
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <stdlib.h>
2+
3+
int x;
4+
int *z = &x;
5+
6+
void bar() __CPROVER_assigns(*z)
7+
{
8+
}
9+
10+
void foo() __CPROVER_assigns()
11+
{
12+
bar();
13+
}
14+
15+
int main()
16+
{
17+
foo();
18+
return 0;
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
main.c
3+
--enforce-contract foo --replace-call-with-contract bar _ --pointer-primitive-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
\[\d+\] file main.c line \d+ Check that bar\'s assigns clause is a subset of foo\'s assigns clause: FAILURE$
7+
\[\d+\] file main.c line \d+ Check that \*z is assignable: FAILURE$
8+
^.* 2 of \d+ failed \(\d+ iteration.*\)$
9+
^VERIFICATION FAILED$
10+
--
11+
\[\d+\] file main.c line \d+ Check that bar\'s assigns clause is a subset of foo\'s assigns clause: SUCCESS$
12+
\[\d+\] file main.c line \d+ Check that \*z is assignable: SUCCESS$
13+
^VERIFICATION SUCCESSFUL$
14+
--
15+
Checks whether CBMC properly evaluates subset relationship on assigns
16+
during replacement.

regression/contracts/assigns_validity_pointer_01/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ void baz() __CPROVER_assigns(*z) __CPROVER_ensures(z == NULL || *z == 7)
1717
*z = 7;
1818
}
1919

20-
void foo(int *x) __CPROVER_assigns(*x) __CPROVER_requires(*x > 0)
20+
void foo(int *x) __CPROVER_assigns(*x, *z) __CPROVER_requires(*x > 0)
2121
__CPROVER_ensures(*x == 3)
2222
{
2323
bar(x, NULL);
24-
z == NULL;
2524
baz();
2625
}
2726

2827
int main()
2928
{
3029
int n;
30+
z = malloc(sizeof(*z));
3131
foo(&n);
3232

3333
assert(n == 3);

regression/contracts/assigns_validity_pointer_02/test.desc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ main.c
33
--enforce-contract foo
44
^EXIT=0$
55
^SIGNAL=0$
6+
^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: SUCCESS$
7+
^\[foo.\d+\] line \d+ Check that bar\'s assigns clause is a subset of foo\'s assigns clause: SUCCESS$
8+
^\[foo.\d+\] line \d+ Check that \*x is assignable: SUCCESS$
9+
^\[foo.\d+\] line \d+ Check that baz\'s assigns clause is a subset of foo\'s assigns clause: SUCCESS$
610
^VERIFICATION SUCCESSFUL$
7-
//^([foo\.1] line 15 assertion: FAILURE)
811
--
9-
\[foo\.1\] line 24 assertion: FAILURE
10-
\[foo\.3\] line 27 assertion: FAILURE
12+
^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: FAILURE$
13+
^\[foo.\d+\] line \d+ Check that bar\'s assigns clause is a subset of foo\'s assigns clause: FAILURE$
14+
^\[foo.\d+\] line \d+ Check that \*x is assignable: FAILURE$
15+
^\[foo.\d+\] line \d+ Check that baz\'s assigns clause is a subset of foo\'s assigns clause: FAILURE$
1116
--
1217
Verification:
1318
This test checks support for a NULL pointer that is assigned to by

regression/contracts/assigns_validity_pointer_04/test.desc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ main.c
33
--enforce-contract foo --replace-call-with-contract bar --replace-call-with-contract baz _ --pointer-primitive-check
44
^EXIT=10$
55
^SIGNAL=0$
6+
^\[\d+\] file main.c line \d+ Check that bar\'s assigns clause is a subset of foo\'s assigns clause: FAILURE$
7+
^\[\d+\] file main.c line \d+ Check that baz\'s assigns clause is a subset of foo\'s assigns clause: FAILURE$
68
^\[foo.\d+\] line \d+ Check that z is assignable: FAILURE$
7-
^.* 1 of \d+ failed \(\d+ iteration.*\)$
9+
^.* 3 of \d+ failed \(\d+ iteration.*\)$
810
^VERIFICATION FAILED$
911
// bar
1012
ASSERT \*foo::x > 0

regression/contracts/test_aliasing_ensure_indirect/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ main.c
77
\[postcondition.\d+\] file main.c line \d+ Check ensures clause: SUCCESS
88
\[bar.\d+\] line \d+ Check that z is assignable: SUCCESS
99
\[foo.\d+\] line \d+ Check that \*x is assignable: SUCCESS
10-
\[foo.\d+\] line \d+ Check that callee's assigns clause is a subset of caller's: SUCCESS
10+
\[foo.\d+\] line \d+ Check that bar\'s assigns clause is a subset of foo\'s assigns clause: SUCCESS
1111
\[main.assertion.\d+\] line \d+ assertion \!\(n \< 4\): SUCCESS
1212
^VERIFICATION SUCCESSFUL$
1313
--

src/goto-instrument/contracts/contracts.cpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,31 @@ bool code_contractst::apply_function_contract(
601601
// in the assigns clause.
602602
if(assigns.is_not_nil())
603603
{
604-
assigns_clauset assigns_cause(assigns, log, ns);
605-
auto assigns_havoc = assigns_cause.generate_havoc_code();
604+
assigns_clauset assigns_clause(assigns, log, ns);
605+
606+
// Retrieve assigns clause of the caller function if exists.
607+
const irep_idt &caller_function = target->source_location.get_function();
608+
auto caller_assigns =
609+
to_code_with_contract_type(ns.lookup(caller_function).type).assigns();
610+
611+
if(caller_assigns.is_not_nil())
612+
{
613+
// check subset relationship of assigns clause for called function
614+
assigns_clauset caller_assigns_clause(caller_assigns, log, ns);
615+
goto_programt subset_check_assertion;
616+
subset_check_assertion.add(goto_programt::make_assertion(
617+
caller_assigns_clause.generate_subset_check(assigns_clause),
618+
assigns_clause.location));
619+
subset_check_assertion.instructions.back().source_location.set_comment(
620+
"Check that " + id2string(function) +
621+
"'s assigns clause is a subset of " + id2string(caller_function) +
622+
"'s assigns clause");
623+
insert_before_swap_and_advance(
624+
goto_program, target, subset_check_assertion);
625+
}
626+
627+
// Havoc all targets in global write set
628+
auto assigns_havoc = assigns_clause.generate_havoc_code();
606629

607630
// Insert the non-deterministic assignment immediately before the call site.
608631
insert_before_swap_and_advance(goto_program, target, assigns_havoc);
@@ -772,8 +795,8 @@ void code_contractst::instrument_call_statement(
772795
alias_assertion.instructions.back().source_location.set_comment(
773796
"Check that " + from_expr(ns, alias_expr.id(), alias_expr) +
774797
" is assignable");
775-
program.insert_before_swap(instruction_iterator, alias_assertion);
776-
++instruction_iterator;
798+
insert_before_swap_and_advance(
799+
program, instruction_iterator, alias_assertion);
777800
}
778801

779802
const symbolt &called_symbol = ns.lookup(called_name);
@@ -810,9 +833,12 @@ void code_contractst::instrument_call_statement(
810833
alias_assertion.add(goto_programt::make_assertion(
811834
subset_check, instruction_iterator->source_location));
812835
alias_assertion.instructions.back().source_location.set_comment(
813-
"Check that callee's assigns clause is a subset of caller's");
814-
program.insert_before_swap(instruction_iterator, alias_assertion);
815-
++instruction_iterator;
836+
"Check that " + id2string(called_name) +
837+
"'s assigns clause is a subset of " +
838+
id2string(instruction_iterator->source_location.get_function()) +
839+
"'s assigns clause");
840+
insert_before_swap_and_advance(
841+
program, instruction_iterator, alias_assertion);
816842
}
817843
}
818844

0 commit comments

Comments
 (0)