Skip to content

Commit 98c2968

Browse files
committed
Support alias of member pointers in loop assigns inference
1 parent f2a7665 commit 98c2968

File tree

3 files changed

+93
-8
lines changed

3 files changed

+93
-8
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 & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,60 @@ 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))
59+
{
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)
5964
{
60-
assigns.insert(lhs);
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+
74+
// For expressions of form `v->member`, insert all targets `u->member`,
75+
// where `u` and `v` alias.
76+
else if(op.id() == ID_dereference)
77+
{
78+
const pointer_arithmetict ptr(to_dereference_expr(op).pointer());
79+
for(const auto &mod : local_may_alias.get(t, ptr.pointer))
80+
{
81+
const typecast_exprt typed_mod{mod, ptr.pointer.type()};
82+
if(mod.id() == ID_unknown)
83+
{
84+
continue;
85+
}
86+
exprt to_insert;
87+
if(ptr.offset.is_nil())
88+
{
89+
// u->member
90+
to_insert = member_exprt(
91+
std::move(dereference_exprt{typed_mod}),
92+
component_name,
93+
lhs.type());
94+
}
95+
else
96+
{
97+
// (u+offset)->member
98+
to_insert = member_exprt(
99+
std::move(dereference_exprt{plus_exprt{typed_mod, ptr.offset}}),
100+
component_name,
101+
lhs.type());
102+
}
103+
new_assigns.insert(to_insert);
104+
}
105+
}
61106
}
62107
else if(lhs.id() == ID_dereference)
63108
{
109+
// All dereference `*v` and their alias `*u` are assigns.
64110
const pointer_arithmetict ptr(to_dereference_expr(lhs).pointer());
65111
for(const auto &mod : local_may_alias.get(t, ptr.pointer))
66112
{
@@ -74,17 +120,24 @@ void get_assigns_lhs(
74120
to_insert = dereference_exprt{typed_mod};
75121
else
76122
to_insert = dereference_exprt{plus_exprt{typed_mod, ptr.offset}};
77-
if(predicate(to_insert))
78-
assigns.insert(std::move(to_insert));
123+
new_assigns.insert(std::move(to_insert));
79124
}
80125
}
81126
else if(lhs.id() == ID_if)
82127
{
83128
const if_exprt &if_expr = to_if_expr(lhs);
84129

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);
130+
get_assigns_lhs(
131+
local_may_alias, t, if_expr.true_case(), assigns, predicate);
132+
get_assigns_lhs(
133+
local_may_alias, t, if_expr.false_case(), assigns, predicate);
87134
}
135+
136+
std::copy_if(
137+
new_assigns.begin(),
138+
new_assigns.end(),
139+
std::inserter(assigns, assigns.begin()),
140+
predicate);
88141
}
89142

90143
void get_assigns(

0 commit comments

Comments
 (0)