Skip to content

Commit 9620802

Browse files
authored
Merge pull request diffblue#1815 from smowton/smowton/feature/replace-clinit-unwinder
Reimplement remove-static-init-loops to avoid need to inspect GOTO program
2 parents 9b59631 + 06a220a commit 9620802

12 files changed

+232
-200
lines changed

src/cbmc/bmc.h

+11
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@ class bmct:public safety_checkert
7171
return run(goto_functions);
7272
}
7373

74+
void add_loop_unwind_handler(symex_bmct::loop_unwind_handlert handler)
75+
{
76+
symex.add_loop_unwind_handler(handler);
77+
}
78+
79+
void add_unwind_recursion_handler(
80+
symex_bmct::recursion_unwind_handlert handler)
81+
{
82+
symex.add_recursion_unwind_handler(handler);
83+
}
84+
7485
protected:
7586
const optionst &options;
7687
symbol_tablet new_symbol_table;

src/cbmc/cbmc_parse_options.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ Author: Daniel Kroening, [email protected]
4545
#include <goto-programs/remove_asm.h>
4646
#include <goto-programs/remove_unused_functions.h>
4747
#include <goto-programs/remove_skip.h>
48-
#include <goto-programs/remove_static_init_loops.h>
4948
#include <goto-programs/set_properties.h>
5049
#include <goto-programs/show_goto_functions.h>
5150
#include <goto-programs/show_symbol_table.h>

src/cbmc/symex_bmc.cpp

+67-28
Original file line numberDiff line numberDiff line change
@@ -110,27 +110,49 @@ bool symex_bmct::get_unwind(
110110
{
111111
const irep_idt id=goto_programt::loop_id(*source.pc);
112112

113-
// We use the most specific limit we have,
114-
// and 'infinity' when we have none.
115-
113+
tvt abort_unwind_decision;
116114
unsigned this_loop_limit=std::numeric_limits<unsigned>::max();
117115

118-
loop_limitst &this_thread_limits=
119-
thread_loop_limits[source.thread_nr];
116+
for(auto handler : loop_unwind_handlers)
117+
{
118+
abort_unwind_decision =
119+
handler(
120+
source.pc->function,
121+
source.pc->loop_number,
122+
unwind,
123+
this_loop_limit);
124+
if(abort_unwind_decision.is_known())
125+
break;
126+
}
120127

121-
loop_limitst::const_iterator l_it=this_thread_limits.find(id);
122-
if(l_it!=this_thread_limits.end())
123-
this_loop_limit=l_it->second;
124-
else
128+
// If no handler gave an opinion, use standard command-line --unwindset
129+
// / --unwind options to decide:
130+
if(abort_unwind_decision.is_unknown())
125131
{
126-
l_it=loop_limits.find(id);
127-
if(l_it!=loop_limits.end())
132+
// We use the most specific limit we have,
133+
// and 'infinity' when we have none.
134+
135+
loop_limitst &this_thread_limits=
136+
thread_loop_limits[source.thread_nr];
137+
138+
loop_limitst::const_iterator l_it=this_thread_limits.find(id);
139+
if(l_it!=this_thread_limits.end())
128140
this_loop_limit=l_it->second;
129-
else if(max_unwind_is_set)
130-
this_loop_limit=max_unwind;
141+
else
142+
{
143+
l_it=loop_limits.find(id);
144+
if(l_it!=loop_limits.end())
145+
this_loop_limit=l_it->second;
146+
else if(max_unwind_is_set)
147+
this_loop_limit=max_unwind;
148+
}
149+
150+
abort_unwind_decision = tvt(unwind >= this_loop_limit);
131151
}
132152

133-
bool abort=unwind>=this_loop_limit;
153+
INVARIANT(
154+
abort_unwind_decision.is_known(), "unwind decision should be taken by now");
155+
bool abort = abort_unwind_decision.is_true();
134156

135157
log.statistics() << (abort ? "Not unwinding" : "Unwinding") << " loop " << id
136158
<< " iteration " << unwind;
@@ -149,27 +171,44 @@ bool symex_bmct::get_unwind_recursion(
149171
const unsigned thread_nr,
150172
unsigned unwind)
151173
{
152-
// We use the most specific limit we have,
153-
// and 'infinity' when we have none.
154-
174+
tvt abort_unwind_decision;
155175
unsigned this_loop_limit=std::numeric_limits<unsigned>::max();
156176

157-
loop_limitst &this_thread_limits=
158-
thread_loop_limits[thread_nr];
177+
for(auto handler : recursion_unwind_handlers)
178+
{
179+
abort_unwind_decision = handler(id, unwind, this_loop_limit);
180+
if(abort_unwind_decision.is_known())
181+
break;
182+
}
159183

160-
loop_limitst::const_iterator l_it=this_thread_limits.find(id);
161-
if(l_it!=this_thread_limits.end())
162-
this_loop_limit=l_it->second;
163-
else
184+
// If no handler gave an opinion, use standard command-line --unwindset
185+
// / --unwind options to decide:
186+
if(abort_unwind_decision.is_unknown())
164187
{
165-
l_it=loop_limits.find(id);
166-
if(l_it!=loop_limits.end())
188+
// We use the most specific limit we have,
189+
// and 'infinity' when we have none.
190+
191+
loop_limitst &this_thread_limits=
192+
thread_loop_limits[thread_nr];
193+
194+
loop_limitst::const_iterator l_it=this_thread_limits.find(id);
195+
if(l_it!=this_thread_limits.end())
167196
this_loop_limit=l_it->second;
168-
else if(max_unwind_is_set)
169-
this_loop_limit=max_unwind;
197+
else
198+
{
199+
l_it=loop_limits.find(id);
200+
if(l_it!=loop_limits.end())
201+
this_loop_limit=l_it->second;
202+
else if(max_unwind_is_set)
203+
this_loop_limit=max_unwind;
204+
}
205+
206+
abort_unwind_decision = tvt(unwind>this_loop_limit);
170207
}
171208

172-
bool abort=unwind>this_loop_limit;
209+
INVARIANT(
210+
abort_unwind_decision.is_known(), "unwind decision should be taken by now");
211+
bool abort = abort_unwind_decision.is_true();
173212

174213
if(unwind>0 || abort)
175214
{

src/cbmc/symex_bmc.h

+46
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Daniel Kroening, [email protected]
1313
#define CPROVER_CBMC_SYMEX_BMC_H
1414

1515
#include <util/message.h>
16+
#include <util/threeval.h>
1617

1718
#include <goto-symex/goto_symex.h>
1819

@@ -53,6 +54,43 @@ class symex_bmct: public goto_symext
5354
loop_limits[id]=limit;
5455
}
5556

57+
/// Loop unwind handlers take the function ID and loop number, the unwind
58+
/// count so far, and an out-parameter specifying an advisory maximum, which
59+
/// they may set. If set the advisory maximum is set it is *only* used to
60+
/// print useful information for the user (e.g. "unwinding iteration N, max
61+
/// M"), and is not enforced. They return true to halt unwinding, false to
62+
/// authorise unwinding, or Unknown to indicate they have no opinion.
63+
typedef
64+
std::function<tvt(const irep_idt &, unsigned, unsigned, unsigned &)>
65+
loop_unwind_handlert;
66+
67+
/// Recursion unwind handlers take the function ID, the unwind count so far,
68+
/// and an out-parameter specifying an advisory maximum, which they may set.
69+
/// If set the advisory maximum is set it is *only* used to print useful
70+
/// information for the user (e.g. "unwinding iteration N, max M"),
71+
/// and is not enforced. They return true to halt unwinding, false to
72+
/// authorise unwinding, or Unknown to indicate they have no opinion.
73+
typedef std::function<tvt(const irep_idt &, unsigned, unsigned &)>
74+
recursion_unwind_handlert;
75+
76+
/// Add a callback function that will be called to determine whether to unwind
77+
/// loops. The first function added will get the first chance to answer, and
78+
/// the first authoratitive (true or false) answer is final.
79+
/// \param handler: new callback
80+
void add_loop_unwind_handler(loop_unwind_handlert handler)
81+
{
82+
loop_unwind_handlers.push_back(handler);
83+
}
84+
85+
/// Add a callback function that will be called to determine whether to unwind
86+
/// recursion. The first function added will get the first chance to answer,
87+
/// and the first authoratitive (true or false) answer is final.
88+
/// \param handler: new callback
89+
void add_recursion_unwind_handler(recursion_unwind_handlert handler)
90+
{
91+
recursion_unwind_handlers.push_back(handler);
92+
}
93+
5694
bool output_coverage_report(
5795
const goto_functionst &goto_functions,
5896
const std::string &path) const
@@ -67,6 +105,8 @@ class symex_bmct: public goto_symext
67105
// 1) a global limit (max_unwind)
68106
// 2) a limit per loop, all threads
69107
// 3) a limit for a particular thread.
108+
// 4) zero or more handler functions that can special-case particular
109+
// functions or loops
70110
// We use the most specific of the above.
71111

72112
unsigned max_unwind;
@@ -78,6 +118,12 @@ class symex_bmct: public goto_symext
78118
typedef std::map<unsigned, loop_limitst> thread_loop_limitst;
79119
thread_loop_limitst thread_loop_limits;
80120

121+
/// Callbacks that may provide an unwind/do-not-unwind decision for a loop
122+
std::vector<loop_unwind_handlert> loop_unwind_handlers;
123+
/// Callbacks that may provide an unwind/do-not-unwind decision for a
124+
/// recursive call
125+
std::vector<recursion_unwind_handlert> recursion_unwind_handlers;
126+
81127
//
82128
// overloaded from goto_symext
83129
//

src/goto-programs/Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ SRC = basic_blocks.cpp \
4747
remove_instanceof.cpp \
4848
remove_returns.cpp \
4949
remove_skip.cpp \
50-
remove_static_init_loops.cpp \
5150
remove_unreachable.cpp \
5251
remove_unused_functions.cpp \
5352
remove_vector.cpp \

src/goto-programs/remove_static_init_loops.cpp

-128
This file was deleted.

src/goto-programs/remove_static_init_loops.h

-36
This file was deleted.

0 commit comments

Comments
 (0)