File tree Expand file tree Collapse file tree 9 files changed +95
-2
lines changed
loop_assigns_inference-01
loop_assigns_inference-02
loop_assigns_inference-03
src/goto-instrument/contracts Expand file tree Collapse file tree 9 files changed +95
-2
lines changed File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
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
+ }
Original file line number Diff line number Diff line change
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.
Original file line number Diff line number Diff line change
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
+ }
Original file line number Diff line number Diff line change
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.
Original file line number Diff line number Diff line change @@ -208,12 +208,14 @@ void code_contractst::check_apply_loop_contracts(
208
208
try
209
209
{
210
210
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))
213
211
214
212
// remove loop-local symbols from the inferred set
215
213
cfg_info.erase_locals (to_havoc);
216
214
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
+
217
219
log.debug () << " No loop assigns clause provided. Inferred targets: {" ;
218
220
// Add inferred targets to the loop assigns clause.
219
221
bool ran_once = false ;
Original file line number Diff line number Diff line change @@ -242,3 +242,29 @@ bool is_assigns_clause_replacement_tracking_comment(const irep_idt &comment)
242
242
return id2string (comment).find (ASSIGNS_CLAUSE_REPLACEMENT_TRACKING) !=
243
243
std::string::npos;
244
244
}
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
+ }
Original file line number Diff line number Diff line change @@ -180,4 +180,11 @@ irep_idt make_assigns_clause_replacement_tracking_comment(
180
180
// / \ref make_assigns_clause_replacement_tracking_comment.
181
181
bool is_assigns_clause_replacement_tracking_comment (const irep_idt &comment);
182
182
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
+
183
190
#endif // CPROVER_GOTO_INSTRUMENT_CONTRACTS_UTILS_H
You can’t perform that action at this time.
0 commit comments