Skip to content

Commit 20a1ecf

Browse files
authored
Merge pull request #8486 from qinheping/infer_def_member
[CONTRACTS] Support alias of member pointers in loop assigns inference
2 parents f2a7665 + 2fd6095 commit 20a1ecf

File tree

3 files changed

+93
-9
lines changed

3 files changed

+93
-9
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
struct hole
2+
{
3+
int pos;
4+
};
5+
6+
void set_len(struct hole *h, unsigned long int new_len)
7+
{
8+
h->pos = new_len;
9+
}
10+
11+
int main()
12+
{
13+
int i = 0;
14+
struct hole h;
15+
h.pos = 0;
16+
for(i = 0; i < 5; i++)
17+
// __CPROVER_assigns(h.pos, i)
18+
__CPROVER_loop_invariant(h.pos == i)
19+
{
20+
set_len(&h, h.pos + 1);
21+
}
22+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^VERIFICATION SUCCESSFUL$
8+
--
9+
--
10+
This test checks assigns h->pos is inferred correctly.

src/goto-instrument/loop_utils.cpp

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,38 +53,90 @@ void get_assigns_lhs(
5353
assignst &assigns,
5454
std::function<bool(const exprt &)> predicate)
5555
{
56-
if(
57-
(lhs.id() == ID_symbol || lhs.id() == ID_member || lhs.id() == ID_index) &&
58-
predicate(lhs))
56+
assignst new_assigns;
57+
58+
if(lhs.id() == ID_symbol || lhs.id() == ID_index)
5959
{
60-
assigns.insert(lhs);
60+
// All variables `v` and their indexing expressions `v[idx]` are assigns.
61+
new_assigns.insert(lhs);
62+
}
63+
else if(lhs.id() == ID_member)
64+
{
65+
auto op = to_member_expr(lhs).struct_op();
66+
auto component_name = to_member_expr(lhs).get_component_name();
67+
68+
// Insert expressions of form `v.member`.
69+
if(op.id() == ID_symbol)
70+
{
71+
new_assigns.insert(lhs);
72+
}
73+
// For expressions of form `v->member`, insert all targets `u->member`,
74+
// where `u` and `v` alias.
75+
else if(op.id() == ID_dereference)
76+
{
77+
const pointer_arithmetict ptr(to_dereference_expr(op).pointer());
78+
for(const auto &mod : local_may_alias.get(t, ptr.pointer))
79+
{
80+
if(mod.id() == ID_unknown)
81+
{
82+
continue;
83+
}
84+
const exprt typed_mod =
85+
typecast_exprt::conditional_cast(mod, ptr.pointer.type());
86+
exprt to_insert;
87+
if(ptr.offset.is_nil())
88+
{
89+
// u->member
90+
to_insert = member_exprt(
91+
dereference_exprt{typed_mod}, component_name, lhs.type());
92+
}
93+
else
94+
{
95+
// (u+offset)->member
96+
to_insert = member_exprt(
97+
dereference_exprt{plus_exprt{typed_mod, ptr.offset}},
98+
component_name,
99+
lhs.type());
100+
}
101+
new_assigns.insert(to_insert);
102+
}
103+
}
61104
}
62105
else if(lhs.id() == ID_dereference)
63106
{
107+
// All dereference `*v` and their alias `*u` are assigns.
64108
const pointer_arithmetict ptr(to_dereference_expr(lhs).pointer());
65109
for(const auto &mod : local_may_alias.get(t, ptr.pointer))
66110
{
67-
const typecast_exprt typed_mod{mod, ptr.pointer.type()};
68111
if(mod.id() == ID_unknown)
69112
{
70113
continue;
71114
}
115+
const exprt typed_mod =
116+
typecast_exprt::conditional_cast(mod, ptr.pointer.type());
72117
exprt to_insert;
73118
if(ptr.offset.is_nil())
74119
to_insert = dereference_exprt{typed_mod};
75120
else
76121
to_insert = dereference_exprt{plus_exprt{typed_mod, ptr.offset}};
77-
if(predicate(to_insert))
78-
assigns.insert(std::move(to_insert));
122+
new_assigns.insert(std::move(to_insert));
79123
}
80124
}
81125
else if(lhs.id() == ID_if)
82126
{
83127
const if_exprt &if_expr = to_if_expr(lhs);
84128

85-
get_assigns_lhs(local_may_alias, t, if_expr.true_case(), assigns);
86-
get_assigns_lhs(local_may_alias, t, if_expr.false_case(), assigns);
129+
get_assigns_lhs(
130+
local_may_alias, t, if_expr.true_case(), assigns, predicate);
131+
get_assigns_lhs(
132+
local_may_alias, t, if_expr.false_case(), assigns, predicate);
87133
}
134+
135+
std::copy_if(
136+
new_assigns.begin(),
137+
new_assigns.end(),
138+
std::inserter(assigns, assigns.begin()),
139+
predicate);
88140
}
89141

90142
void get_assigns(

0 commit comments

Comments
 (0)