Skip to content

Commit 8358828

Browse files
committed
SSA trace: don't concretise steps that will subsequently be dropped
Previously the SSA trace did all concretisation (taking the solver's output and turning it into concrete expressions to be output in the result trace) before sorting the steps by time and determining what belongs in the final trace. This was generally harmless, but could result in much wasted time and potentially memory exhaustion when concretising very large arrays and strings. Therefore, we now perform the time-order sort and figure out which steps are to be kept first, *then* concretise them.
1 parent f6c34f2 commit 8358828

File tree

1 file changed

+98
-89
lines changed

1 file changed

+98
-89
lines changed

src/goto-symex/build_goto_trace.cpp

+98-89
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,20 @@ void build_goto_trace(
173173
// Furthermore, read-events need to occur before write
174174
// events with the same clock.
175175

176-
typedef std::map<mp_integer, goto_tracet::stepst> time_mapt;
176+
typedef symex_target_equationt::SSA_stepst::const_iterator ssa_step_iteratort;
177+
typedef std::map<mp_integer, std::vector<ssa_step_iteratort>> time_mapt;
177178
time_mapt time_map;
178179

179180
mp_integer current_time=0;
180181

181-
const goto_trace_stept *end_ptr=nullptr;
182182
bool end_step_seen=false;
183+
ssa_step_iteratort last_step_in_goto_trace = target.SSA_steps.end();
183184

184-
for(symex_target_equationt::SSA_stepst::const_iterator
185-
it=target.SSA_steps.begin();
186-
it!=target.SSA_steps.end();
185+
// First sort the SSA steps by time, in the process dropping steps
186+
// we definitely don't want to retain in the final trace:
187+
188+
for(ssa_step_iteratort it = target.SSA_steps.begin();
189+
it != target.SSA_steps.end();
187190
it++)
188191
{
189192
if(it==end_step)
@@ -227,12 +230,21 @@ void build_goto_trace(
227230

228231
if(time_before<0)
229232
{
230-
time_mapt::iterator entry=
231-
time_map.insert(std::make_pair(
232-
current_time,
233-
goto_tracet::stepst())).first;
234-
entry->second.splice(entry->second.end(), time_map[time_before]);
235-
time_map.erase(time_before);
233+
time_mapt::const_iterator time_before_steps_it =
234+
time_map.find(time_before);
235+
236+
if(time_before_steps_it != time_map.end())
237+
{
238+
std::vector<ssa_step_iteratort> &current_time_steps =
239+
time_map[current_time];
240+
241+
current_time_steps.insert(
242+
current_time_steps.end(),
243+
time_before_steps_it->second.begin(),
244+
time_before_steps_it->second.end());
245+
246+
time_map.erase(time_before_steps_it);
247+
}
236248
}
237249

238250
continue;
@@ -248,97 +260,94 @@ void build_goto_trace(
248260
continue;
249261
}
250262

251-
goto_tracet::stepst &steps=time_map[current_time];
252-
steps.push_back(goto_trace_stept());
253-
goto_trace_stept &goto_trace_step=steps.back();
254-
if(!end_step_seen)
255-
end_ptr=&goto_trace_step;
256-
257-
goto_trace_step.thread_nr=SSA_step.source.thread_nr;
258-
goto_trace_step.pc=SSA_step.source.pc;
259-
goto_trace_step.comment=SSA_step.comment;
260-
if(SSA_step.ssa_lhs.is_not_nil())
261-
goto_trace_step.lhs_object=
262-
ssa_exprt(SSA_step.ssa_lhs.get_original_expr());
263-
else
264-
goto_trace_step.lhs_object.make_nil();
265-
goto_trace_step.type=SSA_step.type;
266-
goto_trace_step.hidden=SSA_step.hidden;
267-
goto_trace_step.format_string=SSA_step.format_string;
268-
goto_trace_step.io_id=SSA_step.io_id;
269-
goto_trace_step.formatted=SSA_step.formatted;
270-
goto_trace_step.identifier=SSA_step.identifier;
271-
272-
// update internal field for specific variables in the counterexample
273-
update_internal_field(SSA_step, goto_trace_step, ns);
274-
275-
goto_trace_step.assignment_type=
276-
(it->is_assignment()&&
277-
(SSA_step.assignment_type==
278-
symex_targett::assignment_typet::VISIBLE_ACTUAL_PARAMETER ||
279-
SSA_step.assignment_type==
280-
symex_targett::assignment_typet::HIDDEN_ACTUAL_PARAMETER))?
281-
goto_trace_stept::assignment_typet::ACTUAL_PARAMETER:
282-
goto_trace_stept::assignment_typet::STATE;
263+
time_map[current_time].push_back(it);
283264

284-
if(SSA_step.original_full_lhs.is_not_nil())
285-
goto_trace_step.full_lhs=
286-
build_full_lhs_rec(
287-
prop_conv, ns, SSA_step.original_full_lhs, SSA_step.ssa_full_lhs);
265+
if(!end_step_seen)
266+
last_step_in_goto_trace = it;
267+
}
288268

289-
if(SSA_step.ssa_lhs.is_not_nil())
290-
goto_trace_step.lhs_object_value=prop_conv.get(SSA_step.ssa_lhs);
269+
// Now build the GOTO trace, ordered by time, then by SSA trace order.
291270

292-
if(SSA_step.ssa_full_lhs.is_not_nil())
293-
{
294-
goto_trace_step.full_lhs_value=prop_conv.get(SSA_step.ssa_full_lhs);
295-
simplify(goto_trace_step.full_lhs_value, ns);
296-
}
271+
// produce the step numbers
272+
unsigned step_nr=0;
297273

298-
for(const auto &j : SSA_step.converted_io_args)
274+
for(const auto &time_and_ssa_steps : time_map)
275+
{
276+
for(const auto ssa_step_it : time_and_ssa_steps.second)
299277
{
300-
if(j.is_constant() ||
301-
j.id()==ID_string_constant)
302-
goto_trace_step.io_args.push_back(j);
278+
const auto &SSA_step = *ssa_step_it;
279+
goto_trace.steps.push_back(goto_trace_stept());
280+
goto_trace_stept &goto_trace_step = goto_trace.steps.back();
281+
282+
goto_trace_step.step_nr = ++step_nr;
283+
284+
goto_trace_step.thread_nr=SSA_step.source.thread_nr;
285+
goto_trace_step.pc=SSA_step.source.pc;
286+
goto_trace_step.comment=SSA_step.comment;
287+
if(SSA_step.ssa_lhs.is_not_nil())
288+
goto_trace_step.lhs_object=
289+
ssa_exprt(SSA_step.ssa_lhs.get_original_expr());
303290
else
291+
goto_trace_step.lhs_object.make_nil();
292+
goto_trace_step.type=SSA_step.type;
293+
goto_trace_step.hidden=SSA_step.hidden;
294+
goto_trace_step.format_string=SSA_step.format_string;
295+
goto_trace_step.io_id=SSA_step.io_id;
296+
goto_trace_step.formatted=SSA_step.formatted;
297+
goto_trace_step.identifier=SSA_step.identifier;
298+
299+
// update internal field for specific variables in the counterexample
300+
update_internal_field(SSA_step, goto_trace_step, ns);
301+
302+
goto_trace_step.assignment_type=
303+
(SSA_step.is_assignment() &&
304+
(SSA_step.assignment_type==
305+
symex_targett::assignment_typet::VISIBLE_ACTUAL_PARAMETER ||
306+
SSA_step.assignment_type==
307+
symex_targett::assignment_typet::HIDDEN_ACTUAL_PARAMETER))?
308+
goto_trace_stept::assignment_typet::ACTUAL_PARAMETER:
309+
goto_trace_stept::assignment_typet::STATE;
310+
311+
if(SSA_step.original_full_lhs.is_not_nil())
312+
goto_trace_step.full_lhs=
313+
build_full_lhs_rec(
314+
prop_conv, ns, SSA_step.original_full_lhs, SSA_step.ssa_full_lhs);
315+
316+
if(SSA_step.ssa_lhs.is_not_nil())
317+
goto_trace_step.lhs_object_value=prop_conv.get(SSA_step.ssa_lhs);
318+
319+
if(SSA_step.ssa_full_lhs.is_not_nil())
304320
{
305-
exprt tmp=prop_conv.get(j);
306-
goto_trace_step.io_args.push_back(tmp);
321+
goto_trace_step.full_lhs_value=prop_conv.get(SSA_step.ssa_full_lhs);
322+
simplify(goto_trace_step.full_lhs_value, ns);
307323
}
308-
}
309324

310-
if(SSA_step.is_assert() ||
311-
SSA_step.is_assume() ||
312-
SSA_step.is_goto())
313-
{
314-
goto_trace_step.cond_expr=SSA_step.cond_expr;
325+
for(const auto &j : SSA_step.converted_io_args)
326+
{
327+
if(j.is_constant() ||
328+
j.id()==ID_string_constant)
329+
goto_trace_step.io_args.push_back(j);
330+
else
331+
{
332+
exprt tmp=prop_conv.get(j);
333+
goto_trace_step.io_args.push_back(tmp);
334+
}
335+
}
315336

316-
goto_trace_step.cond_value=
317-
prop_conv.l_get(SSA_step.cond_literal).is_true();
318-
}
319-
}
337+
if(SSA_step.is_assert() ||
338+
SSA_step.is_assume() ||
339+
SSA_step.is_goto())
340+
{
341+
goto_trace_step.cond_expr=SSA_step.cond_expr;
320342

321-
// Now assemble into a single goto_trace.
322-
// This exploits sorted-ness of the map.
323-
for(auto &t_it : time_map)
324-
goto_trace.steps.splice(goto_trace.steps.end(), t_it.second);
343+
goto_trace_step.cond_value=
344+
prop_conv.l_get(SSA_step.cond_literal).is_true();
345+
}
325346

326-
// cut off the trace at the desired end
327-
for(goto_tracet::stepst::iterator
328-
s_it1=goto_trace.steps.begin();
329-
s_it1!=goto_trace.steps.end();
330-
++s_it1)
331-
if(end_step_seen && end_ptr==&(*s_it1))
332-
{
333-
goto_trace.trim_after(s_it1);
334-
break;
347+
if(ssa_step_it == last_step_in_goto_trace)
348+
return;
335349
}
336-
337-
// produce the step numbers
338-
unsigned step_nr=0;
339-
340-
for(auto &s_it : goto_trace.steps)
341-
s_it.step_nr=++step_nr;
350+
}
342351
}
343352

344353
void build_goto_trace(

0 commit comments

Comments
 (0)