Skip to content

Commit bb65b67

Browse files
authored
Merge pull request #6034 from padhi-aws-forks/invariant_struct_fix
Fix havocing of struct members when enforcing invariants
2 parents a870eea + fb14521 commit bb65b67

File tree

5 files changed

+85
-4
lines changed

5 files changed

+85
-4
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
typedef struct test
2+
{
3+
int x;
4+
} test;
5+
6+
void main()
7+
{
8+
struct test *t = malloc(sizeof(test));
9+
t->x = 0;
10+
11+
unsigned n;
12+
for(unsigned i = 0; i < n; ++i)
13+
__CPROVER_loop_invariant(i <= n)
14+
{
15+
switch(i % 4)
16+
{
17+
case 0:
18+
break;
19+
20+
case 1:
21+
case 2:
22+
t->x += 1;
23+
24+
default:
25+
t->x += 2;
26+
}
27+
}
28+
29+
assert(t->x == 0 || t->x == 1 || t->x == 2);
30+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main.1\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.2\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assertion.1\] .* assertion .*: FAILURE$
9+
^VERIFICATION FAILED$
10+
--
11+
--
12+
This test checks that members of typedef'd and dynamically allocated structs
13+
are correctly havoced when enforcing loop invariants.
14+
The assertion is expected to fail when `t->x` is correctly havoced (so would be
15+
set to a nondet value).
16+
However, it `t->x` is not havoced then it stays at value `0` and would satisfy
17+
the assertion when the loop is replaced by a single nondet iteration.
18+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
struct test
2+
{
3+
int x;
4+
};
5+
6+
void main()
7+
{
8+
struct test t;
9+
t.x = 0;
10+
11+
unsigned n;
12+
for(unsigned i = 0; i < n; ++i)
13+
__CPROVER_loop_invariant(i <= n)
14+
{
15+
t.x += 2;
16+
}
17+
18+
assert(t.x == 0 || t.x == 2);
19+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main.1\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.2\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assertion.1\] .* assertion t.x == 0 || t.x == 2: FAILURE$
9+
^VERIFICATION FAILED$
10+
--
11+
--
12+
This test checks that members of statically allocated are correctly havoced
13+
when enforcing loop invariants.
14+
The `t.x == 0 || t.x == 2` assertion is expected to fail when `t.x` is correctly
15+
havoced (so would be set to a nondet value).
16+
However, it `t.x` is not havoced then it stays at value `0` and would satisfy
17+
the assertion when the loop is replaced by a single nondet iteration.

src/goto-instrument/loop_utils.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,14 @@ void get_modifies_lhs(
6161
const exprt &lhs,
6262
modifiest &modifies)
6363
{
64-
if(lhs.id()==ID_symbol)
64+
if(lhs.id() == ID_symbol || lhs.id() == ID_member)
6565
modifies.insert(lhs);
6666
else if(lhs.id()==ID_dereference)
6767
{
6868
const auto &pointer = to_dereference_expr(lhs).pointer();
6969
for(const auto &mod : local_may_alias.get(t, pointer))
7070
modifies.insert(dereference_exprt{mod});
7171
}
72-
else if(lhs.id()==ID_member)
73-
{
74-
}
7572
else if(lhs.id()==ID_index)
7673
{
7774
}

0 commit comments

Comments
 (0)