Skip to content

Commit e918a91

Browse files
committed
Goto-symex: add support for general function accessor
Previously goto-symex presumed access to goto_functionst; now it only requires a function that somehow yields a goto_functiont. This will facilitate integration with lazy_goto_modelt, and in future any other kind of on-demand goto_functiont production.
1 parent 9e31303 commit e918a91

File tree

6 files changed

+119
-56
lines changed

6 files changed

+119
-56
lines changed

src/cbmc/symex_bmc.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ symex_bmct::symex_bmct(
3131

3232
/// show progress
3333
void symex_bmct::symex_step(
34-
const goto_functionst &goto_functions,
34+
const get_goto_functiont &get_goto_function,
3535
statet &state)
3636
{
3737
const source_locationt &source_location=state.source.pc->source_location;
@@ -63,12 +63,12 @@ void symex_bmct::symex_step(
6363
log.statistics() << log.eom;
6464
}
6565

66-
goto_symext::symex_step(goto_functions, state);
66+
goto_symext::symex_step(get_goto_function, state);
6767

6868
if(record_coverage &&
6969
// avoid an invalid iterator in state.source.pc
7070
(!cur_pc->is_end_function() ||
71-
cur_pc->function!=goto_functions.entry_point()))
71+
cur_pc->function!=goto_functionst::entry_point()))
7272
{
7373
// forward goto will effectively be covered via phi function,
7474
// which does not invoke symex_step; as symex_step is called

src/cbmc/symex_bmc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ class symex_bmct: public goto_symext
128128
// overloaded from goto_symext
129129
//
130130
virtual void symex_step(
131-
const goto_functionst &goto_functions,
131+
const get_goto_functiont &get_goto_function,
132132
statet &state);
133133

134134
virtual void merge_goto(

src/goto-symex/goto_symex.h

+48-9
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ class goto_symext
6767

6868
typedef goto_symex_statet statet;
6969

70+
typedef
71+
std::function<const goto_functionst::goto_functiont &(const irep_idt &)>
72+
get_goto_functiont;
73+
7074
/// \brief symex entire program starting from entry point
7175
///
7276
/// The state that goto_symext maintains has a large memory footprint.
@@ -76,6 +80,15 @@ class goto_symext
7680
virtual void symex_from_entry_point_of(
7781
const goto_functionst &goto_functions);
7882

83+
/// \brief symex entire program starting from entry point
84+
///
85+
/// The state that goto_symext maintains has a large memory footprint.
86+
/// This method deallocates the state as soon as symbolic execution
87+
/// has completed, so use it if you don't care about having the state
88+
/// around afterwards.
89+
virtual void symex_from_entry_point_of(
90+
const get_goto_functiont &get_goto_function);
91+
7992
//// \brief symex entire program starting from entry point
8093
///
8194
/// This method uses the `state` argument as the symbolic execution
@@ -88,6 +101,18 @@ class goto_symext
88101
const goto_functionst &,
89102
const goto_programt &);
90103

104+
//// \brief symex entire program starting from entry point
105+
///
106+
/// This method uses the `state` argument as the symbolic execution
107+
/// state, which is useful for examining the state after this method
108+
/// returns. The state that goto_symext maintains has a large memory
109+
/// footprint, so if keeping the state around is not necessary,
110+
/// clients should instead call goto_symext::symex_from_entry_point_of().
111+
virtual void symex_with_state(
112+
statet &,
113+
const get_goto_functiont &,
114+
const goto_programt &);
115+
91116
/// Symexes from the first instruction and the given state, terminating as
92117
/// soon as the last instruction is reached. This is useful to explicitly
93118
/// symex certain ranges of a program, e.g. in an incremental decision
@@ -102,6 +127,20 @@ class goto_symext
102127
goto_programt::const_targett first,
103128
goto_programt::const_targett limit);
104129

130+
/// Symexes from the first instruction and the given state, terminating as
131+
/// soon as the last instruction is reached. This is useful to explicitly
132+
/// symex certain ranges of a program, e.g. in an incremental decision
133+
/// procedure.
134+
/// \param state Symex state to start with.
135+
/// \param get_goto_function retrieves a function body
136+
/// \param first Entry point in form of a first instruction.
137+
/// \param limit Final instruction, which itself will not be symexed.
138+
virtual void symex_instruction_range(
139+
statet &state,
140+
const get_goto_functiont &get_goto_function,
141+
goto_programt::const_targett first,
142+
goto_programt::const_targett limit);
143+
105144
protected:
106145
/// Initialise the symbolic execution and the given state with <code>pc</code>
107146
/// as entry point.
@@ -111,21 +150,21 @@ class goto_symext
111150
/// \param limit final instruction, which itself will not
112151
/// be symexed.
113152
void initialize_entry_point(
114-
statet &,
115-
const goto_functionst &,
153+
statet &state,
154+
const get_goto_functiont &get_goto_function,
116155
goto_programt::const_targett pc,
117156
goto_programt::const_targett limit);
118157

119158
/// Invokes symex_step and verifies whether additional threads can be
120159
/// executed.
121160
/// \param state Current GOTO symex step.
122-
/// \param goto_functions GOTO model to symex.
161+
/// \param get_goto_function function that retrieves function bodies
123162
void symex_threaded_step(
124-
statet &, const goto_functionst &);
163+
statet &, const get_goto_functiont &);
125164

126165
/** execute just one step */
127166
virtual void symex_step(
128-
const goto_functionst &,
167+
const get_goto_functiont &,
129168
statet &);
130169

131170
public:
@@ -213,7 +252,7 @@ class goto_symext
213252
virtual void symex_decl(statet &);
214253
virtual void symex_decl(statet &, const symbol_exprt &expr);
215254
virtual void symex_dead(statet &);
216-
virtual void symex_other(const goto_functionst &, statet &);
255+
virtual void symex_other(statet &);
217256

218257
virtual void vcc(
219258
const exprt &,
@@ -255,19 +294,19 @@ class goto_symext
255294
}
256295

257296
virtual void symex_function_call(
258-
const goto_functionst &,
297+
const get_goto_functiont &,
259298
statet &,
260299
const code_function_callt &);
261300

262301
virtual void symex_end_of_function(statet &);
263302

264303
virtual void symex_function_call_symbol(
265-
const goto_functionst &,
304+
const get_goto_functiont &,
266305
statet &,
267306
const code_function_callt &);
268307

269308
virtual void symex_function_call_code(
270-
const goto_functionst &,
309+
const get_goto_functiont &,
271310
statet &,
272311
const code_function_callt &);
273312

src/goto-symex/symex_function_call.cpp

+7-14
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,14 @@ void goto_symext::parameter_assignments(
172172
}
173173

174174
void goto_symext::symex_function_call(
175-
const goto_functionst &goto_functions,
175+
const get_goto_functiont &get_goto_function,
176176
statet &state,
177177
const code_function_callt &code)
178178
{
179179
const exprt &function=code.function();
180180

181181
if(function.id()==ID_symbol)
182-
symex_function_call_symbol(goto_functions, state, code);
182+
symex_function_call_symbol(get_goto_function, state, code);
183183
else if(function.id()==ID_if)
184184
throw "symex_function_call can't do if";
185185
else if(function.id()==ID_dereference)
@@ -189,7 +189,7 @@ void goto_symext::symex_function_call(
189189
}
190190

191191
void goto_symext::symex_function_call_symbol(
192-
const goto_functionst &goto_functions,
192+
const get_goto_functiont &get_goto_function,
193193
statet &state,
194194
const code_function_callt &code)
195195
{
@@ -213,27 +213,20 @@ void goto_symext::symex_function_call_symbol(
213213
symex_macro(state, code);
214214
}
215215
else
216-
symex_function_call_code(goto_functions, state, code);
216+
symex_function_call_code(get_goto_function, state, code);
217217
}
218218

219219
/// do function call by inlining
220220
void goto_symext::symex_function_call_code(
221-
const goto_functionst &goto_functions,
221+
const get_goto_functiont &get_goto_function,
222222
statet &state,
223223
const code_function_callt &call)
224224
{
225225
const irep_idt &identifier=
226226
to_symbol_expr(call.function()).get_identifier();
227227

228-
// find code in function map
229-
230-
goto_functionst::function_mapt::const_iterator it=
231-
goto_functions.function_map.find(identifier);
232-
233-
if(it==goto_functions.function_map.end())
234-
throw "failed to find `"+id2string(identifier)+"' in function_map";
235-
236-
const goto_functionst::goto_functiont &goto_function=it->second;
228+
const goto_functionst::goto_functiont &goto_function =
229+
get_goto_function(identifier);
237230

238231
if(state.dirty)
239232
state.dirty->populate_dirty_for_function(identifier, goto_function);

src/goto-symex/symex_main.cpp

+60-28
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ void goto_symext::rewrite_quantifiers(exprt &expr, statet &state)
126126

127127
void goto_symext::initialize_entry_point(
128128
statet &state,
129-
const goto_functionst &goto_functions,
129+
const get_goto_functiont &get_goto_function,
130130
const goto_programt::const_targett pc,
131131
const goto_programt::const_targett limit)
132132
{
@@ -137,23 +137,19 @@ void goto_symext::initialize_entry_point(
137137
state.top().calling_location.pc=state.top().end_of_function;
138138
state.symex_target=&target;
139139
state.dirty=util_make_unique<incremental_dirtyt>();
140-
if(!pc->function.empty())
141-
{
142-
state.dirty->populate_dirty_for_function(
143-
pc->function, goto_functions.function_map.at(pc->function));
144-
}
145-
else
146-
{
147-
log.warning() << "Unable to analyse address-taken locals, as start "
148-
"instruction does not state its function" << messaget::eom;
149-
}
140+
141+
INVARIANT(
142+
!pc->function.empty(), "all symexed instructions should have a function");
143+
state.dirty->populate_dirty_for_function(
144+
pc->function, get_goto_function(pc->function));
145+
150146
symex_transition(state, state.source.pc);
151147
}
152148

153149
void goto_symext::symex_threaded_step(
154-
statet &state, const goto_functionst &goto_functions)
150+
statet &state, const get_goto_functiont &get_goto_function)
155151
{
156-
symex_step(goto_functions, state);
152+
symex_step(get_goto_function, state);
157153

158154
// is there another thread to execute?
159155
if(state.call_stack().empty() &&
@@ -168,21 +164,39 @@ void goto_symext::symex_threaded_step(
168164
}
169165
}
170166

167+
static goto_symext::get_goto_functiont get_function_from_goto_functions(
168+
const goto_functionst &goto_functions)
169+
{
170+
return [&goto_functions](const irep_idt &key) ->
171+
const goto_functionst::goto_functiont & { // NOLINT(*)
172+
return goto_functions.function_map.at(key);
173+
};
174+
}
175+
171176
void goto_symext::symex_with_state(
172177
statet &state,
173178
const goto_functionst &goto_functions,
174179
const goto_programt &goto_program)
180+
{
181+
symex_with_state(
182+
state, get_function_from_goto_functions(goto_functions), goto_program);
183+
}
184+
185+
void goto_symext::symex_with_state(
186+
statet &state,
187+
const get_goto_functiont &get_goto_function,
188+
const goto_programt &goto_program)
175189
{
176190
PRECONDITION(!goto_program.instructions.empty());
177191
initialize_entry_point(
178192
state,
179-
goto_functions,
193+
get_goto_function,
180194
goto_program.instructions.begin(),
181195
prev(goto_program.instructions.end()));
182196
PRECONDITION(state.top().end_of_function->is_end_function());
183197

184198
while(!state.call_stack().empty())
185-
symex_threaded_step(state, goto_functions);
199+
symex_threaded_step(state, get_goto_function);
186200

187201
state.dirty=nullptr;
188202
}
@@ -193,30 +207,48 @@ void goto_symext::symex_instruction_range(
193207
const goto_programt::const_targett first,
194208
const goto_programt::const_targett limit)
195209
{
196-
initialize_entry_point(state, goto_functions, first, limit);
210+
symex_instruction_range(
211+
state, get_function_from_goto_functions(goto_functions), first, limit);
212+
}
213+
214+
void goto_symext::symex_instruction_range(
215+
statet &state,
216+
const get_goto_functiont &get_goto_function,
217+
const goto_programt::const_targett first,
218+
const goto_programt::const_targett limit)
219+
{
220+
initialize_entry_point(state, get_goto_function, first, limit);
197221
while(state.source.pc->function!=limit->function || state.source.pc!=limit)
198-
symex_threaded_step(state, goto_functions);
222+
symex_threaded_step(state, get_goto_function);
199223
}
200224

201-
/// symex from entry point
202225
void goto_symext::symex_from_entry_point_of(
203-
const goto_functionst &goto_functions)
226+
const goto_functionst &goto_functions)
204227
{
205-
goto_functionst::function_mapt::const_iterator it=
206-
goto_functions.function_map.find(goto_functionst::entry_point());
228+
symex_from_entry_point_of(get_function_from_goto_functions(goto_functions));
229+
}
207230

208-
if(it==goto_functions.function_map.end())
231+
/// symex from entry point
232+
void goto_symext::symex_from_entry_point_of(
233+
const get_goto_functiont &get_goto_function)
234+
{
235+
const goto_functionst::goto_functiont *start_function;
236+
try
237+
{
238+
start_function = &get_goto_function(goto_functionst::entry_point());
239+
}
240+
catch(const std::out_of_range &error)
241+
{
209242
throw "the program has no entry point";
210-
211-
const goto_programt &body=it->second.body;
243+
}
212244

213245
statet state;
214-
symex_with_state(state, goto_functions, body);
246+
symex_with_state(state, get_goto_function, start_function->body);
215247
}
216248

217249
/// do just one step
218250
void goto_symext::symex_step(
219-
const goto_functionst &goto_functions,
251+
const get_goto_functiont &get_goto_function,
220252
statet &state)
221253
{
222254
#if 0
@@ -321,15 +353,15 @@ void goto_symext::symex_step(
321353
Forall_expr(it, deref_code.arguments())
322354
clean_expr(*it, state, false);
323355

324-
symex_function_call(goto_functions, state, deref_code);
356+
symex_function_call(get_goto_function, state, deref_code);
325357
}
326358
else
327359
symex_transition(state);
328360
break;
329361

330362
case OTHER:
331363
if(!state.guard.is_false())
332-
symex_other(goto_functions, state);
364+
symex_other(state);
333365

334366
symex_transition(state);
335367
break;

src/goto-symex/symex_other.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ void goto_symext::havoc_rec(
7979
}
8080

8181
void goto_symext::symex_other(
82-
const goto_functionst &goto_functions,
8382
statet &state)
8483
{
8584
const goto_programt::instructiont &instruction=*state.source.pc;

0 commit comments

Comments
 (0)