Skip to content

Commit 625df39

Browse files
authored
Merge pull request #7228 from qinheping/assigns_inference
CONTRACTS: Add widening strategy into assigns inference
2 parents 60b95b2 + a899b80 commit 625df39

File tree

9 files changed

+95
-2
lines changed

9 files changed

+95
-2
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <stdlib.h>
2+
3+
#define SIZE 8
4+
5+
void main()
6+
{
7+
int *b = malloc(SIZE * sizeof(int));
8+
for(unsigned i = 0; i < SIZE; i++)
9+
// clang-format off
10+
__CPROVER_loop_invariant(i <= SIZE)
11+
// clang-format on
12+
{
13+
b[i] = 1;
14+
}
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that i is assignable: SUCCESS$
9+
^\[main.assigns.\d+\] .* Check that b\[(.*)i\] is assignable: SUCCESS$
10+
^VERIFICATION SUCCESSFUL$
11+
--
12+
--
13+
This test checks assigns clauses (i, __CPROVER_POINTER_OBJECT(b)) is inferred,
14+
and widened correctly.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <stdlib.h>
2+
3+
#define SIZE 8
4+
5+
void main()
6+
{
7+
int b[SIZE];
8+
for(unsigned i = 0; i < SIZE; i++)
9+
// clang-format off
10+
__CPROVER_loop_invariant(i <= SIZE)
11+
// clang-format on
12+
{
13+
b[i] = 1;
14+
}
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that i is assignable: SUCCESS$
9+
^\[main.assigns.\d+\] .* Check that b\[(.*)i\] is assignable: SUCCESS$
10+
^VERIFICATION SUCCESSFUL$
11+
--
12+
--
13+
This test checks assigns clauses (i, __CPROVER_POINTER_OBJECT(b)) is inferred,
14+
and widened correctly.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,14 @@ void code_contractst::check_apply_loop_contracts(
208208
try
209209
{
210210
get_assigns(local_may_alias, loop, to_havoc);
211-
// TODO: if the set contains pairs (i, a[i]),
212-
// we must at least widen them to (i, pointer_object(a))
213211

214212
// remove loop-local symbols from the inferred set
215213
cfg_info.erase_locals(to_havoc);
216214

215+
// If the set contains pairs (i, a[i]),
216+
// we widen them to (i, __CPROVER_POINTER_OBJECT(a))
217+
widen_assigns(to_havoc);
218+
217219
log.debug() << "No loop assigns clause provided. Inferred targets: {";
218220
// Add inferred targets to the loop assigns clause.
219221
bool ran_once = false;

src/goto-instrument/contracts/utils.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,29 @@ bool is_assigns_clause_replacement_tracking_comment(const irep_idt &comment)
242242
return id2string(comment).find(ASSIGNS_CLAUSE_REPLACEMENT_TRACKING) !=
243243
std::string::npos;
244244
}
245+
246+
void widen_assigns(assignst &assigns)
247+
{
248+
assignst result;
249+
250+
havoc_utils_is_constantt is_constant(assigns);
251+
252+
for(const auto &e : assigns)
253+
{
254+
if(e.id() == ID_index || e.id() == ID_dereference)
255+
{
256+
address_of_exprt address_of_expr(e);
257+
258+
// index or offset is non-constant.
259+
if(!is_constant(address_of_expr))
260+
{
261+
result.emplace(pointer_object(address_of_expr));
262+
}
263+
else
264+
result.emplace(e);
265+
}
266+
else
267+
result.emplace(e);
268+
}
269+
assigns = result;
270+
}

src/goto-instrument/contracts/utils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,11 @@ irep_idt make_assigns_clause_replacement_tracking_comment(
180180
/// \ref make_assigns_clause_replacement_tracking_comment.
181181
bool is_assigns_clause_replacement_tracking_comment(const irep_idt &comment);
182182

183+
/// Widen expressions in \p assigns with the following strategy.
184+
/// If an expression is an array index or object dereference expression,
185+
/// with a non-constant offset, e.g. a[i] or *(b+i) with a non-constant `i`,
186+
/// then replace it by the entire underlying object. Otherwise, e.g. for a[i] or
187+
/// *(b+i) when `i` is a known constant, keep the expression in the result.
188+
void widen_assigns(assignst &assigns);
189+
183190
#endif // CPROVER_GOTO_INSTRUMENT_CONTRACTS_UTILS_H

0 commit comments

Comments
 (0)