Skip to content

Commit b847942

Browse files
author
Remi Delmas
committed
Function contracts: skip assigns clause checking on function parameters and auxiliary variables
1 parent eeddb3f commit b847942

File tree

18 files changed

+85
-46
lines changed

18 files changed

+85
-46
lines changed

regression/contracts/assigns_enforce_04/test.desc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ main.c
33
--enforce-contract f1
44
^EXIT=0$
55
^SIGNAL=0$
6-
^\[f1.\d+\] line \d+ Check that x2 is assignable: SUCCESS$
7-
^\[f1.\d+\] line \d+ Check that y2 is assignable: SUCCESS$
8-
^\[f1.\d+\] line \d+ Check that z2 is assignable: SUCCESS$
9-
^\[f2.\d+\] line \d+ Check that x3 is assignable: SUCCESS$
10-
^\[f2.\d+\] line \d+ Check that y3 is assignable: SUCCESS$
11-
^\[f2.\d+\] line \d+ Check that z3 is assignable: SUCCESS$
126
^\[f3.\d+\] line \d+ Check that \*x3 is assignable: SUCCESS$
137
^\[f3.\d+\] line \d+ Check that \*y3 is assignable: SUCCESS$
148
^\[f3.\d+\] line \d+ Check that \*z3 is assignable: SUCCESS$

regression/contracts/assigns_enforce_05/test.desc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ main.c
33
--enforce-contract f1 --enforce-contract f2 --enforce-contract f3
44
^EXIT=0$
55
^SIGNAL=0$
6-
^\[f1.1\] line \d+ .*: SUCCESS$
76
^VERIFICATION SUCCESSFUL$
87
--
98
--

regression/contracts/assigns_enforce_18/test.desc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ main.c
77
^\[bar.\d+\] line \d+ Check that \*b is assignable: SUCCESS$
88
^\[baz.\d+\] line \d+ Check that POINTER_OBJECT\(\(void \*\)c\) is assignable: FAILURE$
99
^\[baz.\d+\] line \d+ Check that \*a is assignable: SUCCESS$
10-
^\[foo.\d+\] line \d+ Check that a is assignable: SUCCESS$
1110
^\[foo.\d+\] line \d+ Check that yp is assignable: SUCCESS$
1211
^\[foo.\d+\] line \d+ Check that z is assignable: SUCCESS$
1312
^\[foo.\d+\] line \d+ Check that \*xp is assignable: SUCCESS$

regression/contracts/assigns_enforce_21/test.desc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ main.c
66
main.c function bar
77
^\[bar.\d+\] line \d+ Check that \*y is assignable: SUCCESS$
88
^\[bar.\d+\] line \d+ Check that x is assignable: FAILURE$
9-
^\[baz.\d+\] line \d+ Check that w is assignable: SUCCESS$
10-
^\[foo.\d+\] line \d+ Check that w is assignable: SUCCESS$
11-
^\[foo.\d+\] line \d+ Check that z is assignable: SUCCESS$
129
^VERIFICATION FAILED$
1310
--
1411
--

regression/contracts/assigns_enforce_free_dead/test.desc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ main.c
1010
^\[foo.\d+\] line \d+ Check that a is assignable: SUCCESS$
1111
^\[foo.\d+\] line \d+ Check that q is assignable: SUCCESS$
1212
^\[foo.\d+\] line \d+ Check that w is assignable: SUCCESS$
13-
^\[foo.\d+\] line \d+ Check that x is assignable: SUCCESS$
1413
^\[foo.\d+\] line \d+ Check that y is assignable: SUCCESS$
1514
^\[foo.\d+\] line \d+ Check that z is assignable: SUCCESS$
1615
^\[foo.\d+\] line \d+ Check that POINTER_OBJECT\(\(void \*\)z\) is assignable: SUCCESS$
@@ -25,7 +24,6 @@ main.c
2524
^\[foo.\d+\] line \d+ Check that a is assignable: FAILURE$
2625
^\[foo.\d+\] line \d+ Check that q is assignable: FAILURE$
2726
^\[foo.\d+\] line \d+ Check that w is assignable: FAILURE$
28-
^\[foo.\d+\] line \d+ Check that x is assignable: FAILURE$
2927
^\[foo.\d+\] line \d+ Check that y is assignable: FAILURE$
3028
^\[foo.\d+\] line \d+ Check that z is assignable: FAILURE$
3129
^\[foo.\d+\] line \d+ Check that POINTER_OBJECT\(\(void \*\)z\) is assignable: FAILURE$

regression/contracts/assigns_enforce_structs_04/test.desc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ main.c
66
^\[f1.\d+\] line \d+ Check that p->y is assignable: FAILURE$
77
^\[f2.\d+\] line \d+ Check that p->x is assignable: FAILURE$
88
^\[f3.\d+\] line \d+ Check that p->y is assignable: SUCCESS$
9-
^\[f4.\d+\] line \d+ Check that p is assignable: SUCCESS$
109
^VERIFICATION FAILED$
1110
--
1211
--

regression/contracts/assigns_enforce_subfunction_calls/test.desc

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,15 @@ main.c
33
--enforce-contract foo
44
^EXIT=10$
55
^SIGNAL=0$
6-
^main.c function bar$
7-
^\[bar.1\] line \d+ Check that x is assignable: SUCCESS$
8-
^\[bar.2\] line \d+ Check that y is assignable: SUCCESS$
9-
^\[bar.3\] line \d+ Check that x is assignable: SUCCESS$
10-
^\[bar.4\] line \d+ Check that y is assignable: SUCCESS$
116
^main.c function baz$
127
^\[baz.1\] line \d+ Check that \*x is assignable: SUCCESS$
138
^\[baz.2\] line \d+ Check that \*x is assignable: SUCCESS$
149
^\[baz.3\] line \d+ Check that \*x is assignable: FAILURE$
1510
^\[baz.4\] line \d+ Check that \*x is assignable: FAILURE$
1611
^main.c function foo$
17-
^\[foo.1\] line \d+ Check that x is assignable: SUCCESS$
18-
^\[foo.2\] line \d+ Check that y is assignable: SUCCESS$
1912
^\[foo.assertion.1\] line \d+ foo.x.set: SUCCESS$
20-
^\[foo.3\] line \d+ Check that x is assignable: SUCCESS$
21-
^\[foo.4\] line \d+ Check that y is assignable: SUCCESS$
2213
^\[foo.assertion.2\] line \d+ foo.local.set: SUCCESS$
23-
^\[foo.5\] line \d+ Check that x is assignable: SUCCESS$
24-
^\[foo.6\] line \d+ Check that y is assignable: SUCCESS$
2514
^\[foo.assertion.3\] line \d+ foo.y.set: SUCCESS$
26-
^\[foo.7\] line \d+ Check that x is assignable: SUCCESS$
27-
^\[foo.8\] line \d+ Check that y is assignable: SUCCESS$
2815
^\[foo.assertion.4\] line \d+ foo.z.set: SUCCESS$
2916
^VERIFICATION FAILED$
3017
--

regression/contracts/assigns_function_pointer/test.desc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ main.c
33
--enforce-contract bar
44
^EXIT=0$
55
^SIGNAL=0$
6-
^\[bar.1\] line \d+ Check that fun\_ptr is assignable: SUCCESS$
76
^\[main.assertion.\d+\] line \d+ assertion x \=\= 0: SUCCESS$
87
^\[main.assertion.\d+\] line \d+ assertion x \=\= 1: SUCCESS$
98
^VERIFICATION SUCCESSFUL$

regression/contracts/assigns_type_checking_valid_cases/test.desc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@ main.c
33
--enforce-contract foo1 --enforce-contract foo2 --enforce-contract foo3 --enforce-contract foo4 --enforce-contract foo5 --enforce-contract foo6 --enforce-contract foo7 --enforce-contract foo8 --enforce-contract foo9 --enforce-contract foo10 _ --pointer-primitive-check
44
^EXIT=0$
55
^SIGNAL=0$
6-
^\[foo1.\d+\] line \d+ Check that a is assignable: SUCCESS$
76
^\[foo10.\d+\] line \d+ Check that buffer->len is assignable: SUCCESS$
87
^\[foo10.\d+\] line \d+ Check that buffer->aux\.allocated is assignable: SUCCESS$
9-
^\[foo2.\d+\] line \d+ Check that b is assignable: SUCCESS$
10-
^\[foo3.\d+\] line \d+ Check that b is assignable: SUCCESS$
118
^\[foo3.\d+\] line \d+ Check that y is assignable: SUCCESS$
12-
^\[foo4.\d+\] line \d+ Check that b is assignable: SUCCESS$
139
^\[foo4.\d+\] line \d+ Check that \*c is assignable: SUCCESS$
1410
^\[foo4.\d+\] line \d+ Check that \*x is assignable: SUCCESS$
1511
^\[foo5.\d+\] line \d+ Check that buffer.data is assignable: SUCCESS$
@@ -28,7 +24,6 @@ main.c
2824
^\[foo8.\d+\] line \d+ Check that array\[\(.* int\)7\] is assignable: SUCCESS$
2925
^\[foo8.\d+\] line \d+ Check that array\[\(.* int\)8\] is assignable: SUCCESS$
3026
^\[foo8.\d+\] line \d+ Check that array\[\(.* int\)9\] is assignable: SUCCESS$
31-
^\[foo9.\d+\] line \d+ Check that array is assignable: SUCCESS$
3227
^VERIFICATION SUCCESSFUL$
3328
--
3429
Checks whether CBMC parses correctly all standard cases for assigns clauses.

regression/contracts/assigns_validity_pointer_02/test.desc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ main.c
77
^\[bar.\d+\] line \d+ Check that \*x is assignable: SUCCESS$
88
^\[bar.\d+\] line \d+ Check that \*y is assignable: SUCCESS$
99
^\[baz.\d+\] line \d+ Check that \*z is assignable: SUCCESS$
10-
^\[foo.\d+\] line \d+ Check that x is assignable: SUCCESS$
11-
^\[foo.\d+\] line \d+ Check that y is assignable: SUCCESS$
1210
^\[foo.\d+\] line \d+ Check that \*x is assignable: SUCCESS$
1311
^VERIFICATION SUCCESSFUL$
1412
--

regression/contracts/history-pointer-enforce-10/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ void bar(struct pair *p) __CPROVER_assigns(p->y)
2323
p->y = (p->y + 5);
2424
}
2525

26-
void baz(struct pair p) __CPROVER_assigns(p)
26+
void baz(struct pair p) __CPROVER_assigns()
2727
__CPROVER_ensures(p == __CPROVER_old(p))
2828
{
2929
struct pair pp = p;

regression/contracts/history-pointer-enforce-10/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ main.c
77
^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: SUCCESS$
88
^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: SUCCESS$
99
^\[bar.\d+\] line \d+ Check that p->y is assignable: SUCCESS$
10-
^\[baz.\d+\] line \d+ Check that p is assignable: SUCCESS$
11-
^\[baz.\d+\] line \d+ Check that p is assignable: SUCCESS$
1210
^\[foo.\d+\] line \d+ Check that \*p->y is assignable: SUCCESS$
1311
^\[foo.\d+\] line \d+ Check that z is assignable: SUCCESS$
1412
^\[main.assertion.\d+\] line \d+ assertion \*\(p->y\) == 7: SUCCESS$
@@ -19,3 +17,5 @@ main.c
1917
This test checks that history variables are supported for structs, symbols, and
2018
struct members. By using the --enforce-contract flag, the postcondition
2119
(with history variable) is asserted. In this case, this assertion should pass.
20+
Note: A function is always authorized to assign the variables that store
21+
its arguments, there is no need to mention them in the assigns clause.

regression/contracts/test_aliasing_ensure_indirect/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#include <stdbool.h>
33
#include <stdlib.h>
44

5-
void bar(int *z) __CPROVER_assigns(z)
5+
void bar(int *z) __CPROVER_assigns()
66
__CPROVER_ensures(__CPROVER_is_fresh(z, sizeof(int)))
77
{
88
z = malloc(sizeof(*z));

regression/contracts/test_aliasing_ensure_indirect/test.desc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ main.c
44
^EXIT=0$
55
^SIGNAL=0$
66
\[postcondition.\d+\] file main.c line \d+ Check ensures clause: SUCCESS
7-
\[bar.\d+\] line \d+ Check that z is assignable: SUCCESS
87
\[foo.\d+\] line \d+ Check that \*x is assignable: SUCCESS
98
\[main.assertion.\d+\] line \d+ assertion \!\(n \< 4\): SUCCESS
109
^VERIFICATION SUCCESSFUL$

src/goto-instrument/contracts/contracts.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,13 @@ void code_contractst::check_apply_loop_contracts(
309309

310310
// Perform write set instrumentation on the entire loop.
311311
check_frame_conditions(
312-
function_name, goto_function.body, loop_head, loop_end, loop_assigns);
312+
function_name,
313+
goto_function.body,
314+
loop_head,
315+
loop_end,
316+
loop_assigns,
317+
// do not skip checks on function parameter assignments
318+
false);
313319

314320
havoc_assigns_targetst havoc_gen(to_havoc, ns);
315321
havoc_gen.append_full_havoc_code(
@@ -1171,7 +1177,9 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
11711177
function_obj->second.body,
11721178
instruction_it,
11731179
function_obj->second.body.instructions.end(),
1174-
assigns);
1180+
assigns,
1181+
// skip checks on function parameter assignments
1182+
true);
11751183

11761184
return false;
11771185
}
@@ -1181,14 +1189,21 @@ void code_contractst::check_frame_conditions(
11811189
goto_programt &body,
11821190
goto_programt::targett instruction_it,
11831191
const goto_programt::targett &instruction_end,
1184-
assigns_clauset &assigns)
1192+
assigns_clauset &assigns,
1193+
bool skip_parameter_assigns)
11851194
{
11861195
for(; instruction_it != instruction_end; ++instruction_it)
11871196
{
11881197
const auto &pragmas = instruction_it->source_location().get_pragmas();
11891198
if(pragmas.find(CONTRACT_PRAGMA_DISABLE_ASSIGNS_CHECK) != pragmas.end())
11901199
continue;
11911200

1201+
if(skip_parameter_assigns && is_parameter_assign(instruction_it, ns))
1202+
continue;
1203+
1204+
if(is_auxiliary_decl_dead_or_assign(instruction_it, ns))
1205+
continue;
1206+
11921207
// Do not instrument this instruction again in the future,
11931208
// since we are going to instrument it now below.
11941209
add_pragma_disable_assigns_check(*instruction_it);

src/goto-instrument/contracts/contracts.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ class code_contractst
132132
goto_programt &,
133133
goto_programt::targett,
134134
const goto_programt::targett &,
135-
assigns_clauset &);
135+
assigns_clauset &,
136+
bool skip_parameter_assigns);
136137

137138
/// Inserts an assertion into the goto program to ensure that
138139
/// an expression is within the assignable memory frame.

src/goto-instrument/contracts/utils.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,50 @@ void disable_pointer_checks(source_locationt &source_location)
163163
source_location.add_pragma("disable:pointer-primitive-check");
164164
source_location.add_pragma("disable:pointer-overflow-check");
165165
}
166+
167+
bool is_parameter_assign(
168+
const goto_programt::targett &instruction_it,
169+
namespacet &ns)
170+
{
171+
optionalt<symbol_exprt> sym = {};
172+
173+
// extract symbol
174+
if(instruction_it->is_assign())
175+
{
176+
const auto &lhs = instruction_it->assign_lhs();
177+
if(can_cast_expr<symbol_exprt>(lhs))
178+
sym = to_symbol_expr(lhs);
179+
}
180+
181+
// check condition
182+
if(sym.has_value())
183+
return ns.lookup(sym.value().get_identifier()).is_parameter;
184+
185+
return false;
186+
}
187+
188+
bool is_auxiliary_decl_dead_or_assign(
189+
const goto_programt::targett &instruction_it,
190+
namespacet &ns)
191+
{
192+
optionalt<symbol_exprt> sym = {};
193+
194+
// extract symbol
195+
if(instruction_it->is_decl())
196+
sym = instruction_it->decl_symbol();
197+
else if(instruction_it->is_dead())
198+
sym = instruction_it->dead_symbol();
199+
else if(instruction_it->is_assign())
200+
{
201+
const auto &lhs = instruction_it->assign_lhs();
202+
if(can_cast_expr<symbol_exprt>(lhs))
203+
sym = to_symbol_expr(lhs);
204+
}
205+
206+
// check condition
207+
if(sym.has_value())
208+
return ns.lookup(sym.value().get_identifier()).is_auxiliary;
209+
210+
return false;
211+
}
212+

src/goto-instrument/contracts/utils.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,29 @@ void insert_before_swap_and_advance(
112112
/// \param mode: The mode for the new symbol, e.g. ID_C, ID_java.
113113
/// \param symtab: The symbol table to which the new symbol is to be added.
114114
/// \param suffix: Suffix to use to generate the unique name
115-
/// \param is_auxiliary: Do not print symbol in traces if true (default = false)
115+
/// \param is_auxiliary: Do not print symbol in traces if true (default = true)
116116
/// \return The new symbolt object.
117117
const symbolt &new_tmp_symbol(
118118
const typet &type,
119119
const source_locationt &location,
120120
const irep_idt &mode,
121121
symbol_table_baset &symtab,
122122
std::string suffix = "tmp_cc",
123-
bool is_auxiliary = false);
123+
bool is_auxiliary = true);
124124

125125
/// Add disable pragmas for all pointer checks on the given location
126126
void disable_pointer_checks(source_locationt &source_location);
127127

128+
/// Returns true iff the instruction is a `DECL x`, `DEAD x`,
129+
/// or `ASSIGN x := expr` where `x` has the `is_parameter` flag set.
130+
bool is_parameter_assign(
131+
const goto_programt::targett &instruction_it,
132+
namespacet &ns);
133+
134+
/// Returns true iff the instruction is a `DECL x`, `DEAD x`,
135+
/// or `ASSIGN x := expr` where `x` has the `is_auxiliary` flag set.
136+
bool is_auxiliary_decl_dead_or_assign(
137+
const goto_programt::targett &instruction_it,
138+
namespacet &ns);
139+
128140
#endif // CPROVER_GOTO_INSTRUMENT_CONTRACTS_UTILS_H

0 commit comments

Comments
 (0)