Skip to content

Commit 7e7864b

Browse files
authored
Merge pull request #7603 from qinheping/bugfix/assignable-check-not-in-loop
CONTRACTS: use alias analysis to infer loop assigns in synthesizer
2 parents 2d4b3f7 + c5bebfa commit 7e7864b

File tree

4 files changed

+30
-9
lines changed

4 files changed

+30
-9
lines changed

regression/contracts/loop_assigns-fail/test.desc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
CORE
22
main.c
33
--apply-loop-contracts
4-
activate-multi-line-match
5-
Failed to infer variables being modified by the loop at file main.c line \d+ function main\.\nPlease specify an assigns clause\.\nReason:\nAlias analysis returned UNKNOWN!
6-
^EXIT=6$
4+
^EXIT=10$
75
^SIGNAL=0$
6+
^\[main.assigns.\d+\] .* Check that i is assignable: SUCCESS$
7+
^\[main.assigns.\d+\] .* Check that b->data\[(.*)i\] is assignable: FAILURE$
8+
^VERIFICATION FAILED$
89
--
910
--
1011
This test (taken from #6021) shows the need for assigns clauses on loops.

src/goto-instrument/loop_utils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void get_assigns_lhs(
5252
const typecast_exprt typed_mod{mod, ptr.pointer.type()};
5353
if(mod.id() == ID_unknown)
5454
{
55-
throw analysis_exceptiont("Alias analysis returned UNKNOWN!");
55+
continue;
5656
}
5757
if(ptr.offset.is_nil())
5858
assigns.insert(dereference_exprt{typed_mod});

src/goto-synthesizer/enumerative_loop_contracts_synthesizer.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ Author: Qinheping Hu
1919
#include <util/replace_symbol.h>
2020
#include <util/simplify_expr.h>
2121

22+
#include <analyses/local_may_alias.h>
2223
#include <analyses/natural_loops.h>
24+
#include <goto-instrument/contracts/cfg_info.h>
25+
#include <goto-instrument/contracts/utils.h>
2326
#include <goto-instrument/havoc_utils.h>
27+
#include <goto-instrument/loop_utils.h>
2428

2529
#include "cegis_verifier.h"
2630
#include "expr_enumerator.h"
@@ -82,9 +86,12 @@ void enumerative_loop_contracts_synthesizert::init_candidates()
8286
{
8387
for(auto &function_p : goto_model.goto_functions.function_map)
8488
{
85-
natural_loopst natural_loops;
89+
natural_loops_mutablet natural_loops;
8690
natural_loops(function_p.second.body);
8791

92+
// TODO: use global may alias instead.
93+
local_may_aliast local_may_alias(function_p.second);
94+
8895
// Initialize invariants for unannotated loops as true
8996
for(const auto &loop_head_and_content : natural_loops.loop_map)
9097
{
@@ -93,10 +100,11 @@ void enumerative_loop_contracts_synthesizert::init_candidates()
93100
continue;
94101

95102
goto_programt::const_targett loop_end =
96-
get_loop_end_from_loop_head_and_content(
103+
get_loop_end_from_loop_head_and_content_mutable(
97104
loop_head_and_content.first, loop_head_and_content.second);
98105

99106
loop_idt new_id(function_p.first, loop_end->loop_number);
107+
loop_cfg_infot cfg_info(function_p.second, loop_head_and_content.second);
100108

101109
log.debug() << "Initialize candidates for the loop at "
102110
<< loop_end->source_location() << messaget::eom;
@@ -120,6 +128,17 @@ void enumerative_loop_contracts_synthesizert::init_candidates()
120128
if(loop_end->condition().find(ID_C_spec_assigns).is_nil())
121129
{
122130
assigns_map[new_id] = {};
131+
132+
// Infer loop assigns using alias analysis.
133+
get_assigns(
134+
local_may_alias, loop_head_and_content.second, assigns_map[new_id]);
135+
136+
// remove loop-local symbols from the inferred set
137+
cfg_info.erase_locals(assigns_map[new_id]);
138+
139+
// If the set contains pairs (i, a[i]),
140+
// we widen them to (i, __CPROVER_POINTER_OBJECT(a))
141+
widen_assigns(assigns_map[new_id], ns);
123142
}
124143
}
125144
}
@@ -131,7 +150,6 @@ void enumerative_loop_contracts_synthesizert::synthesize_assigns(
131150
const exprt &checked_pointer,
132151
const std::list<loop_idt> cause_loop_ids)
133152
{
134-
namespacet ns(goto_model.symbol_table);
135153
auto new_assign = checked_pointer;
136154

137155
// Add the new assigns target to the most-inner loop that doesn't contain
@@ -246,7 +264,6 @@ exprt enumerative_loop_contracts_synthesizert::synthesize_strengthening_clause(
246264
// | StartBool <= StartBool | StartBool < StartBool
247265
// Start -> Start + Start | terminal_symbols
248266
// where a0, and a1 are symbol expressions.
249-
namespacet ns(goto_model.symbol_table);
250267
enumerator_factoryt factory = enumerator_factoryt(ns);
251268
recursive_enumerator_placeholdert start_bool_ph(factory, "StartBool", ns);
252269
recursive_enumerator_placeholdert start_ph(factory, "Start", ns);

src/goto-synthesizer/enumerative_loop_contracts_synthesizer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class enumerative_loop_contracts_synthesizert
3131
enumerative_loop_contracts_synthesizert(
3232
goto_modelt &goto_model,
3333
messaget &log)
34-
: loop_contracts_synthesizer_baset(goto_model, log)
34+
: loop_contracts_synthesizer_baset(goto_model, log),
35+
ns(goto_model.symbol_table)
3536
{
3637
}
3738

@@ -45,6 +46,8 @@ class enumerative_loop_contracts_synthesizert
4546
return assigns_map;
4647
}
4748

49+
namespacet ns;
50+
4851
private:
4952
/// Initialize invariants as true for all unannotated loops.
5053
void init_candidates();

0 commit comments

Comments
 (0)