Skip to content

Commit 606fb8d

Browse files
committed
Adds support for struct members in history variables
Signed-off-by: Felipe R. Monteiro <[email protected]>
1 parent 25ed175 commit 606fb8d

File tree

6 files changed

+84
-11
lines changed

6 files changed

+84
-11
lines changed

doc/cprover-manual/contracts-history-variables.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ _ensures_ clause.
1313
1414
### Parameters
1515
16-
`__CPROVER_old` takes a single argument, which is the identifier corresponding to
17-
a parameter of the function. For now, only scalar or pointer types are supported.
16+
`__CPROVER_old` takes a single argument, which is the identifier
17+
corresponding to a parameter of the function. For now, only scalars,
18+
pointers, and struct members are supported.
1819
1920
### Semantics
2021
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <stdlib.h>
2+
3+
struct pair
4+
{
5+
int x;
6+
int y;
7+
};
8+
9+
void foo(struct pair *p) __CPROVER_assigns(p->y)
10+
__CPROVER_ensures(p->y == __CPROVER_old(p->y) + 5)
11+
{
12+
p->y = p->y + 5;
13+
}
14+
15+
int main()
16+
{
17+
struct pair *p = malloc(sizeof(*p));
18+
p->x = 2;
19+
p->y = 2;
20+
foo(p);
21+
22+
return 0;
23+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: SUCCESS$
7+
^\[foo.\d+\] line \d+ Check that p\-\>y is assignable\: SUCCESS$
8+
^VERIFICATION SUCCESSFUL$
9+
--
10+
--
11+
This test checks that history variables are supported for struct members.
12+
By using the --enforce-all-contracts flag, the post-condition (which contains
13+
the history variable) is asserted. In this case, this assertion should pass.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <stdlib.h>
2+
3+
struct pair
4+
{
5+
int x;
6+
int y;
7+
};
8+
9+
void foo(struct pair *p) __CPROVER_requires(p != NULL) __CPROVER_assigns(p->y)
10+
__CPROVER_ensures(p->y == __CPROVER_old(p->y) + 5)
11+
{
12+
p->y = p->y + 5;
13+
}
14+
15+
int main()
16+
{
17+
struct pair *p = malloc(sizeof(*p));
18+
p->x = 2;
19+
p->y = 2;
20+
foo(p);
21+
assert(p->y != 7);
22+
23+
return 0;
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
main.c
3+
--replace-all-calls-with-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[precondition.\d+\] file main.c line \d+ Check requires clause\: SUCCESS$
7+
^\[main.assertion.\d+\] line \d+ assertion p\-\>y \!\= 7\: FAILURE$
8+
^VERIFICATION FAILED$
9+
--
10+
--
11+
This test checks that history variables are supported for struct members.
12+
By using the --replace-all-calls-with-contracts flag, the assertion in
13+
main should consider the ensures clause (with old value). In this case,
14+
this assertion should fail.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -395,22 +395,20 @@ void code_contractst::replace_old_parameter(
395395
const auto &parameter = to_old_expr(expr).expression();
396396

397397
// TODO: generalize below
398-
if(parameter.id() == ID_dereference)
398+
if(parameter.id() == ID_dereference || parameter.id() == ID_member)
399399
{
400-
const auto &dereference_expr = to_dereference_expr(parameter);
401-
402-
auto it = parameter2history.find(dereference_expr);
400+
auto it = parameter2history.find(parameter);
403401

404402
if(it == parameter2history.end())
405403
{
406404
// 1. Create a temporary symbol expression that represents the
407405
// history variable
408406
symbol_exprt tmp_symbol =
409-
new_tmp_symbol(dereference_expr.type(), location, mode).symbol_expr();
407+
new_tmp_symbol(parameter.type(), location, mode).symbol_expr();
410408

411409
// 2. Associate the above temporary variable to it's corresponding
412410
// expression
413-
parameter2history[dereference_expr] = tmp_symbol;
411+
parameter2history[parameter] = tmp_symbol;
414412

415413
// 3. Add the required instructions to the instructions list
416414
// 3.1 Declare the newly created temporary variable
@@ -419,11 +417,11 @@ void code_contractst::replace_old_parameter(
419417
// 3.2 Add an assignment such that the value pointed to by the new
420418
// temporary variable is equal to the value of the corresponding
421419
// parameter
422-
history.add(goto_programt::make_assignment(
423-
tmp_symbol, dereference_expr, location));
420+
history.add(
421+
goto_programt::make_assignment(tmp_symbol, parameter, location));
424422
}
425423

426-
expr = parameter2history[dereference_expr];
424+
expr = parameter2history[parameter];
427425
}
428426
else
429427
{

0 commit comments

Comments
 (0)