Skip to content

Commit 1657d97

Browse files
authored
Merge pull request #8313 from qinheping/feature/get_assigns_ignore_cprover_variable
[CONTRACTS] Ignore cprover symbols in loop assigns inference
2 parents b465e80 + b04d6f0 commit 1657d97

File tree

12 files changed

+186
-14
lines changed

12 files changed

+186
-14
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <assert.h>
2+
typedef struct test
3+
{
4+
int id;
5+
} test;
6+
7+
int main()
8+
{
9+
int r, s = 1;
10+
__CPROVER_assume(r >= 0);
11+
while(r > 0)
12+
// clang-format off
13+
__CPROVER_loop_invariant(r >= 0 && s == 1)
14+
__CPROVER_decreases(r)
15+
// clang-format on
16+
{
17+
s = 1;
18+
goto label_1;
19+
20+
if(1 == 1)
21+
goto label_0;
22+
23+
test newAlloc0 = {0};
24+
25+
if(1 == 1)
26+
goto label_1;
27+
28+
label_0:
29+
r--;
30+
31+
label_1:
32+
r--;
33+
}
34+
assert(r == 0);
35+
assert(s == 1);
36+
37+
return 0;
38+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
This test checks the assigns inference correctly
9+
ignore __CPROVER_going_to variables.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <assert.h>
2+
typedef struct test
3+
{
4+
int id;
5+
} test;
6+
7+
int main()
8+
{
9+
int r, s = 1;
10+
__CPROVER_assume(r >= 0);
11+
while(r > 0)
12+
// clang-format off
13+
__CPROVER_loop_invariant(r >= 0 && s == 1)
14+
__CPROVER_decreases(r)
15+
// clang-format on
16+
{
17+
s = 1;
18+
goto label_1;
19+
20+
if(1 == 1)
21+
goto label_0;
22+
23+
test newAlloc0 = {0};
24+
25+
if(1 == 1)
26+
goto label_1;
27+
28+
label_0:
29+
r--;
30+
31+
label_1:
32+
r--;
33+
}
34+
assert(r == 0);
35+
assert(s == 1);
36+
37+
return 0;
38+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
This test checks the assigns inference correctly
9+
ignore __CPROVER_going_to variables.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ void code_contractst::check_apply_loop_contracts(
220220
// and the inferred aliasing relation.
221221
try
222222
{
223-
get_assigns(local_may_alias, loop, to_havoc);
223+
infer_loop_assigns(local_may_alias, loop, to_havoc);
224224

225225
// remove loop-local symbols from the inferred set
226226
cfg_info.erase_locals(to_havoc);

src/goto-instrument/contracts/dynamic-frames/dfcc_infer_loop_assigns.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Remi Delmas, [email protected]
1313
#include <util/pointer_expr.h>
1414
#include <util/std_code.h>
1515

16+
#include <goto-instrument/contracts/utils.h>
1617
#include <goto-instrument/havoc_utils.h>
1718

1819
#include "dfcc_root_object.h"
@@ -53,7 +54,7 @@ assignst dfcc_infer_loop_assigns(
5354
{
5455
// infer
5556
assignst assigns;
56-
get_assigns(local_may_alias, loop_instructions, assigns);
57+
infer_loop_assigns(local_may_alias, loop_instructions, assigns);
5758

5859
// compute locals
5960
std::unordered_set<irep_idt> loop_locals;

src/goto-instrument/contracts/dynamic-frames/dfcc_is_cprover_symbol.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,7 @@ bool dfcc_is_cprover_static_symbol(const irep_idt &id)
151151
init_static_symbols(static_symbols);
152152
return static_symbols.find(id) != static_symbols.end() ||
153153
// auto objects from pointer derefs
154-
has_suffix(id2string(id), "$object");
154+
has_suffix(id2string(id), "$object") ||
155+
// going_to variables converted from goto statements
156+
has_prefix(id2string(id), CPROVER_PREFIX "going_to");
155157
}

src/goto-instrument/contracts/instrument_spec_assigns.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Date: January 2022
1919
#include <util/fresh_symbol.h>
2020
#include <util/pointer_offset_size.h>
2121
#include <util/pointer_predicates.h>
22+
#include <util/prefix.h>
2223
#include <util/simplify_expr.h>
2324

2425
#include <ansi-c/c_expr.h>
@@ -147,6 +148,13 @@ void instrument_spec_assignst::check_inclusion_assignment(
147148
const exprt &lhs,
148149
goto_programt &dest) const
149150
{
151+
// Don't check assignable for CPROVER symbol
152+
if(
153+
lhs.id() == ID_symbol &&
154+
has_prefix(id2string(to_symbol_expr(lhs).get_identifier()), CPROVER_PREFIX))
155+
{
156+
return;
157+
}
150158
// create temporary car but do not track
151159
const auto car = create_car_expr(true_exprt{}, lhs);
152160
create_snapshot(car, dest);

src/goto-instrument/contracts/utils.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Date: September 2021
1818
#include <util/pointer_expr.h>
1919
#include <util/pointer_offset_size.h>
2020
#include <util/pointer_predicates.h>
21+
#include <util/prefix.h>
2122
#include <util/simplify_expr.h>
2223
#include <util/symbol.h>
2324

@@ -338,6 +339,22 @@ bool is_assigns_clause_replacement_tracking_comment(const irep_idt &comment)
338339
std::string::npos;
339340
}
340341

342+
void infer_loop_assigns(
343+
const local_may_aliast &local_may_alias,
344+
const loopt &loop,
345+
assignst &assigns)
346+
{
347+
// Assign targets should not include cprover symbols.
348+
get_assigns(local_may_alias, loop, assigns, [](const exprt &e) {
349+
if(e.id() == ID_symbol)
350+
{
351+
const auto &s = expr_try_dynamic_cast<symbol_exprt>(e);
352+
return !has_prefix(id2string(s->get_identifier()), CPROVER_PREFIX);
353+
}
354+
return true;
355+
});
356+
}
357+
341358
void widen_assigns(assignst &assigns, const namespacet &ns)
342359
{
343360
assignst result;

src/goto-instrument/contracts/utils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ Date: September 2021
1616
#include <goto-programs/goto_model.h>
1717
#include <goto-programs/loop_ids.h>
1818

19+
#include <analyses/local_may_alias.h>
1920
#include <goto-instrument/havoc_utils.h>
21+
#include <goto-instrument/loop_utils.h>
2022

2123
#include <vector>
2224

@@ -214,6 +216,12 @@ irep_idt make_assigns_clause_replacement_tracking_comment(
214216
/// \ref make_assigns_clause_replacement_tracking_comment.
215217
bool is_assigns_clause_replacement_tracking_comment(const irep_idt &comment);
216218

219+
/// Infer loop assigns using alias analysis result `local_may_alias`.
220+
void infer_loop_assigns(
221+
const local_may_aliast &local_may_alias,
222+
const loopt &loop,
223+
assignst &assigns);
224+
217225
/// Widen expressions in \p assigns with the following strategy.
218226
/// If an expression is an array index or object dereference expression,
219227
/// with a non-constant offset, e.g. a[i] or *(b+i) with a non-constant `i`,

src/goto-instrument/loop_utils.cpp

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,24 @@ void get_assigns_lhs(
4242
const exprt &lhs,
4343
assignst &assigns)
4444
{
45-
if(lhs.id() == ID_symbol || lhs.id() == ID_member || lhs.id() == ID_index)
45+
get_assigns_lhs(
46+
local_may_alias, t, lhs, assigns, [](const exprt &e) { return true; });
47+
}
48+
49+
void get_assigns_lhs(
50+
const local_may_aliast &local_may_alias,
51+
goto_programt::const_targett t,
52+
const exprt &lhs,
53+
assignst &assigns,
54+
std::function<bool(const exprt &)> predicate)
55+
{
56+
if(
57+
(lhs.id() == ID_symbol || lhs.id() == ID_member || lhs.id() == ID_index) &&
58+
predicate(lhs))
59+
{
4660
assigns.insert(lhs);
47-
else if(lhs.id()==ID_dereference)
61+
}
62+
else if(lhs.id() == ID_dereference)
4863
{
4964
const pointer_arithmetict ptr(to_dereference_expr(lhs).pointer());
5065
for(const auto &mod : local_may_alias.get(t, ptr.pointer))
@@ -54,15 +69,18 @@ void get_assigns_lhs(
5469
{
5570
continue;
5671
}
72+
exprt to_insert;
5773
if(ptr.offset.is_nil())
58-
assigns.insert(dereference_exprt{typed_mod});
74+
to_insert = dereference_exprt{typed_mod};
5975
else
60-
assigns.insert(dereference_exprt{plus_exprt{typed_mod, ptr.offset}});
76+
to_insert = dereference_exprt{plus_exprt{typed_mod, ptr.offset}};
77+
if(predicate(to_insert))
78+
assigns.insert(std::move(to_insert));
6179
}
6280
}
63-
else if(lhs.id()==ID_if)
81+
else if(lhs.id() == ID_if)
6482
{
65-
const if_exprt &if_expr=to_if_expr(lhs);
83+
const if_exprt &if_expr = to_if_expr(lhs);
6684

6785
get_assigns_lhs(local_may_alias, t, if_expr.true_case(), assigns);
6886
get_assigns_lhs(local_may_alias, t, if_expr.false_case(), assigns);
@@ -74,20 +92,29 @@ void get_assigns(
7492
const loopt &loop,
7593
assignst &assigns)
7694
{
77-
for(loopt::const_iterator
78-
i_it=loop.begin(); i_it!=loop.end(); i_it++)
95+
get_assigns(
96+
local_may_alias, loop, assigns, [](const exprt &e) { return true; });
97+
}
98+
99+
void get_assigns(
100+
const local_may_aliast &local_may_alias,
101+
const loopt &loop,
102+
assignst &assigns,
103+
std::function<bool(const exprt &)> predicate)
104+
{
105+
for(loopt::const_iterator i_it = loop.begin(); i_it != loop.end(); i_it++)
79106
{
80-
const goto_programt::instructiont &instruction=**i_it;
107+
const goto_programt::instructiont &instruction = **i_it;
81108

82109
if(instruction.is_assign())
83110
{
84111
const exprt &lhs = instruction.assign_lhs();
85-
get_assigns_lhs(local_may_alias, *i_it, lhs, assigns);
112+
get_assigns_lhs(local_may_alias, *i_it, lhs, assigns, predicate);
86113
}
87114
else if(instruction.is_function_call())
88115
{
89116
const exprt &lhs = instruction.call_lhs();
90-
get_assigns_lhs(local_may_alias, *i_it, lhs, assigns);
117+
get_assigns_lhs(local_may_alias, *i_it, lhs, assigns, predicate);
91118
}
92119
}
93120
}

src/goto-instrument/loop_utils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,27 @@ void get_assigns(
2424
const loopt &loop,
2525
assignst &assigns);
2626

27+
/// get all assign targets that satisfy `predicate` within the loops.
28+
void get_assigns(
29+
const local_may_aliast &local_may_alias,
30+
const loopt &loop,
31+
assignst &assigns,
32+
std::function<bool(const exprt &)> predicate);
33+
2734
void get_assigns_lhs(
2835
const local_may_aliast &local_may_alias,
2936
goto_programt::const_targett t,
3037
const exprt &lhs,
3138
assignst &assigns);
3239

40+
/// get all assign targets that satisfy `predicate` from `lhs`.
41+
void get_assigns_lhs(
42+
const local_may_aliast &local_may_alias,
43+
goto_programt::const_targett t,
44+
const exprt &lhs,
45+
assignst &assigns,
46+
std::function<bool(const exprt &)> predicate);
47+
3348
goto_programt::targett get_loop_exit(const loopt &);
3449

3550
#endif // CPROVER_GOTO_INSTRUMENT_LOOP_UTILS_H

0 commit comments

Comments
 (0)