Skip to content

Commit 5359895

Browse files
author
Aalok Thakkar
committed
Added support for loop_entry history variable.
1. Created a new predicate __CPROVER_loop_entry which can be used in the loop invariant to keep track of the value of a variable at the start of the loop. 2. Modified the code contract to support this history variable.
1 parent bf70daa commit 5359895

File tree

16 files changed

+192
-21
lines changed

16 files changed

+192
-21
lines changed

regression/contracts/history-pointer-replace-03/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ main.c
44
^EXIT=(1|64)$
55
^SIGNAL=0$
66
^CONVERSION ERROR$
7-
error: __CPROVER_old expressions are not allowed in __CPROVER_requires clauses
7+
error: __CPROVER_old expressions are not allowed
88
--
99
--
1010
Verification:
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <assert.h>
2+
3+
typedef struct
4+
{
5+
int *n;
6+
} s;
7+
8+
void main()
9+
{
10+
int *x1, y1, z1;
11+
*x1 = &z1;
12+
13+
while(y1 > 0)
14+
__CPROVER_loop_invariant(*x1 == __CPROVER_loop_entry(*x1))
15+
{
16+
--y1;
17+
*x1 = *x1 + 1;
18+
*x1 = *x1 - 1;
19+
}
20+
assert(*x1 == &z1);
21+
22+
int x2, y2, z2;
23+
x2 = z2;
24+
25+
while(y2 > 0)
26+
__CPROVER_loop_invariant(x2 == __CPROVER_loop_entry(x2))
27+
{
28+
--y2;
29+
x2 = x2 + 1;
30+
x2 = x2 - 1;
31+
}
32+
assert(x2 == z2);
33+
34+
int y3;
35+
s *s1, *s2;
36+
s2->n = malloc(sizeof(int));
37+
s1->n = s2->n;
38+
39+
while(y3 > 0)
40+
__CPROVER_loop_invariant(*s1 == __CPROVER_loop_entry(*s1))
41+
{
42+
--y3;
43+
s1->n = s1->n + 1;
44+
s1->n = s1->n - 1;
45+
}
46+
47+
assert(s1->n == s2->n);
48+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^EXIT=0$
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 \*x1 == &z1: SUCCESS$
9+
^\[main.3\] .* Check loop invariant before entry: SUCCESS$
10+
^\[main.4\] .* Check that loop invariant is preserved: SUCCESS$
11+
^\[main.assertion.2\] .* assertion x2 == z2: SUCCESS$
12+
^\[main.5\] .* Check loop invariant before entry: SUCCESS$
13+
^\[main.6\] .* Check that loop invariant is preserved: SUCCESS$
14+
^\[main.assertion.3\] .* assertion s1->n == s2->n: SUCCESS$
15+
^VERIFICATION SUCCESSFUL$
16+
--
17+
--
18+
This test checks that __CPROVER_loop_entry is supported.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <assert.h>
2+
3+
void main()
4+
{
5+
int *x, y, z;
6+
7+
*x = &z;
8+
9+
while(y > 0)
10+
__CPROVER_loop_invariant(*x == __CPROVER_old(*x))
11+
{
12+
--y;
13+
*x = *x + 1;
14+
*x = *x - 1;
15+
}
16+
assert(*x == &z);
17+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^CONVERSION ERROR$
5+
^EXIT=1$
6+
^SIGNAL=0$
7+
--
8+
--
9+
This test ensures that __CPROVER_old cannot be used for loop contracts.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
void foo(int *x) __CPROVER_assigns(*x)
2+
__CPROVER_ensures(*x == __CPROVER_loop_entry(*x) + 5)
3+
{
4+
*x = *x + 5;
5+
}
6+
7+
int main()
8+
{
9+
int n;
10+
foo(&n);
11+
12+
return 0;
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^CONVERSION ERROR$
5+
^EXIT=1$
6+
^SIGNAL=0$
7+
--
8+
--
9+
This test ensures that __CPROVER_loop_entry cannot be
10+
used for function contracts.

src/ansi-c/c_expr.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,11 @@ inline side_effect_expr_overflowt &to_side_effect_expr_overflow(exprt &expr)
202202

203203
/// \brief A class for an expression that indicates the pre-function-call
204204
/// value of an expression passed as a parameter to a function
205-
class old_exprt : public unary_exprt
205+
class history_exprt : public unary_exprt
206206
{
207207
public:
208-
explicit old_exprt(exprt variable) : unary_exprt(ID_old, std::move(variable))
208+
explicit history_exprt(exprt variable, const irep_idt &id)
209+
: unary_exprt(id, std::move(variable))
209210
{
210211
}
211212

@@ -215,10 +216,12 @@ class old_exprt : public unary_exprt
215216
}
216217
};
217218

218-
inline const old_exprt &to_old_expr(const exprt &expr)
219+
inline const history_exprt &
220+
to_history_expr(const exprt &expr, const irep_idt &id)
219221
{
220-
PRECONDITION(expr.id() == ID_old);
221-
auto &ret = static_cast<const old_exprt &>(expr);
222+
PRECONDITION(id == ID_old || id == ID_loop_entry);
223+
PRECONDITION(expr.id() == id);
224+
auto &ret = static_cast<const history_exprt &>(expr);
222225
validate_expr(ret);
223226
return ret;
224227
}

src/ansi-c/c_typecheck_base.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@ void c_typecheck_baset::typecheck_declaration(
731731
typecheck_expr(requires);
732732
implicit_typecast_bool(requires);
733733
disallow_history_variables(requires);
734+
disallow_loop_history_variables(requires);
734735
}
735736
}
736737

@@ -751,6 +752,7 @@ void c_typecheck_baset::typecheck_declaration(
751752
{
752753
typecheck_expr(ensures);
753754
implicit_typecast_bool(ensures);
755+
disallow_loop_history_variables(ensures);
754756
}
755757

756758
if(return_type.id() != ID_empty)

src/ansi-c/c_typecheck_base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class c_typecheck_baset:
207207
virtual exprt
208208
typecheck_shuffle_vector(const side_effect_expr_function_callt &expr);
209209
void disallow_history_variables(const exprt &) const;
210+
void disallow_loop_history_variables(const exprt &) const;
210211

211212
virtual void make_index_type(exprt &expr);
212213
virtual void make_constant(exprt &expr);

0 commit comments

Comments
 (0)