Skip to content

Commit 45d7ad7

Browse files
committed
Infer loop assigns for DFCC with functions inlined
1 parent f2a7665 commit 45d7ad7

File tree

10 files changed

+343
-21
lines changed

10 files changed

+343
-21
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
struct hole
2+
{
3+
int pos;
4+
};
5+
6+
void set_len(struct hole *h, unsigned long int new_len)
7+
{
8+
h->pos = new_len;
9+
}
10+
11+
int main()
12+
{
13+
int i = 0;
14+
struct hole h;
15+
h.pos = 0;
16+
for(i = 0; i < 5; i++)
17+
// __CPROVER_assigns(h.pos, i)
18+
__CPROVER_loop_invariant(h.pos == i)
19+
{
20+
set_len(&h, h.pos + 1);
21+
}
22+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE dfcc-only
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.loop_invariant_base.\d+\] line \d+ Check invariant before entry for loop .*: SUCCESS$
7+
^\[main.loop_invariant_base.\d+\] line \d+ Check invariant before entry for loop .*: SUCCESS$
8+
^\[main.loop_invariant_step.\d+\] line \d+ Check invariant after step for loop .*: SUCCESS$
9+
^\[main.loop_step_unwinding.\d+\] line \d+ Check step was unwound for loop .*: SUCCESS$
10+
^\[set_len.assigns.\d+\] line \d+ Check that h\-\>pos is assignable: SUCCESS
11+
^VERIFICATION SUCCESSFUL$
12+
--
13+
--
14+
This test checks assigns h->pos is inferred correctly.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
struct hole
2+
{
3+
int pos;
4+
};
5+
6+
void set_len(struct hole *h, unsigned long int new_len)
7+
{
8+
h->pos = new_len;
9+
}
10+
11+
int main()
12+
{
13+
int i = 0;
14+
struct hole h;
15+
h.pos = 0;
16+
for(i = 0; i < 5; i++)
17+
// __CPROVER_assigns(h.pos, i)
18+
__CPROVER_loop_invariant(h.pos == i)
19+
{
20+
set_len(&h, h.pos + 1);
21+
}
22+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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+
^VERIFICATION SUCCESSFUL$
8+
--
9+
--
10+
This test checks assigns h->pos is inferred correctly.

src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ static struct contract_clausest default_loop_contract_clauses(
329329
const dfcc_loop_nesting_grapht &loop_nesting_graph,
330330
const std::size_t loop_id,
331331
const irep_idt &function_id,
332-
local_may_aliast &local_may_alias,
332+
const assignst &inferred_assigns,
333333
const bool check_side_effect,
334334
message_handlert &message_handler,
335335
const namespacet &ns)
@@ -380,13 +380,11 @@ static struct contract_clausest default_loop_contract_clauses(
380380
else
381381
{
382382
// infer assigns clause targets if none given
383-
auto inferred = dfcc_infer_loop_assigns(
384-
local_may_alias, loop.instructions, loop.head->source_location(), ns);
385383
log.warning() << "No assigns clause provided for loop " << function_id
386384
<< "." << loop.latch->loop_number << " at "
387385
<< loop.head->source_location() << ". The inferred set {";
388386
bool first = true;
389-
for(const auto &expr : inferred)
387+
for(const auto &expr : inferred_assigns)
390388
{
391389
if(!first)
392390
{
@@ -398,7 +396,7 @@ static struct contract_clausest default_loop_contract_clauses(
398396
log.warning() << "} might be incomplete or imprecise, please provide an "
399397
"assigns clause if the analysis fails."
400398
<< messaget::eom;
401-
result.assigns.swap(inferred);
399+
result.assigns = inferred_assigns;
402400
}
403401

404402
if(result.decreases_clauses.empty())
@@ -416,14 +414,16 @@ static dfcc_loop_infot gen_dfcc_loop_info(
416414
const dfcc_loop_nesting_grapht &loop_nesting_graph,
417415
const std::size_t loop_id,
418416
const irep_idt &function_id,
417+
goto_functiont &goto_function,
419418
const std::map<std::size_t, dfcc_loop_infot> &loop_info_map,
420419
dirtyt &dirty,
421-
local_may_aliast &local_may_alias,
420+
const assignst &inferred_assigns,
422421
const bool check_side_effect,
423422
message_handlert &message_handler,
424423
dfcc_libraryt &library,
425424
symbol_table_baset &symbol_table)
426425
{
426+
const namespacet ns(symbol_table);
427427
std::unordered_set<irep_idt> loop_locals =
428428
gen_loop_locals_set(loop_nesting_graph, loop_id);
429429

@@ -433,12 +433,11 @@ static dfcc_loop_infot gen_dfcc_loop_info(
433433
dirty,
434434
loop_info_map);
435435

436-
const namespacet ns(symbol_table);
437436
struct contract_clausest contract_clauses = default_loop_contract_clauses(
438437
loop_nesting_graph,
439438
loop_id,
440439
function_id,
441-
local_may_alias,
440+
inferred_assigns,
442441
check_side_effect,
443442
message_handler,
444443
ns);
@@ -489,6 +488,7 @@ static dfcc_loop_infot gen_dfcc_loop_info(
489488
}
490489

491490
dfcc_cfg_infot::dfcc_cfg_infot(
491+
goto_modelt &goto_model,
492492
const irep_idt &function_id,
493493
goto_functiont &goto_function,
494494
const exprt &top_level_write_set,
@@ -507,6 +507,9 @@ dfcc_cfg_infot::dfcc_cfg_infot(
507507
// Clean up possible fake loops that are due to do { ... } while(0);
508508
simplify_gotos(goto_program, ns);
509509

510+
// From loop number to the inferred loop assigns.
511+
std::map<std::size_t, assignst> inferred_loop_assigns_map;
512+
510513
if(loop_contract_config.apply_loop_contracts)
511514
{
512515
messaget log(message_handler);
@@ -527,9 +530,23 @@ dfcc_cfg_infot::dfcc_cfg_infot(
527530

528531
auto topsorted = loop_nesting_graph.topsort();
529532

533+
bool has_loops_with_contracts = false;
530534
for(const auto idx : topsorted)
531535
{
532536
topsorted_loops.push_back(idx);
537+
has_loops_with_contracts |= has_contract(
538+
loop_nesting_graph[idx].latch, loop_contract_config.check_side_effect);
539+
}
540+
541+
// We infer loop assigns for all loops in the function.
542+
if(has_loops_with_contracts)
543+
{
544+
dfcc_infer_loop_assigns_for_function(
545+
inferred_loop_assigns_map,
546+
goto_model.goto_functions,
547+
goto_function,
548+
message_handler,
549+
ns);
533550
}
534551
}
535552

@@ -549,19 +566,21 @@ dfcc_cfg_infot::dfcc_cfg_infot(
549566

550567
// generate dfcc_cfg_loop_info for loops and add to loop_info_map
551568
dirtyt dirty(goto_function);
552-
local_may_aliast local_may_alias(goto_function);
553569

554570
for(const auto &loop_id : topsorted_loops)
555571
{
572+
auto inferred_loop_assigns =
573+
inferred_loop_assigns_map[loop_nesting_graph[loop_id].latch->loop_number];
556574
loop_info_map.insert(
557575
{loop_id,
558576
gen_dfcc_loop_info(
559577
loop_nesting_graph,
560578
loop_id,
561579
function_id,
580+
goto_function,
562581
loop_info_map,
563582
dirty,
564-
local_may_alias,
583+
inferred_loop_assigns,
565584
loop_contract_config.check_side_effect,
566585
message_handler,
567586
library,

src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Date: March 2023
2121
#include <util/std_expr.h>
2222
#include <util/symbol_table.h>
2323

24+
#include <goto-programs/goto_model.h>
2425
#include <goto-programs/goto_program.h>
2526

2627
#include <goto-instrument/contracts/loop_contract_config.h>
@@ -242,6 +243,7 @@ class dfcc_cfg_infot
242243
{
243244
public:
244245
dfcc_cfg_infot(
246+
goto_modelt &goto_model,
245247
const irep_idt &function_id,
246248
goto_functiont &goto_function,
247249
const exprt &top_level_write_set,

0 commit comments

Comments
 (0)