CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
build_goto_trace.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Traces of GOTO Programs
4
5Author: Daniel Kroening
6
7 Date: July 2005
8
9\*******************************************************************/
10
13
14#include "build_goto_trace.h"
15
16#include <util/arith_tools.h>
17#include <util/byte_operators.h>
18#include <util/namespace.h>
19#include <util/simplify_expr.h>
20#include <util/symbol.h>
21
24
26
28
30 const decision_proceduret &decision_procedure,
31 const namespacet &ns,
32 const exprt &src_original, // original identifiers
33 const exprt &src_ssa) // renamed identifiers
34{
35 if(src_ssa.id()!=src_original.id())
36 return src_original;
37
38 const irep_idt id=src_original.id();
39
40 if(id==ID_index)
41 {
42 // get index value from src_ssa
43 exprt index_value = decision_procedure.get(to_index_expr(src_ssa).index());
44
45 if(index_value.is_not_nil())
46 {
49 tmp.index()=index_value;
50 tmp.array() = build_full_lhs_rec(
51 decision_procedure,
52 ns,
54 to_index_expr(src_ssa).array());
55 return std::move(tmp);
56 }
57
58 return src_original;
59 }
60 else if(id==ID_member)
61 {
63 tmp.struct_op() = build_full_lhs_rec(
64 decision_procedure,
65 ns,
66 to_member_expr(src_original).struct_op(),
67 to_member_expr(src_ssa).struct_op());
68 }
69 else if(id==ID_if)
70 {
72
73 tmp2.false_case() = build_full_lhs_rec(
74 decision_procedure,
75 ns,
76 tmp2.false_case(),
77 to_if_expr(src_ssa).false_case());
78
79 tmp2.true_case() = build_full_lhs_rec(
80 decision_procedure,
81 ns,
82 tmp2.true_case(),
83 to_if_expr(src_ssa).true_case());
84
85 exprt tmp = decision_procedure.get(to_if_expr(src_ssa).cond());
86
87 if(tmp.is_true())
88 return tmp2.true_case();
89 else if(tmp.is_false())
90 return tmp2.false_case();
91 else
92 return std::move(tmp2);
93 }
94 else if(id==ID_typecast)
95 {
98 decision_procedure,
99 ns,
102 return std::move(tmp);
103 }
104 else if(id==ID_byte_extract_little_endian ||
106 {
108 tmp.op() = build_full_lhs_rec(
109 decision_procedure, ns, tmp.op(), to_byte_extract_expr(src_ssa).op());
110
111 // re-write into big case-split
112 }
113
114 return src_original;
115}
116
120 const exprt &expr,
122 const namespacet &ns)
123{
124 if(expr.id()==ID_symbol)
125 {
126 const auto &type = expr.type();
127 if(type.id() != ID_code && type.id() != ID_mathematical_function)
128 {
129 const irep_idt &id = to_ssa_expr(expr).get_original_name();
130 const symbolt *symbol;
131 if(!ns.lookup(id, symbol))
132 {
133 bool result = symbol->type.get_bool(ID_C_dynamic);
134 if(result)
135 goto_trace_step.internal = true;
136 }
137 }
138 }
139 else
140 {
141 for(const auto &op : expr.operands())
143 }
144}
145
149 const SSA_stept &SSA_step,
151 const namespacet &ns)
152{
153 // set internal for dynamic_object in both lhs and rhs expressions
156
157 // set internal field to CPROVER functions (e.g., __CPROVER_initialize)
158 if(SSA_step.is_function_call())
159 {
160 if(SSA_step.source.pc->source_location().as_string().empty())
161 goto_trace_step.internal=true;
162 }
163
164 // set internal field to input and output steps
167 {
168 goto_trace_step.internal=true;
169 }
170
171 // set internal field to _start function-return step
173 {
174 // "__CPROVER_*" function calls in __CPROVER_start are already marked as
175 // internal. Don't mark any other function calls (i.e. "main"), function
176 // arguments or any other parts of a code_function_callt as internal.
177 if(SSA_step.source.pc->code().get_statement() != ID_function_call)
178 goto_trace_step.internal=true;
179 }
180}
181
184static void
186{
187 if(type.id() == ID_array)
188 {
190 array_type.size() = solver.get(array_type.size());
191 }
192
193 if(type.has_subtype())
195}
196
199static void
201{
203 for(auto &sub : expr.operands())
205}
206
208 const symex_target_equationt &target,
210 const decision_proceduret &decision_procedure,
211 const namespacet &ns,
213{
214 // We need to re-sort the steps according to their clock.
215 // Furthermore, read-events need to occur before write
216 // events with the same clock.
217
218 typedef symex_target_equationt::SSA_stepst::const_iterator ssa_step_iteratort;
219 typedef std::map<mp_integer, std::vector<ssa_step_iteratort>> time_mapt;
221
223 const bool has_threads = target.has_threads();
224
226 bool last_step_was_kept = false;
227
228 // First sort the SSA steps by time, in the process dropping steps
229 // we definitely don't want to retain in the final trace:
230
231 for(ssa_step_iteratort it = target.SSA_steps.begin();
232 it != target.SSA_steps.end();
233 it++)
234 {
235 if(
236 last_step_to_keep == target.SSA_steps.end() &&
237 is_last_step_to_keep(it, decision_procedure))
238 {
240 }
241
242 const SSA_stept &SSA_step = *it;
243
244 if(!decision_procedure.get(SSA_step.guard_handle).is_true())
245 continue;
246
247 if(it->is_constraint() ||
248 it->is_spawn())
249 continue;
250 else if(it->is_atomic_begin())
251 {
252 // for atomic sections the timing can only be determined once we see
253 // a shared read or write (if there is none, the time will be
254 // reverted to the time before entering the atomic section); we thus
255 // use a temporary negative time slot to gather all events
256 current_time*=-1;
257 continue;
258 }
259 else if(it->is_shared_read() || it->is_shared_write() ||
260 it->is_atomic_end())
261 {
262 if(!has_threads)
263 continue;
264
266
267 if(it->is_shared_read() || it->is_shared_write())
268 {
269 // these are just used to get the time stamp -- the clock type is
270 // computed to be of the minimal necessary size, but we don't need to
271 // know it to get the value so just use typeless
272 exprt clock_value = decision_procedure.get(
274
276 if(cv.has_value())
277 current_time = *cv;
278 else
279 current_time = 0;
280 }
281 else if(it->is_atomic_end() && current_time<0)
282 current_time*=-1;
283
284 INVARIANT(current_time >= 0, "time keeping inconsistency");
285 // move any steps gathered in an atomic section
286
287 if(time_before<0)
288 {
289 time_mapt::const_iterator time_before_steps_it =
290 time_map.find(time_before);
291
292 if(time_before_steps_it != time_map.end())
293 {
294 std::vector<ssa_step_iteratort> &current_time_steps =
296
297 current_time_steps.insert(
298 current_time_steps.end(),
299 time_before_steps_it->second.begin(),
300 time_before_steps_it->second.end());
301
303 }
304 }
305
306 continue;
307 }
308
309 // drop PHI and GUARD assignments altogether
310 if(it->is_assignment() &&
311 (SSA_step.assignment_type==
313 SSA_step.assignment_type==
315 {
316 continue;
317 }
318
319 if(it == last_step_to_keep)
320 {
321 last_step_was_kept = true;
322 }
323
324 time_map[current_time].push_back(it);
325 }
326
327 INVARIANT(
329 "last step in SSA trace to keep must not be filtered out as a sync "
330 "instruction, not-taken branch, PHI node, or similar");
331
332 // Now build the GOTO trace, ordered by time, then by SSA trace order.
333
334 // produce the step numbers
335 unsigned step_nr = 0;
336
337 for(const auto &time_and_ssa_steps : time_map)
338 {
339 for(const auto &ssa_step_it : time_and_ssa_steps.second)
340 {
341 const auto &SSA_step = *ssa_step_it;
342 goto_trace.steps.push_back(goto_trace_stept());
344
345 goto_trace_step.step_nr = ++step_nr;
346
347 goto_trace_step.thread_nr = SSA_step.source.thread_nr;
348 goto_trace_step.pc = SSA_step.source.pc;
349 goto_trace_step.function_id = SSA_step.source.function_id;
350 if(SSA_step.is_assert())
351 {
352 goto_trace_step.comment = SSA_step.comment;
353 goto_trace_step.property_id = SSA_step.property_id;
354 }
355 goto_trace_step.type = SSA_step.type;
356 goto_trace_step.hidden = SSA_step.hidden;
357 goto_trace_step.format_string = SSA_step.format_string;
358 goto_trace_step.io_id = SSA_step.io_id;
359 goto_trace_step.formatted = SSA_step.formatted;
360 goto_trace_step.called_function = SSA_step.called_function;
361
362 for(const auto &arg : SSA_step.converted_function_arguments)
363 {
364 goto_trace_step.function_arguments.push_back(
365 simplify_expr(decision_procedure.get(arg), ns));
366 }
367
368 // update internal field for specific variables in the counterexample
370
371 goto_trace_step.assignment_type =
372 (SSA_step.is_assignment() &&
373 (SSA_step.assignment_type ==
375 SSA_step.assignment_type ==
379
380 if(SSA_step.original_full_lhs.is_not_nil())
381 {
384 decision_procedure,
385 ns,
386 SSA_step.original_full_lhs,
387 SSA_step.ssa_full_lhs),
388 ns);
389 replace_nondet_in_type(goto_trace_step.full_lhs, decision_procedure);
390 restore_union(goto_trace_step.full_lhs, ns);
391 }
392
393 if(SSA_step.ssa_full_lhs.is_not_nil())
394 {
395 goto_trace_step.full_lhs_value =
396 decision_procedure.get(SSA_step.ssa_full_lhs);
397 simplify(goto_trace_step.full_lhs_value, ns);
399 goto_trace_step.full_lhs_value, decision_procedure);
400 }
401
402 for(const auto &j : SSA_step.converted_io_args)
403 {
404 goto_trace_step.io_args.push_back(
405 simplify_expr(decision_procedure.get(j), ns));
406 }
407
408 if(SSA_step.is_assert() || SSA_step.is_assume() || SSA_step.is_goto())
409 {
410 goto_trace_step.cond_expr = SSA_step.cond_expr;
411
412 goto_trace_step.cond_value =
413 decision_procedure.get(SSA_step.cond_handle).is_true();
414 }
415
416 if(SSA_step.source.pc->is_assert() || SSA_step.source.pc->is_assume())
417 {
418 goto_trace_step.original_condition = SSA_step.source.pc->condition();
419 restore_union(goto_trace_step.original_condition, ns);
420 }
421
423 return;
424 }
425 }
426}
427
429 const symex_target_equationt &target,
430 symex_target_equationt::SSA_stepst::const_iterator last_step_to_keep,
431 const decision_proceduret &decision_procedure,
432 const namespacet &ns,
434{
435 const auto is_last_step_to_keep =
437 symex_target_equationt::SSA_stepst::const_iterator it,
438 const decision_proceduret &) { return last_step_to_keep == it; };
439
440 return build_goto_trace(
441 target, is_last_step_to_keep, decision_procedure, ns, goto_trace);
442}
443
445 symex_target_equationt::SSA_stepst::const_iterator step,
446 const decision_proceduret &decision_procedure)
447{
448 return step->is_assert() &&
449 decision_procedure.get(step->cond_handle).is_false();
450}
451
453 const symex_target_equationt &target,
454 const decision_proceduret &decision_procedure,
455 const namespacet &ns,
457{
459 target, is_failed_assertion_step, decision_procedure, ns, goto_trace);
460}
static exprt build_full_lhs_rec(const decision_proceduret &decision_procedure, const namespacet &ns, const exprt &src_original, const exprt &src_ssa)
static void set_internal_dynamic_object(const exprt &expr, goto_trace_stept &goto_trace_step, const namespacet &ns)
set internal field for variable assignment related to dynamic_object[0-9] and dynamic_[0-9]_array.
static void update_internal_field(const SSA_stept &SSA_step, goto_trace_stept &goto_trace_step, const namespacet &ns)
set internal for variables assignments related to dynamic_object and CPROVER internal functions (e....
static bool is_failed_assertion_step(symex_target_equationt::SSA_stepst::const_iterator step, const decision_proceduret &decision_procedure)
static void replace_nondet_in_type(typet &type, const decision_proceduret &solver)
Replace nondet values that appear in type by their values as found by solver.
void build_goto_trace(const symex_target_equationt &target, ssa_step_predicatet is_last_step_to_keep, const decision_proceduret &decision_procedure, const namespacet &ns, goto_tracet &goto_trace)
Build a trace by going through the steps of target and stopping after the step matching a given condi...
Traces of GOTO Programs.
std::function< bool(symex_target_equationt::SSA_stepst::const_iterator, const decision_proceduret &)> ssa_step_predicatet
Expression classes for byte-level operators.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
Single SSA step in the equation.
Definition ssa_step.h:47
exprt guard_handle
Definition ssa_step.h:136
symex_targett::assignment_typet assignment_type
Definition ssa_step.h:142
exprt ssa_rhs
Definition ssa_step.h:141
symex_targett::sourcet source
Definition ssa_step.h:49
bool is_function_call() const
Definition ssa_step.h:92
ssa_exprt ssa_lhs
Definition ssa_step.h:139
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Arrays with given size.
Definition std_types.h:807
Expression of type type extracted from some object op starting at position offset (given in number of...
An interface for a decision procedure for satisfiability problems.
virtual exprt get(const exprt &) const =0
Return expr with variables replaced by values from satisfying assignment if available.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Base class for all expressions.
Definition expr.h:56
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
static irep_idt entry_point()
Get the identifier of the entry point to a goto model.
Step of the trace of a GOTO program.
Definition goto_trace.h:50
Trace of a GOTO program.
Definition goto_trace.h:177
The trinary if-then-else operator.
Definition std_expr.h:2497
Array index operator.
Definition std_expr.h:1470
bool get_bool(const irep_idt &name) const
Definition irep.cpp:57
const irep_idt & id() const
Definition irep.h:388
Extract member of struct or union.
Definition std_expr.h:2971
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
static irep_idt rw_clock_id(event_it e, axiomt axiom=AX_PROPAGATION)
Build identifier for the read/write clock variable.
static symbol_exprt typeless(const irep_idt &id)
Generate a symbol_exprt without a proper type.
Definition std_expr.h:150
Symbol table entry.
Definition symbol.h:28
typet type
Type of symbol.
Definition symbol.h:31
Inheriting the interface of symex_targett this class represents the SSA form of the input program as ...
Semantic type conversion.
Definition std_expr.h:2073
The type of an expression, extends irept.
Definition type.h:29
bool has_subtype() const
Definition type.h:64
Decision Procedure Interface.
Goto Programs with Functions.
Add constraints to equation encoding partial orders on events.
void restore_union(exprt &expr, const namespacet &ns)
Undo the union access -> byte_extract replacement that rewrite_union did for the purpose of displayin...
Symbolic Execution.
bool simplify(exprt &expr, const namespacet &ns)
exprt simplify_expr(exprt src, const namespacet &ns)
BigInt mp_integer
Definition smt_terms.h:17
void solver(std::vector< framet > &frames, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const solver_optionst &solver_options, const namespacet &ns, std::vector< propertyt > &properties, std::size_t property_index)
Definition solver.cpp:44
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
Definition ssa_expr.h:145
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2577
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
goto_programt::const_targett pc
Symbol table entry.
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition type.h:208