Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CONTRACTS] Support alias of member pointers in loop assigns inference #8486

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions regression/contracts/loop_assigns_inference-04/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
struct hole
{
int pos;
};

void set_len(struct hole *h, unsigned long int new_len)
{
h->pos = new_len;
}

int main()
{
int i = 0;
struct hole h;
h.pos = 0;
for(i = 0; i < 5; i++)
// __CPROVER_assigns(h.pos, i)
__CPROVER_loop_invariant(h.pos == i)
{
set_len(&h, h.pos + 1);
}
}
10 changes: 10 additions & 0 deletions regression/contracts/loop_assigns_inference-04/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--apply-loop-contracts
^EXIT=0$
^SIGNAL=0$
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
^VERIFICATION SUCCESSFUL$
--
--
This test checks assigns h->pos is inferred correctly.
70 changes: 61 additions & 9 deletions src/goto-instrument/loop_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,38 +53,90 @@ void get_assigns_lhs(
assignst &assigns,
std::function<bool(const exprt &)> predicate)
{
if(
(lhs.id() == ID_symbol || lhs.id() == ID_member || lhs.id() == ID_index) &&
predicate(lhs))
assignst new_assigns;

if(lhs.id() == ID_symbol || lhs.id() == ID_index)
{
assigns.insert(lhs);
// All variables `v` and their indexing expressions `v[idx]` are assigns.
new_assigns.insert(lhs);
}
else if(lhs.id() == ID_member)
{
auto op = to_member_expr(lhs).struct_op();
auto component_name = to_member_expr(lhs).get_component_name();

// Insert expressions of form `v.member`.
if(op.id() == ID_symbol)
{
new_assigns.insert(lhs);
}
// For expressions of form `v->member`, insert all targets `u->member`,
// where `u` and `v` alias.
else if(op.id() == ID_dereference)
{
const pointer_arithmetict ptr(to_dereference_expr(op).pointer());
for(const auto &mod : local_may_alias.get(t, ptr.pointer))
{
if(mod.id() == ID_unknown)
{
continue;
}
const exprt typed_mod =
typecast_exprt::conditional_cast(mod, ptr.pointer.type());
exprt to_insert;
if(ptr.offset.is_nil())
{
// u->member
to_insert = member_exprt(
dereference_exprt{typed_mod}, component_name, lhs.type());
}
else
{
// (u+offset)->member
to_insert = member_exprt(
dereference_exprt{plus_exprt{typed_mod, ptr.offset}},
component_name,
lhs.type());
}
new_assigns.insert(to_insert);
}
}
}
else if(lhs.id() == ID_dereference)
{
// All dereference `*v` and their alias `*u` are assigns.
const pointer_arithmetict ptr(to_dereference_expr(lhs).pointer());
for(const auto &mod : local_may_alias.get(t, ptr.pointer))
{
const typecast_exprt typed_mod{mod, ptr.pointer.type()};
if(mod.id() == ID_unknown)
{
continue;
}
const exprt typed_mod =
typecast_exprt::conditional_cast(mod, ptr.pointer.type());
exprt to_insert;
if(ptr.offset.is_nil())
to_insert = dereference_exprt{typed_mod};
else
to_insert = dereference_exprt{plus_exprt{typed_mod, ptr.offset}};
if(predicate(to_insert))
assigns.insert(std::move(to_insert));
new_assigns.insert(std::move(to_insert));
}
}
else if(lhs.id() == ID_if)
{
const if_exprt &if_expr = to_if_expr(lhs);

get_assigns_lhs(local_may_alias, t, if_expr.true_case(), assigns);
get_assigns_lhs(local_may_alias, t, if_expr.false_case(), assigns);
get_assigns_lhs(
local_may_alias, t, if_expr.true_case(), assigns, predicate);
get_assigns_lhs(
local_may_alias, t, if_expr.false_case(), assigns, predicate);
}

std::copy_if(
new_assigns.begin(),
new_assigns.end(),
std::inserter(assigns, assigns.begin()),
predicate);
}

void get_assigns(
Expand Down
Loading