Skip to content

Commit f5f0672

Browse files
authored
Merge pull request #8490 from qinheping/DFCC_loop_assigns_infer
[CONTRACTS] DFCC loop assigns infererence with functions inlined
2 parents 018c61c + 2317524 commit f5f0672

File tree

11 files changed

+285
-28
lines changed

11 files changed

+285
-28
lines changed

regression/contracts-dfcc/invar_havoc_dynamic_array_const_idx/main.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ void main()
1010
data[4] = 0;
1111

1212
for(unsigned i = 0; i < SIZE; i++)
13-
__CPROVER_loop_invariant(i <= SIZE)
13+
__CPROVER_assigns(data[1], i) __CPROVER_loop_invariant(i <= SIZE)
1414
{
1515
data[1] = i;
1616
}
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
KNOWNBUG
1+
CORE dfcc-only
22
main.c
3-
--dfcc main --apply-loop-contracts
3+
--dfcc main --apply-loop-contracts _ --no-standard-checks
44
^EXIT=0$
55
^SIGNAL=0$
66
^\[body_1.assigns.\d+\] .* Check that j is assignable: SUCCESS$
77
^\[body_2.assigns.\d+\] .* Check that \*i is assignable: SUCCESS$
88
^\[body_3.assigns.\d+\] .* Check that \*i is assignable: SUCCESS$
99
^\[incr.assigns.\d+\] .* Check that \*i is assignable: SUCCESS$
10-
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
11-
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
10+
^\[main.loop_invariant_base.\d+\] line \d+ Check invariant before entry for loop .*: SUCCESS$
11+
^\[main.loop_invariant_step.\d+\] line \d+ Check invariant after step for loop .*: SUCCESS$
12+
^\[main.loop_step_unwinding.\d+\] line \d+ Check step was unwound for loop .*: SUCCESS$
1213
^\[main.assertion.\d+\] .* assertion j == 9: SUCCESS$
1314
^VERIFICATION SUCCESSFUL$
1415
--
1516
--
1617
This test checks loop locals are correctly removed during assigns inference so
1718
that the assign clause is correctly inferred.
18-
This test failed when using dfcc for loop contracts.
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+
}
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.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <stdlib.h>
2+
3+
#define SIZE 8
4+
5+
int main()
6+
{
7+
int i = 0;
8+
int *j = malloc(SIZE * sizeof(int));
9+
for(i = 0; i < SIZE; i++)
10+
// __CPROVER_assigns(h.pos, i)
11+
__CPROVER_loop_invariant(0 <= i && i <= SIZE)
12+
{
13+
int *k;
14+
k = j + i;
15+
*k = 1;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE dfcc-only
2+
main.c
3+
--no-malloc-may-fail --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+
^\[main.assigns.\d+\] line \d+ Check that \*k is assignable: SUCCESS
11+
^VERIFICATION SUCCESSFUL$
12+
--
13+
--
14+
This test checks assigns __CPROVER_object_whole(k) is inferred correctly,
15+
which requires widening *k to the whole object.

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

+26-11
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,7 @@ static struct contract_clausest default_loop_contract_clauses(
309309
const dfcc_loop_nesting_grapht &loop_nesting_graph,
310310
const std::size_t loop_id,
311311
const irep_idt &function_id,
312-
goto_functiont &goto_function,
313-
local_may_aliast &local_may_alias,
312+
const assignst &inferred_assigns,
314313
const bool check_side_effect,
315314
message_handlert &message_handler,
316315
const namespacet &ns)
@@ -361,13 +360,11 @@ static struct contract_clausest default_loop_contract_clauses(
361360
else
362361
{
363362
// infer assigns clause targets if none given
364-
auto inferred = dfcc_infer_loop_assigns(
365-
local_may_alias, goto_function, loop, message_handler, ns);
366363
log.warning() << "No assigns clause provided for loop " << function_id
367364
<< "." << loop.latch->loop_number << " at "
368365
<< loop.head->source_location() << ". The inferred set {";
369366
bool first = true;
370-
for(const auto &expr : inferred)
367+
for(const auto &expr : inferred_assigns)
371368
{
372369
if(!first)
373370
{
@@ -379,7 +376,7 @@ static struct contract_clausest default_loop_contract_clauses(
379376
log.warning() << "} might be incomplete or imprecise, please provide an "
380377
"assigns clause if the analysis fails."
381378
<< messaget::eom;
382-
result.assigns.swap(inferred);
379+
result.assigns = inferred_assigns;
383380
}
384381

385382
if(result.decreases_clauses.empty())
@@ -400,7 +397,7 @@ static dfcc_loop_infot gen_dfcc_loop_info(
400397
goto_functiont &goto_function,
401398
const std::map<std::size_t, dfcc_loop_infot> &loop_info_map,
402399
dirtyt &dirty,
403-
local_may_aliast &local_may_alias,
400+
const assignst &inferred_assigns,
404401
const bool check_side_effect,
405402
message_handlert &message_handler,
406403
dfcc_libraryt &library,
@@ -436,8 +433,7 @@ static dfcc_loop_infot gen_dfcc_loop_info(
436433
loop_nesting_graph,
437434
loop_id,
438435
function_id,
439-
goto_function,
440-
local_may_alias,
436+
inferred_assigns,
441437
check_side_effect,
442438
message_handler,
443439
ns);
@@ -488,6 +484,7 @@ static dfcc_loop_infot gen_dfcc_loop_info(
488484
}
489485

490486
dfcc_cfg_infot::dfcc_cfg_infot(
487+
goto_modelt &goto_model,
491488
const irep_idt &function_id,
492489
goto_functiont &goto_function,
493490
const exprt &top_level_write_set,
@@ -506,6 +503,9 @@ dfcc_cfg_infot::dfcc_cfg_infot(
506503
// Clean up possible fake loops that are due to do { ... } while(0);
507504
simplify_gotos(goto_program, ns);
508505

506+
// From loop number to the inferred loop assigns.
507+
std::map<std::size_t, assignst> inferred_loop_assigns_map;
508+
509509
if(loop_contract_config.apply_loop_contracts)
510510
{
511511
messaget log(message_handler);
@@ -526,9 +526,23 @@ dfcc_cfg_infot::dfcc_cfg_infot(
526526

527527
auto topsorted = loop_nesting_graph.topsort();
528528

529+
bool has_loops_with_contracts = false;
529530
for(const auto idx : topsorted)
530531
{
531532
topsorted_loops.push_back(idx);
533+
has_loops_with_contracts |= has_contract(
534+
loop_nesting_graph[idx].latch, loop_contract_config.check_side_effect);
535+
}
536+
537+
// We infer loop assigns for all loops in the function.
538+
if(has_loops_with_contracts)
539+
{
540+
dfcc_infer_loop_assigns_for_function(
541+
inferred_loop_assigns_map,
542+
goto_model.goto_functions,
543+
goto_function,
544+
message_handler,
545+
ns);
532546
}
533547
}
534548

@@ -548,10 +562,11 @@ dfcc_cfg_infot::dfcc_cfg_infot(
548562

549563
// generate dfcc_cfg_loop_info for loops and add to loop_info_map
550564
dirtyt dirty(goto_function);
551-
local_may_aliast local_may_alias(goto_function);
552565

553566
for(const auto &loop_id : topsorted_loops)
554567
{
568+
auto inferred_loop_assigns =
569+
inferred_loop_assigns_map[loop_nesting_graph[loop_id].latch->loop_number];
555570
loop_info_map.insert(
556571
{loop_id,
557572
gen_dfcc_loop_info(
@@ -561,7 +576,7 @@ dfcc_cfg_infot::dfcc_cfg_infot(
561576
goto_function,
562577
loop_info_map,
563578
dirty,
564-
local_may_alias,
579+
inferred_loop_assigns,
565580
loop_contract_config.check_side_effect,
566581
message_handler,
567582
library,

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

+2
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)