CBMC
build_goto_trace.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Traces of GOTO Programs
4 
5 Author: 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/simplify_expr.h>
19 #include <util/symbol.h>
20 
22 
24 
26 
28  const decision_proceduret &decision_procedure,
29  const namespacet &ns,
30  const exprt &src_original, // original identifiers
31  const exprt &src_ssa) // renamed identifiers
32 {
33  if(src_ssa.id()!=src_original.id())
34  return src_original;
35 
36  const irep_idt id=src_original.id();
37 
38  if(id==ID_index)
39  {
40  // get index value from src_ssa
41  exprt index_value = decision_procedure.get(to_index_expr(src_ssa).index());
42 
43  if(index_value.is_not_nil())
44  {
45  simplify(index_value, ns);
46  index_exprt tmp=to_index_expr(src_original);
47  tmp.index()=index_value;
48  tmp.array() = build_full_lhs_rec(
49  decision_procedure,
50  ns,
51  to_index_expr(src_original).array(),
52  to_index_expr(src_ssa).array());
53  return std::move(tmp);
54  }
55 
56  return src_original;
57  }
58  else if(id==ID_member)
59  {
60  member_exprt tmp=to_member_expr(src_original);
62  decision_procedure,
63  ns,
64  to_member_expr(src_original).struct_op(),
65  to_member_expr(src_ssa).struct_op());
66  }
67  else if(id==ID_if)
68  {
69  if_exprt tmp2=to_if_expr(src_original);
70 
72  decision_procedure,
73  ns,
74  tmp2.false_case(),
75  to_if_expr(src_ssa).false_case());
76 
78  decision_procedure,
79  ns,
80  tmp2.true_case(),
81  to_if_expr(src_ssa).true_case());
82 
83  exprt tmp = decision_procedure.get(to_if_expr(src_ssa).cond());
84 
85  if(tmp.is_true())
86  return tmp2.true_case();
87  else if(tmp.is_false())
88  return tmp2.false_case();
89  else
90  return std::move(tmp2);
91  }
92  else if(id==ID_typecast)
93  {
94  typecast_exprt tmp=to_typecast_expr(src_original);
95  tmp.op() = build_full_lhs_rec(
96  decision_procedure,
97  ns,
98  to_typecast_expr(src_original).op(),
99  to_typecast_expr(src_ssa).op());
100  return std::move(tmp);
101  }
102  else if(id==ID_byte_extract_little_endian ||
103  id==ID_byte_extract_big_endian)
104  {
105  byte_extract_exprt tmp = to_byte_extract_expr(src_original);
106  tmp.op() = build_full_lhs_rec(
107  decision_procedure, ns, tmp.op(), to_byte_extract_expr(src_ssa).op());
108 
109  // re-write into big case-split
110  }
111 
112  return src_original;
113 }
114 
118  const exprt &expr,
119  goto_trace_stept &goto_trace_step,
120  const namespacet &ns)
121 {
122  if(expr.id()==ID_symbol)
123  {
124  const auto &type = expr.type();
125  if(type.id() != ID_code && type.id() != ID_mathematical_function)
126  {
127  const irep_idt &id = to_ssa_expr(expr).get_original_name();
128  const symbolt *symbol;
129  if(!ns.lookup(id, symbol))
130  {
131  bool result = symbol->type.get_bool(ID_C_dynamic);
132  if(result)
133  goto_trace_step.internal = true;
134  }
135  }
136  }
137  else
138  {
139  forall_operands(it, expr)
140  set_internal_dynamic_object(*it, goto_trace_step, ns);
141  }
142 }
143 
147  const SSA_stept &SSA_step,
148  goto_trace_stept &goto_trace_step,
149  const namespacet &ns)
150 {
151  // set internal for dynamic_object in both lhs and rhs expressions
152  set_internal_dynamic_object(SSA_step.ssa_lhs, goto_trace_step, ns);
153  set_internal_dynamic_object(SSA_step.ssa_rhs, goto_trace_step, ns);
154 
155  // set internal field to CPROVER functions (e.g., __CPROVER_initialize)
156  if(SSA_step.is_function_call())
157  {
158  if(SSA_step.source.pc->source_location().as_string().empty())
159  goto_trace_step.internal=true;
160  }
161 
162  // set internal field to input and output steps
163  if(goto_trace_step.type==goto_trace_stept::typet::OUTPUT ||
164  goto_trace_step.type==goto_trace_stept::typet::INPUT)
165  {
166  goto_trace_step.internal=true;
167  }
168 
169  // set internal field to _start function-return step
171  {
172  // "__CPROVER_*" function calls in __CPROVER_start are already marked as
173  // internal. Don't mark any other function calls (i.e. "main"), function
174  // arguments or any other parts of a code_function_callt as internal.
175  if(SSA_step.source.pc->code().get_statement() != ID_function_call)
176  goto_trace_step.internal=true;
177  }
178 }
179 
182 static void
184 {
185  if(type.id() == ID_array)
186  {
187  array_typet &array_type = to_array_type(type);
188  array_type.size() = solver.get(array_type.size());
189  }
190 
191  if(type.has_subtype())
193 }
194 
197 static void
199 {
201  for(auto &sub : expr.operands())
203 }
204 
206  const symex_target_equationt &target,
207  ssa_step_predicatet is_last_step_to_keep,
208  const decision_proceduret &decision_procedure,
209  const namespacet &ns,
210  goto_tracet &goto_trace)
211 {
212  // We need to re-sort the steps according to their clock.
213  // Furthermore, read-events need to occur before write
214  // events with the same clock.
215 
216  typedef symex_target_equationt::SSA_stepst::const_iterator ssa_step_iteratort;
217  typedef std::map<mp_integer, std::vector<ssa_step_iteratort>> time_mapt;
218  time_mapt time_map;
219 
220  mp_integer current_time=0;
221 
222  ssa_step_iteratort last_step_to_keep = target.SSA_steps.end();
223  bool last_step_was_kept = false;
224 
225  // First sort the SSA steps by time, in the process dropping steps
226  // we definitely don't want to retain in the final trace:
227 
228  for(ssa_step_iteratort it = target.SSA_steps.begin();
229  it != target.SSA_steps.end();
230  it++)
231  {
232  if(
233  last_step_to_keep == target.SSA_steps.end() &&
234  is_last_step_to_keep(it, decision_procedure))
235  {
236  last_step_to_keep = it;
237  }
238 
239  const SSA_stept &SSA_step = *it;
240 
241  if(!decision_procedure.get(SSA_step.guard_handle).is_true())
242  continue;
243 
244  if(it->is_constraint() ||
245  it->is_spawn())
246  continue;
247  else if(it->is_atomic_begin())
248  {
249  // for atomic sections the timing can only be determined once we see
250  // a shared read or write (if there is none, the time will be
251  // reverted to the time before entering the atomic section); we thus
252  // use a temporary negative time slot to gather all events
253  current_time*=-1;
254  continue;
255  }
256  else if(it->is_shared_read() || it->is_shared_write() ||
257  it->is_atomic_end())
258  {
259  mp_integer time_before=current_time;
260 
261  if(it->is_shared_read() || it->is_shared_write())
262  {
263  // these are just used to get the time stamp -- the clock type is
264  // computed to be of the minimal necessary size, but we don't need to
265  // know it to get the value so just use typeless
266  exprt clock_value = decision_procedure.get(
268 
269  const auto cv = numeric_cast<mp_integer>(clock_value);
270  if(cv.has_value())
271  current_time = *cv;
272  else
273  current_time = 0;
274  }
275  else if(it->is_atomic_end() && current_time<0)
276  current_time*=-1;
277 
278  INVARIANT(current_time >= 0, "time keeping inconsistency");
279  // move any steps gathered in an atomic section
280 
281  if(time_before<0)
282  {
283  time_mapt::const_iterator time_before_steps_it =
284  time_map.find(time_before);
285 
286  if(time_before_steps_it != time_map.end())
287  {
288  std::vector<ssa_step_iteratort> &current_time_steps =
289  time_map[current_time];
290 
291  current_time_steps.insert(
292  current_time_steps.end(),
293  time_before_steps_it->second.begin(),
294  time_before_steps_it->second.end());
295 
296  time_map.erase(time_before_steps_it);
297  }
298  }
299 
300  continue;
301  }
302 
303  // drop PHI and GUARD assignments altogether
304  if(it->is_assignment() &&
305  (SSA_step.assignment_type==
307  SSA_step.assignment_type==
309  {
310  continue;
311  }
312 
313  if(it == last_step_to_keep)
314  {
315  last_step_was_kept = true;
316  }
317 
318  time_map[current_time].push_back(it);
319  }
320 
321  INVARIANT(
322  last_step_to_keep == target.SSA_steps.end() || last_step_was_kept,
323  "last step in SSA trace to keep must not be filtered out as a sync "
324  "instruction, not-taken branch, PHI node, or similar");
325 
326  // Now build the GOTO trace, ordered by time, then by SSA trace order.
327 
328  // produce the step numbers
329  unsigned step_nr = 0;
330 
331  for(const auto &time_and_ssa_steps : time_map)
332  {
333  for(const auto &ssa_step_it : time_and_ssa_steps.second)
334  {
335  const auto &SSA_step = *ssa_step_it;
336  goto_trace.steps.push_back(goto_trace_stept());
337  goto_trace_stept &goto_trace_step = goto_trace.steps.back();
338 
339  goto_trace_step.step_nr = ++step_nr;
340 
341  goto_trace_step.thread_nr = SSA_step.source.thread_nr;
342  goto_trace_step.pc = SSA_step.source.pc;
343  goto_trace_step.function_id = SSA_step.source.function_id;
344  if(SSA_step.is_assert())
345  {
346  goto_trace_step.comment = SSA_step.comment;
347  goto_trace_step.property_id = SSA_step.get_property_id();
348  }
349  goto_trace_step.type = SSA_step.type;
350  goto_trace_step.hidden = SSA_step.hidden;
351  goto_trace_step.format_string = SSA_step.format_string;
352  goto_trace_step.io_id = SSA_step.io_id;
353  goto_trace_step.formatted = SSA_step.formatted;
354  goto_trace_step.called_function = SSA_step.called_function;
355  goto_trace_step.function_arguments = SSA_step.converted_function_arguments;
356 
357  for(auto &arg : goto_trace_step.function_arguments)
358  arg = decision_procedure.get(arg);
359 
360  // update internal field for specific variables in the counterexample
361  update_internal_field(SSA_step, goto_trace_step, ns);
362 
363  goto_trace_step.assignment_type =
364  (SSA_step.is_assignment() &&
365  (SSA_step.assignment_type ==
367  SSA_step.assignment_type ==
371 
372  if(SSA_step.original_full_lhs.is_not_nil())
373  {
374  goto_trace_step.full_lhs = simplify_expr(
376  decision_procedure,
377  ns,
378  SSA_step.original_full_lhs,
379  SSA_step.ssa_full_lhs),
380  ns);
381  replace_nondet_in_type(goto_trace_step.full_lhs, decision_procedure);
382  }
383 
384  if(SSA_step.ssa_full_lhs.is_not_nil())
385  {
386  goto_trace_step.full_lhs_value =
387  decision_procedure.get(SSA_step.ssa_full_lhs);
388  simplify(goto_trace_step.full_lhs_value, ns);
390  goto_trace_step.full_lhs_value, decision_procedure);
391  }
392 
393  for(const auto &j : SSA_step.converted_io_args)
394  {
395  if(j.is_constant() || j.id() == ID_string_constant)
396  {
397  goto_trace_step.io_args.push_back(j);
398  }
399  else
400  {
401  exprt tmp = decision_procedure.get(j);
402  goto_trace_step.io_args.push_back(tmp);
403  }
404  }
405 
406  if(SSA_step.is_assert() || SSA_step.is_assume() || SSA_step.is_goto())
407  {
408  goto_trace_step.cond_expr = SSA_step.cond_expr;
409 
410  goto_trace_step.cond_value =
411  decision_procedure.get(SSA_step.cond_handle).is_true();
412  }
413 
414  if(ssa_step_it == last_step_to_keep)
415  return;
416  }
417  }
418 }
419 
421  const symex_target_equationt &target,
422  symex_target_equationt::SSA_stepst::const_iterator last_step_to_keep,
423  const decision_proceduret &decision_procedure,
424  const namespacet &ns,
425  goto_tracet &goto_trace)
426 {
427  const auto is_last_step_to_keep =
428  [last_step_to_keep](
429  symex_target_equationt::SSA_stepst::const_iterator it,
430  const decision_proceduret &) { return last_step_to_keep == it; };
431 
432  return build_goto_trace(
433  target, is_last_step_to_keep, decision_procedure, ns, goto_trace);
434 }
435 
437  symex_target_equationt::SSA_stepst::const_iterator step,
438  const decision_proceduret &decision_procedure)
439 {
440  return step->is_assert() &&
441  decision_procedure.get(step->cond_handle).is_false();
442 }
443 
445  const symex_target_equationt &target,
446  const decision_proceduret &decision_procedure,
447  const namespacet &ns,
448  goto_tracet &goto_trace)
449 {
451  target, is_failed_assertion_step, decision_procedure, ns, goto_trace);
452 }
decision_proceduret::get
virtual exprt get(const exprt &expr) const =0
Return expr with variables replaced by values from satisfying assignment if available.
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
update_internal_field
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....
Definition: build_goto_trace.cpp:146
goto_trace_stept::full_lhs_value
exprt full_lhs_value
Definition: goto_trace.h:132
goto_trace_stept::formatted
bool formatted
Definition: goto_trace.h:138
goto_trace_stept::comment
std::string comment
Definition: goto_trace.h:123
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
ssa_exprt::get_original_name
const irep_idt get_original_name() const
Definition: ssa_expr.h:49
build_goto_trace
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...
Definition: build_goto_trace.cpp:205
arith_tools.h
ssa_step_predicatet
std::function< bool(symex_target_equationt::SSA_stepst::const_iterator, const decision_proceduret &)> ssa_step_predicatet
Definition: build_goto_trace.h:48
typet
The type of an expression, extends irept.
Definition: type.h:28
SSA_stept
Single SSA step in the equation.
Definition: ssa_step.h:46
symex_targett::sourcet::pc
goto_programt::const_targett pc
Definition: symex_target.h:42
goto_trace_stept::assignment_typet::STATE
@ STATE
to_byte_extract_expr
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
Definition: byte_operators.h:57
goto_trace_stept::internal
bool internal
Definition: goto_trace.h:103
to_index_expr
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1478
to_if_expr
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2403
typet::has_subtype
bool has_subtype() const
Definition: type.h:82
decision_proceduret
Definition: decision_procedure.h:20
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
if_exprt
The trinary if-then-else operator.
Definition: std_expr.h:2322
symbol_exprt::typeless
static symbol_exprt typeless(const irep_idt &id)
Generate a symbol_exprt without a proper type.
Definition: std_expr.h:132
goto_trace_stept::type
typet type
Definition: goto_trace.h:97
SSA_stept::assignment_type
symex_targett::assignment_typet assignment_type
Definition: ssa_step.h:146
to_type_with_subtype
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:193
goto_tracet::steps
stepst steps
Definition: goto_trace.h:178
exprt
Base class for all expressions.
Definition: expr.h:55
is_failed_assertion_step
static bool is_failed_assertion_step(symex_target_equationt::SSA_stepst::const_iterator step, const decision_proceduret &decision_procedure)
Definition: build_goto_trace.cpp:436
set_internal_dynamic_object
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.
Definition: build_goto_trace.cpp:117
exprt::is_true
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:34
goto_trace_stept
Step of the trace of a GOTO program.
Definition: goto_trace.h:49
SSA_stept::source
symex_targett::sourcet source
Definition: ssa_step.h:49
goto_trace_stept::called_function
irep_idt called_function
Definition: goto_trace.h:141
partial_order_concurrencyt::rw_clock_id
static irep_idt rw_clock_id(event_it e, axiomt axiom=AX_PROPAGATION)
Build identifier for the read/write clock variable.
Definition: partial_order_concurrency.cpp:125
decision_procedure.h
replace_nondet_in_type
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.
Definition: build_goto_trace.cpp:183
if_exprt::false_case
exprt & false_case()
Definition: std_expr.h:2360
exprt::is_false
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:43
symex_targett::assignment_typet::VISIBLE_ACTUAL_PARAMETER
@ VISIBLE_ACTUAL_PARAMETER
array_typet::size
const exprt & size() const
Definition: std_types.h:800
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
namespacet::lookup
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:138
irept::is_not_nil
bool is_not_nil() const
Definition: irep.h:380
byte_operators.h
Expression classes for byte-level operators.
goto_trace_stept::typet::OUTPUT
@ OUTPUT
to_ssa_expr
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
Definition: ssa_expr.h:145
SSA_stept::ssa_lhs
ssa_exprt ssa_lhs
Definition: ssa_step.h:143
symex_targett::assignment_typet::HIDDEN_ACTUAL_PARAMETER
@ HIDDEN_ACTUAL_PARAMETER
byte_extract_exprt::op
exprt & op()
Definition: byte_operators.h:43
goto_trace_stept::cond_expr
exprt cond_expr
Definition: goto_trace.h:119
forall_operands
#define forall_operands(it, expr)
Definition: expr.h:20
member_exprt::struct_op
const exprt & struct_op() const
Definition: std_expr.h:2832
goto_trace_stept::step_nr
std::size_t step_nr
Number of the step in the trace.
Definition: goto_trace.h:53
goto_trace_stept::full_lhs
exprt full_lhs
Definition: goto_trace.h:126
goto_trace_stept::function_arguments
std::vector< exprt > function_arguments
Definition: goto_trace.h:144
goto_trace_stept::pc
goto_programt::const_targett pc
Definition: goto_trace.h:112
simplify
bool simplify(exprt &expr, const namespacet &ns)
Definition: simplify_expr.cpp:2926
simplify_expr
exprt simplify_expr(exprt src, const namespacet &ns)
Definition: simplify_expr.cpp:2931
index_exprt::index
exprt & index()
Definition: std_expr.h:1450
index_exprt::array
exprt & array()
Definition: std_expr.h:1440
symbol.h
Symbol table entry.
irept::id
const irep_idt & id() const
Definition: irep.h:396
goto_trace_stept::assignment_typet::ACTUAL_PARAMETER
@ ACTUAL_PARAMETER
goto_trace_stept::typet::INPUT
@ INPUT
unary_exprt::op
const exprt & op() const
Definition: std_expr.h:326
goto_trace_stept::thread_nr
unsigned thread_nr
Definition: goto_trace.h:115
symex_target_equationt
Inheriting the interface of symex_targett this class represents the SSA form of the input program as ...
Definition: symex_target_equation.h:33
simplify_expr.h
goto_trace_stept::property_id
irep_idt property_id
Definition: goto_trace.h:122
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
goto_trace_stept::cond_value
bool cond_value
Definition: goto_trace.h:118
symex_targett::assignment_typet::PHI
@ PHI
array_typet
Arrays with given size.
Definition: std_types.h:762
if_exprt::true_case
exprt & true_case()
Definition: std_expr.h:2350
build_full_lhs_rec
static exprt build_full_lhs_rec(const decision_proceduret &decision_procedure, const namespacet &ns, const exprt &src_original, const exprt &src_ssa)
Definition: build_goto_trace.cpp:27
goto_trace_stept::assignment_type
assignment_typet assignment_type
Definition: goto_trace.h:107
symbolt
Symbol table entry.
Definition: symbol.h:27
symex_target_equationt::SSA_steps
SSA_stepst SSA_steps
Definition: symex_target_equation.h:250
to_typecast_expr
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2051
solver
int solver(std::istream &in)
Definition: smt2_solver.cpp:407
SSA_stept::ssa_rhs
exprt ssa_rhs
Definition: ssa_step.h:145
goto_trace_stept::hidden
bool hidden
Definition: goto_trace.h:100
build_goto_trace.h
byte_extract_exprt
Expression of type type extracted from some object op starting at position offset (given in number of...
Definition: byte_operators.h:28
to_array_type
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:844
SSA_stept::guard_handle
exprt guard_handle
Definition: ssa_step.h:140
goto_trace_stept::format_string
irep_idt format_string
Definition: goto_trace.h:135
goto_functions.h
goto_tracet
Trace of a GOTO program.
Definition: goto_trace.h:174
symex_targett::assignment_typet::GUARD
@ GUARD
to_member_expr
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2886
exprt::operands
operandst & operands()
Definition: expr.h:94
goto_functionst::entry_point
static irep_idt entry_point()
Get the identifier of the entry point to a goto model.
Definition: goto_functions.h:92
index_exprt
Array index operator.
Definition: std_expr.h:1409
goto_trace_stept::io_id
irep_idt io_id
Definition: goto_trace.h:135
typecast_exprt
Semantic type conversion.
Definition: std_expr.h:2016
partial_order_concurrency.h
symex_targett::sourcet::function_id
irep_idt function_id
Definition: symex_target.h:39
goto_trace_stept::io_args
io_argst io_args
Definition: goto_trace.h:137
goto_trace_stept::function_id
irep_idt function_id
Definition: goto_trace.h:111
SSA_stept::is_function_call
bool is_function_call() const
Definition: ssa_step.h:92
irept::get_bool
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:58
validation_modet::INVARIANT
@ INVARIANT