@@ -252,13 +252,30 @@ void code_contractst::check_apply_loop_contracts(
252
252
loop_head,
253
253
add_pragma_disable_assigns_check (generated_code));
254
254
255
- // havoc the variables that may be modified
256
- assignst assigns;
255
+ assignst to_havoc;
256
+
257
257
if (assigns_clause.is_nil ())
258
258
{
259
+ // No assigns clause was specified for this loop.
260
+ // Infer memory locations assigned by the loop from the loop instructions
261
+ // and the inferred alisaing relation.
259
262
try
260
263
{
261
- get_assigns (local_may_alias, loop, assigns);
264
+ get_assigns (local_may_alias, loop, to_havoc);
265
+ log.warning () << " No loop assigns clause provided. Inferred targets {" ;
266
+ // Add inferred targets to the loop assigns clause.
267
+ bool ran_once = false ;
268
+ for (auto &target : to_havoc)
269
+ {
270
+ if (ran_once)
271
+ log.warning () << " , " ;
272
+ ran_once = true ;
273
+ log.warning () << from_expr (ns, target.id (), target);
274
+ loop_assigns.add_to_write_set (target);
275
+ }
276
+ log.warning ()
277
+ << " }. Please specify an assigns clause if verification fails."
278
+ << messaget::eom;
262
279
}
263
280
catch (const analysis_exceptiont &exc)
264
281
{
@@ -271,24 +288,29 @@ void code_contractst::check_apply_loop_contracts(
271
288
}
272
289
else
273
290
{
274
- assigns.insert (
291
+ // An assigns clause was specified for this loop.
292
+ // Add the targets to the set of expressions to havoc.
293
+ // TODO: Should we add the automatically detected local static variables
294
+ // too ? (they are present in loop_assigns but not in assigns_clause, and
295
+ // they are not necessarily touched by the loop).
296
+ to_havoc.insert (
275
297
assigns_clause.operands ().cbegin (), assigns_clause.operands ().cend ());
298
+ }
276
299
277
- // Create snapshots of write set CARs.
278
- // This must be done before havocing the write set.
279
- for (const auto &car : loop_assigns.get_write_set ())
280
- {
281
- auto snapshot_instructions = car.generate_snapshot_instructions ();
282
- insert_before_swap_and_advance (
283
- goto_function.body , loop_head, snapshot_instructions);
284
- };
300
+ // Create snapshots of write set CARs.
301
+ // This must be done before havocing the write set.
302
+ for (const auto &car : loop_assigns.get_write_set ())
303
+ {
304
+ auto snapshot_instructions = car.generate_snapshot_instructions ();
305
+ insert_before_swap_and_advance (
306
+ goto_function.body , loop_head, snapshot_instructions);
307
+ };
285
308
286
- // Perform write set instrumentation on the entire loop.
287
- check_frame_conditions (
288
- function_name, goto_function.body , loop_head, loop_end, loop_assigns);
289
- }
309
+ // Perform write set instrumentation on the entire loop.
310
+ check_frame_conditions (
311
+ function_name, goto_function.body , loop_head, loop_end, loop_assigns);
290
312
291
- havoc_assigns_targetst havoc_gen (assigns , ns);
313
+ havoc_assigns_targetst havoc_gen (to_havoc , ns);
292
314
havoc_gen.append_full_havoc_code (
293
315
loop_head->source_location (), generated_code);
294
316
0 commit comments