CBMC
symex_main.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Symbolic Execution
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include <util/exception_utils.h>
13 #include <util/expr_iterator.h>
14 #include <util/expr_util.h>
15 #include <util/format.h>
16 #include <util/format_expr.h>
17 #include <util/invariant.h>
18 #include <util/magic.h>
19 #include <util/mathematical_expr.h>
20 #include <util/replace_symbol.h>
21 #include <util/std_expr.h>
22 
24 
25 #include "goto_symex.h"
26 #include "path_storage.h"
27 
28 #include <memory>
29 
31  : max_depth(options.get_unsigned_int_option("depth")),
32  doing_path_exploration(options.is_set("paths")),
33  allow_pointer_unsoundness(
34  options.get_bool_option("allow-pointer-unsoundness")),
35  constant_propagation(options.get_bool_option("propagation")),
36  self_loops_to_assumptions(
37  options.get_bool_option("self-loops-to-assumptions")),
38  simplify_opt(options.get_bool_option("simplify")),
39  unwinding_assertions(options.get_bool_option("unwinding-assertions")),
40  partial_loops(options.get_bool_option("partial-loops")),
41  run_validation_checks(options.get_bool_option("validate-ssa-equation")),
42  show_symex_steps(options.get_bool_option("show-goto-symex-steps")),
43  show_points_to_sets(options.get_bool_option("show-points-to-sets")),
44  max_field_sensitivity_array_size(
45  options.is_set("no-array-field-sensitivity")
46  ? 0
47  : options.is_set("max-field-sensitivity-array-size")
48  ? options.get_unsigned_int_option(
49  "max-field-sensitivity-array-size")
51  complexity_limits_active(
52  options.get_signed_int_option("symex-complexity-limit") > 0),
53  cache_dereferences{options.get_bool_option("symex-cache-dereferences")}
54 {
55 }
56 
60 static void pop_exited_loops(
62  std::vector<framet::active_loop_infot> &active_loops)
63 {
64  while(!active_loops.empty())
65  {
66  if(!active_loops.back().loop.contains(to))
67  active_loops.pop_back();
68  else
69  break;
70  }
71 }
72 
74  goto_symext::statet &state,
76  bool is_backwards_goto)
77 {
78  if(!state.call_stack().empty())
79  {
80  // initialize the loop counter of any loop we are newly entering
81  // upon this transition; we are entering a loop if
82  // 1. the transition from state.source.pc to "to" is not a backwards goto
83  // or
84  // 2. we are arriving from an outer loop
85 
86  // TODO: This should all be replaced by natural loop analysis.
87  // This is because the way we detect loops is pretty imprecise.
88 
89  framet &frame = state.call_stack().top();
90  const goto_programt::instructiont &instruction=*to;
91  for(const auto &i_e : instruction.incoming_edges)
92  {
93  if(
94  i_e->is_backwards_goto() && i_e->get_target() == to &&
95  (!is_backwards_goto ||
96  state.source.pc->location_number > i_e->location_number))
97  {
98  const auto loop_id =
100  auto &current_loop_info = frame.loop_iterations[loop_id];
101  current_loop_info.count = 0;
102 
103  // We've found a loop, put it on the stack and say it's our current
104  // active loop.
105  if(
106  frame.loops_info && frame.loops_info->loop_map.find(to) !=
107  frame.loops_info->loop_map.end())
108  {
109  frame.active_loops.emplace_back(frame.loops_info->loop_map[to]);
110  }
111  }
112  }
113 
114  // Only do this if we have active loop analysis going.
115  if(!frame.active_loops.empty())
116  {
117  // Otherwise if we find we're transitioning out of a loop, make sure
118  // to remove any loops we're not currently iterating over.
119 
120  // Match the do-while pattern.
121  if(
122  state.source.pc->is_backwards_goto() &&
123  state.source.pc->location_number < to->location_number)
124  {
125  pop_exited_loops(to, frame.active_loops);
126  }
127 
128  // Match for-each or while.
129  for(const auto &incoming_edge : state.source.pc->incoming_edges)
130  {
131  if(
132  incoming_edge->is_backwards_goto() &&
133  incoming_edge->location_number < to->location_number)
134  {
135  pop_exited_loops(to, frame.active_loops);
136  }
137  }
138  }
139  }
140 
141  state.source.pc=to;
142 }
143 
145 {
147  ++next;
148  symex_transition(state, next, false);
149 }
150 
152  const goto_programt::instructiont &instruction,
153  statet &state)
154 {
155  exprt condition = clean_expr(instruction.condition(), state, false);
156 
157  // First, push negations in and perhaps convert existential quantifiers into
158  // universals:
159  if(has_subexpr(condition, ID_exists) || has_subexpr(condition, ID_forall))
160  do_simplify(condition);
161 
162  // Second, L2-rename universal quantifiers:
163  if(has_subexpr(condition, ID_forall))
164  rewrite_quantifiers(condition, state);
165 
166  // now rename, enables propagation
167  exprt l2_condition = state.rename(std::move(condition), ns).get();
168 
169  // now try simplifier on it
170  do_simplify(l2_condition);
171 
172  std::string msg = id2string(instruction.source_location().get_comment());
173  if(msg.empty())
174  msg = "assertion";
175 
176  vcc(
177  l2_condition, instruction.source_location().get_property_id(), msg, state);
178 }
179 
181  const exprt &condition,
182  const irep_idt &property_id,
183  const std::string &msg,
184  statet &state)
185 {
186  state.total_vccs++;
188 
189  if(condition.is_true())
190  return;
191 
192  const exprt guarded_condition = state.guard.guard_expr(condition);
193 
194  state.remaining_vccs++;
196  state.guard.as_expr(), guarded_condition, property_id, msg, state.source);
197 }
198 
199 void goto_symext::symex_assume(statet &state, const exprt &cond)
200 {
201  exprt simplified_cond = clean_expr(cond, state, false);
202  simplified_cond = state.rename(std::move(simplified_cond), ns).get();
203  do_simplify(simplified_cond);
204 
205  // It would be better to call try_filter_value_sets after apply_condition,
206  // but it is not currently possible. See the comment at the beginning of
207  // \ref apply_goto_condition for more information.
208 
210  state, cond, state.value_set, &state.value_set, nullptr, ns);
211 
212  // apply_condition must come after rename because it might change the
213  // constant propagator and the value-set and we read from those in rename
214  state.apply_condition(simplified_cond, state, ns);
215 
216  symex_assume_l2(state, simplified_cond);
217 }
218 
219 void goto_symext::symex_assume_l2(statet &state, const exprt &cond)
220 {
221  if(cond.is_true())
222  return;
223 
224  if(cond.is_false())
225  state.reachable = false;
226 
227  // we are willing to re-write some quantified expressions
228  exprt rewritten_cond = cond;
229  if(has_subexpr(rewritten_cond, ID_exists))
230  rewrite_quantifiers(rewritten_cond, state);
231 
232  if(state.threads.size()==1)
233  {
234  exprt tmp = state.guard.guard_expr(rewritten_cond);
235  target.assumption(state.guard.as_expr(), tmp, state.source);
236  }
237  // symex_target_equationt::convert_assertions would fail to
238  // consider assumptions of threads that have a thread-id above that
239  // of the thread containing the assertion:
240  // T0 T1
241  // x=0; assume(x==1);
242  // assert(x!=42); x=42;
243  else
244  state.guard.add(rewritten_cond);
245 
246  if(state.atomic_section_id!=0 &&
247  state.guard.is_false())
248  symex_atomic_end(state);
249 }
250 
252 {
253  const bool is_assert = state.source.pc->is_assert();
254 
255  if(
256  (is_assert && expr.id() == ID_forall) ||
257  (!is_assert && expr.id() == ID_exists))
258  {
259  // for assertions e can rewrite "forall X. P" to "P", and
260  // for assumptions we can rewrite "exists X. P" to "P"
261  // we keep the quantified variable unique by means of L2 renaming
262  auto &quant_expr = to_quantifier_expr(expr);
263  symbol_exprt tmp0 =
264  to_symbol_expr(to_ssa_expr(quant_expr.symbol()).get_original_expr());
265  symex_decl(state, tmp0);
266  instruction_local_symbols.push_back(tmp0);
267  exprt tmp = quant_expr.where();
268  rewrite_quantifiers(tmp, state);
269  quant_expr.swap(tmp);
270  }
271  else if(expr.id() == ID_or || expr.id() == ID_and)
272  {
273  for(auto &op : expr.operands())
274  rewrite_quantifiers(op, state);
275  }
276 }
277 
278 static void
279 switch_to_thread(goto_symex_statet &state, const unsigned int thread_nb)
280 {
281  PRECONDITION(state.source.thread_nr < state.threads.size());
282  PRECONDITION(thread_nb < state.threads.size());
283 
284  // save PC
285  state.threads[state.source.thread_nr].pc = state.source.pc;
286  state.threads[state.source.thread_nr].atomic_section_id =
287  state.atomic_section_id;
288 
289  // get new PC
290  state.source.thread_nr = thread_nb;
291  state.source.pc = state.threads[thread_nb].pc;
292  state.source.function_id = state.threads[thread_nb].function_id;
293 
294  state.guard = state.threads[thread_nb].guard;
295  // A thread's initial state is certainly reachable:
296  state.reachable = true;
297 }
298 
300  statet &state, const get_goto_functiont &get_goto_function)
301 {
303 
304  _total_vccs = state.total_vccs;
306 
308  return;
309 
310  // is there another thread to execute?
311  if(state.call_stack().empty() &&
312  state.source.thread_nr+1<state.threads.size())
313  {
314  unsigned t=state.source.thread_nr+1;
315 #if 0
316  std::cout << "********* Now executing thread " << t << '\n';
317 #endif
318  switch_to_thread(state, t);
319  symex_transition(state, state.source.pc, false);
320  }
321 }
322 
324  statet &state,
325  const get_goto_functiont &get_goto_function)
326 {
327  // resets the namespace to only wrap a single symbol table, and does so upon
328  // destruction of an object of this type; instantiating the type is thus all
329  // that's needed to achieve a reset upon exiting this method
330  struct reset_namespacet
331  {
332  explicit reset_namespacet(namespacet &ns) : ns(ns)
333  {
334  }
335 
336  ~reset_namespacet()
337  {
338  // Get symbol table 1, the outer symbol table from the GOTO program
339  const symbol_table_baset &st = ns.get_symbol_table();
340  // Move a new namespace containing this symbol table over the top of the
341  // current one
342  ns = namespacet(st);
343  }
344 
345  namespacet &ns;
346  };
347 
348  // We'll be using ns during symbolic execution and it needs to know
349  // about the names minted in `state`, so make it point both to
350  // `state`'s symbol table and the symbol table of the original
351  // goto-program.
353 
354  // whichever way we exit this method, reset the namespace back to a sane state
355  // as state.symbol_table might go out of scope
356  reset_namespacet reset_ns(ns);
357 
358  PRECONDITION(state.call_stack().top().end_of_function->is_end_function());
359 
362  return state.symbol_table;
363 
364  while(!state.call_stack().empty())
365  {
366  state.has_saved_jump_target = false;
367  state.has_saved_next_instruction = false;
370  return state.symbol_table;
371  }
372 
373  // Clients may need to construct a namespace with both the names in
374  // the original goto-program and the names generated during symbolic
375  // execution, so return the names generated through symbolic execution
376  return state.symbol_table;
377 }
378 
380  const get_goto_functiont &get_goto_function,
381  const statet &saved_state,
382  symex_target_equationt *const saved_equation)
383 {
384  // saved_state contains a pointer to a symex_target_equationt that is
385  // almost certainly stale. This is because equations are owned by bmcts,
386  // and we construct a new bmct for every path that we execute. We're on a
387  // new path now, so the old bmct and the equation that it owned have now
388  // been deallocated. So, construct a new state from the old one, and make
389  // its equation member point to the (valid) equation passed as an argument.
390  statet state(saved_state, saved_equation);
391 
392  // Do NOT do the same initialization that `symex_with_state` does for a
393  // fresh state, as that would clobber the saved state's program counter
394  return symex_with_state(state, get_goto_function);
395 }
396 
397 std::unique_ptr<goto_symext::statet> goto_symext::initialize_entry_point_state(
398  const get_goto_functiont &get_goto_function)
399 {
400  const irep_idt entry_point_id = goto_functionst::entry_point();
401 
402  const goto_functionst::goto_functiont *start_function;
403  try
404  {
405  start_function = &get_goto_function(entry_point_id);
406  }
407  catch(const std::out_of_range &)
408  {
409  throw unsupported_operation_exceptiont("the program has no entry point");
410  }
411 
412  // Get our path_storage pointer because this state will live beyond
413  // this instance of goto_symext, so we can't take the reference directly.
414  auto *storage = &path_storage;
415 
416  // create and prepare the state
417  auto state = std::make_unique<statet>(
418  symex_targett::sourcet(entry_point_id, start_function->body),
422  [storage](const irep_idt &id) { return storage->get_unique_l2_index(id); });
423 
424  CHECK_RETURN(!state->threads.empty());
425  CHECK_RETURN(!state->call_stack().empty());
426 
428  std::prev(start_function->body.instructions.end());
429  state->call_stack().top().end_of_function = limit;
430  state->call_stack().top().calling_location.pc =
431  state->call_stack().top().end_of_function;
432  state->call_stack().top().hidden_function = start_function->is_hidden();
433 
434  state->symex_target = &target;
435 
436  state->run_validation_checks = symex_config.run_validation_checks;
437 
438  // initialize support analyses
439  auto emplace_safe_pointers_result =
440  path_storage.safe_pointers.emplace(entry_point_id, local_safe_pointerst{});
441  if(emplace_safe_pointers_result.second)
442  emplace_safe_pointers_result.first->second(start_function->body);
443 
445  entry_point_id, *start_function);
446  state->dirty = &path_storage.dirty;
447 
448  // Only enable loop analysis when complexity is enabled.
450  {
451  // Set initial loop analysis.
452  path_storage.add_function_loops(entry_point_id, start_function->body);
453  state->call_stack().top().loops_info =
454  path_storage.get_loop_analysis(entry_point_id);
455  }
456 
457  // make the first step onto the instruction pointed to by the initial program
458  // counter
459  symex_transition(*state, state->source.pc, false);
460 
461  return state;
462 }
463 
465  const get_goto_functiont &get_goto_function,
466  const shadow_memory_field_definitionst &fields)
467 {
469  // Initialize declared shadow memory fields
470  state->shadow_memory.fields = fields;
471 
472  return symex_with_state(*state, get_goto_function);
473 }
474 
476  const get_goto_functiont &get_goto_function,
477  symbol_table_baset &new_symbol_table,
478  const shadow_memory_field_definitionst &fields)
479 {
481  // Initialize declared shadow memory fields
482  state->shadow_memory.fields = fields;
483 
484  path_storaget::patht entry_point_start(target, *state);
485  entry_point_start.state.saved_target = state->source.pc;
486  entry_point_start.state.has_saved_next_instruction = true;
487 
488  path_storage.push(entry_point_start);
489 }
490 
493 {
494  return [&goto_model](
495  const irep_idt &id) -> const goto_functionst::goto_functiont & {
496  return goto_model.get_goto_function(id);
497  };
498 }
499 
502 {
503  log.status() << source.function_id
504  << " location number: " << source.pc->location_number;
505 
506  return log.status();
507 }
508 
510 {
511  // If we're showing the route, begin outputting debug info, and don't print
512  // instructions we don't run.
513 
514  // We also skip dead instructions as they don't add much to step-based
515  // debugging and if there's no code block at this point.
516  if(
518  state.source.pc->type() == DEAD ||
519  (state.source.pc->code().is_nil() &&
520  state.source.pc->type() != END_FUNCTION))
521  {
522  return;
523  }
524 
525  if(state.source.pc->code().is_not_nil())
526  {
527  auto guard_expression = state.guard.as_expr();
528  std::size_t size = 0;
529  for(auto it = guard_expression.depth_begin();
530  it != guard_expression.depth_end();
531  ++it)
532  {
533  size++;
534  }
535 
536  log.status() << "[Guard size: " << size << "] "
537  << format(state.source.pc->code());
538 
539  if(
540  state.source.pc->source_location().is_not_nil() &&
541  !state.source.pc->source_location().get_java_bytecode_index().empty())
542  {
543  log.status()
544  << " bytecode index: "
545  << state.source.pc->source_location().get_java_bytecode_index();
546  }
547 
548  log.status() << messaget::eom;
549  }
550 
551  // Print the method we're returning too.
552  const auto &call_stack = state.threads[state.source.thread_nr].call_stack;
553  if(state.source.pc->type() == END_FUNCTION)
554  {
555  log.status() << messaget::eom;
556 
557  if(!call_stack.empty())
558  {
559  log.status() << "Returning to: ";
560  print_callstack_entry(call_stack.back().calling_location)
561  << messaget::eom;
562  }
563 
564  log.status() << messaget::eom;
565  }
566 
567  // On a function call print the entire call stack.
568  if(state.source.pc->type() == FUNCTION_CALL)
569  {
570  log.status() << messaget::eom;
571 
572  if(!call_stack.empty())
573  {
574  log.status() << "Call stack:" << messaget::eom;
575 
576  for(auto &frame : call_stack)
577  {
578  print_callstack_entry(frame.calling_location) << messaget::eom;
579  }
580 
582 
583  // Add the method we're about to enter with no location number.
584  log.status() << format(state.source.pc->call_function()) << messaget::eom
585  << messaget::eom;
586  }
587  }
588 }
589 
592  const get_goto_functiont &get_goto_function,
593  statet &state)
594 {
595  // Print debug statements if they've been enabled.
596  print_symex_step(state);
599 }
600 
602  const get_goto_functiont &get_goto_function,
603  statet &state)
604 {
605  PRECONDITION(!state.threads.empty());
606  PRECONDITION(!state.call_stack().empty());
607 
608  const goto_programt::instructiont &instruction=*state.source.pc;
609 
611  merge_gotos(state);
612 
613  // depth exceeded?
614  if(state.depth > symex_config.max_depth)
615  {
616  // Rule out this path:
617  symex_assume_l2(state, false_exprt());
618  }
619  state.depth++;
620 
621  // actually do instruction
622  switch(instruction.type())
623  {
624  case SKIP:
625  if(state.reachable)
626  target.location(state.guard.as_expr(), state.source);
627  symex_transition(state);
628  break;
629 
630  case END_FUNCTION:
631  // do even if !state.reachable to clear out frame created
632  // in symex_start_thread
633  symex_end_of_function(state);
634  symex_transition(state);
635  break;
636 
637  case LOCATION:
638  if(state.reachable)
639  target.location(state.guard.as_expr(), state.source);
640  symex_transition(state);
641  break;
642 
643  case GOTO:
644  if(state.reachable)
645  symex_goto(state);
646  else
647  symex_unreachable_goto(state);
648  break;
649 
650  case ASSUME:
651  if(state.reachable)
652  symex_assume(state, instruction.condition());
653  symex_transition(state);
654  break;
655 
656  case ASSERT:
657  if(state.reachable && !ignore_assertions)
658  symex_assert(instruction, state);
659  symex_transition(state);
660  break;
661 
662  case SET_RETURN_VALUE:
663  if(state.reachable)
664  symex_set_return_value(state, instruction.return_value());
665  symex_transition(state);
666  break;
667 
668  case ASSIGN:
669  if(state.reachable)
670  symex_assign(state, instruction.assign_lhs(), instruction.assign_rhs());
671 
672  symex_transition(state);
673  break;
674 
675  case FUNCTION_CALL:
676  if(state.reachable)
677  symex_function_call(get_goto_function, state, instruction);
678  else
679  symex_transition(state);
680  break;
681 
682  case OTHER:
683  if(state.reachable)
684  symex_other(state);
685  symex_transition(state);
686  break;
687 
688  case DECL:
689  if(state.reachable)
690  symex_decl(state);
691  symex_transition(state);
692  break;
693 
694  case DEAD:
695  symex_dead(state);
696  symex_transition(state);
697  break;
698 
699  case START_THREAD:
700  symex_start_thread(state);
701  symex_transition(state);
702  break;
703 
704  case END_THREAD:
705  // behaves like assume(0);
706  if(state.reachable)
707  state.reachable = false;
708  symex_transition(state);
709  break;
710 
711  case ATOMIC_BEGIN:
712  symex_atomic_begin(state);
713  symex_transition(state);
714  break;
715 
716  case ATOMIC_END:
717  symex_atomic_end(state);
718  symex_transition(state);
719  break;
720 
721  case CATCH:
722  symex_catch(state);
723  symex_transition(state);
724  break;
725 
726  case THROW:
727  symex_throw(state);
728  symex_transition(state);
729  break;
730 
731  case NO_INSTRUCTION_TYPE:
732  throw unsupported_operation_exceptiont("symex got NO_INSTRUCTION");
733 
734  case INCOMPLETE_GOTO:
735  DATA_INVARIANT(false, "symex got unexpected instruction type");
736  }
737 
738  complexity_violationt complexity_result =
740  if(complexity_result != complexity_violationt::NONE)
741  complexity_module.run_transformations(complexity_result, state);
742 }
743 
745 {
746  for(const auto &symbol_expr : instruction_local_symbols)
747  symex_dead(state, symbol_expr);
749 }
750 
756 static std::optional<symbol_exprt>
758 {
759  std::optional<symbol_exprt> return_value;
760  for(auto it = expr.depth_cbegin(); it != expr.depth_cend(); ++it)
761  {
762  const symbol_exprt *symbol_expr = expr_try_dynamic_cast<symbol_exprt>(*it);
763  if(symbol_expr && can_cast_type<pointer_typet>(symbol_expr->type()))
764  {
765  // If we already have a potential return value, check if it is the same
766  // symbol, and return an empty std::optional if not
767  if(return_value && *symbol_expr != *return_value)
768  {
769  return {};
770  }
771  return_value = *symbol_expr;
772  }
773  }
774 
775  // Either expr contains no pointer-typed symbols or it contains one unique
776  // pointer-typed symbol, possibly repeated multiple times
777  return return_value;
778 }
779 
781  goto_symex_statet &state,
782  exprt condition,
783  const value_sett &original_value_set,
784  value_sett *jump_taken_value_set,
785  value_sett *jump_not_taken_value_set,
786  const namespacet &ns)
787 {
788  condition = state.rename<L1>(std::move(condition), ns).get();
789 
790  std::optional<symbol_exprt> symbol_expr =
792 
793  if(!symbol_expr)
794  {
795  return;
796  }
797 
798  const pointer_typet &symbol_type = to_pointer_type(symbol_expr->type());
799 
800  const std::vector<exprt> value_set_elements =
801  original_value_set.get_value_set(*symbol_expr, ns);
802 
803  std::unordered_set<exprt, irep_hash> erase_from_jump_taken_value_set;
804  std::unordered_set<exprt, irep_hash> erase_from_jump_not_taken_value_set;
805  erase_from_jump_taken_value_set.reserve(value_set_elements.size());
806  erase_from_jump_not_taken_value_set.reserve(value_set_elements.size());
807 
808  // Try evaluating the condition with the symbol replaced by a pointer to each
809  // one of its possible values in turn. If that leads to a true for some
810  // value_set_element then we can delete it from the value set that will be
811  // used if the condition is false, and vice versa.
812  for(const exprt &value_set_element : value_set_elements)
813  {
814  if(
815  value_set_element.id() == ID_unknown ||
816  value_set_element.id() == ID_invalid)
817  {
818  continue;
819  }
820 
821  const bool exclude_null_derefs = false;
823  value_set_element, exclude_null_derefs, language_mode))
824  {
825  continue;
826  }
827 
830  value_set_element, *symbol_expr, ns);
831 
832  if(value.pointer.is_nil())
833  continue;
834 
835  exprt modified_condition(condition);
836 
837  address_of_aware_replace_symbolt replace_symbol{};
838  replace_symbol.insert(*symbol_expr, value.pointer);
839  replace_symbol(modified_condition);
840 
841  // This do_simplify() is needed for the following reason: if `condition` is
842  // `*p == a` and we replace `p` with `&a` then we get `*&a == a`. Suppose
843  // our constant propagation knows that `a` is `1`. Without this call to
844  // do_simplify(), state.rename() turns this into `*&a == 1` (because
845  // rename() doesn't do constant propagation inside addresses), which
846  // do_simplify() turns into `a == 1`, which cannot be evaluated as true
847  // without another round of constant propagation.
848  // It would be sufficient to replace this call to do_simplify() with
849  // something that just replaces `*&x` with `x` whenever it finds it.
850  do_simplify(modified_condition);
851 
852  state.record_events.push(false);
853  modified_condition = state.rename(std::move(modified_condition), ns).get();
854  state.record_events.pop();
855 
856  do_simplify(modified_condition);
857 
858  if(jump_taken_value_set && modified_condition.is_false())
859  {
860  erase_from_jump_taken_value_set.insert(value_set_element);
861  }
862  else if(jump_not_taken_value_set && modified_condition.is_true())
863  {
864  erase_from_jump_not_taken_value_set.insert(value_set_element);
865  }
866  }
867  if(jump_taken_value_set && !erase_from_jump_taken_value_set.empty())
868  {
869  auto entry_index = jump_taken_value_set->get_index_of_symbol(
870  symbol_expr->get_identifier(), symbol_type, "", ns);
871  jump_taken_value_set->erase_values_from_entry(
872  *entry_index, erase_from_jump_taken_value_set);
873  }
874  if(jump_not_taken_value_set && !erase_from_jump_not_taken_value_set.empty())
875  {
876  auto entry_index = jump_not_taken_value_set->get_index_of_symbol(
877  symbol_expr->get_identifier(), symbol_type, "", ns);
878  jump_not_taken_value_set->erase_values_from_entry(
879  *entry_index, erase_from_jump_not_taken_value_set);
880  }
881 }
Abstract interface to eager or lazy GOTO models.
virtual const goto_functionst::goto_functiont & get_goto_function(const irep_idt &id)=0
Get a GOTO function by name, or throw if no such function exists.
Replace symbols with constants while maintaining syntactically valid expressions.
framet & top()
Definition: call_stack.h:17
complexity_violationt check_complexity(goto_symex_statet &state)
Checks the passed-in state to see if its become too complex for us to deal with, and if so set its gu...
void run_transformations(complexity_violationt complexity_violation, goto_symex_statet &current_state)
Runs a suite of transformations on the state and symex executable, performing whatever transformation...
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
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:27
const_depth_iteratort depth_cend() const
Definition: expr.cpp:257
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:34
typet & type()
Return the type of the expression.
Definition: expr.h:84
const_depth_iteratort depth_cbegin() const
Definition: expr.cpp:255
operandst & operands()
Definition: expr.h:94
The Boolean constant false.
Definition: std_expr.h:3077
Stack frames – these are used for function calls and for exceptions.
Definition: solver_types.h:41
std::vector< active_loop_infot > active_loops
Definition: frame.h:75
std::unordered_map< irep_idt, loop_infot > loop_iterations
Definition: frame.h:77
goto_programt::const_targett end_of_function
Definition: frame.h:37
std::shared_ptr< lexical_loopst > loops_info
Definition: frame.h:74
::goto_functiont goto_functiont
static irep_idt entry_point()
Get the identifier of the entry point to a goto model.
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:181
const exprt & condition() const
Get the condition of gotos, assume, assert.
Definition: goto_program.h:366
const exprt & return_value() const
Get the return value of a SET_RETURN_VALUE instruction.
Definition: goto_program.h:258
const exprt & assign_rhs() const
Get the rhs of the assignment for ASSIGN.
Definition: goto_program.h:214
std::set< targett, target_less_than > incoming_edges
Definition: goto_program.h:450
const source_locationt & source_location() const
Definition: goto_program.h:333
const exprt & assign_lhs() const
Get the lhs of the assignment for ASSIGN.
Definition: goto_program.h:200
goto_program_instruction_typet type() const
What kind of instruction?
Definition: goto_program.h:344
static irep_idt loop_id(const irep_idt &function_id, const instructiont &instruction)
Human-readable loop name.
Definition: goto_program.h:792
instructionst::const_iterator const_targett
Definition: goto_program.h:615
guardt guard
Definition: goto_state.h:58
unsigned depth
Distance from entry.
Definition: goto_state.h:35
bool reachable
Is this code reachable? If not we can take shortcuts such as not entering function calls,...
Definition: goto_state.h:62
void apply_condition(const exprt &condition, const goto_symex_statet &previous_state, const namespacet &ns)
Given a condition that must hold on this path, propagate as much knowledge as possible.
Definition: goto_state.cpp:43
unsigned atomic_section_id
Threads.
Definition: goto_state.h:76
value_sett value_set
Uses level 1 names, and is used to do dereferencing.
Definition: goto_state.h:51
Central data structure: state.
goto_programt::const_targett saved_target
std::stack< bool > record_events
call_stackt & call_stack()
renamedt< exprt, level > rename(exprt expr, const namespacet &ns)
Rewrites symbol expressions in exprt, applying a suffix to each symbol reflecting its most recent ver...
symbol_tablet symbol_table
contains symbols that are minted during symbolic execution, such as dynamically created objects etc.
symex_targett::sourcet source
bool has_saved_jump_target
This state is saved, with the PC pointing to the target of a GOTO.
std::vector< threadt > threads
bool has_saved_next_instruction
This state is saved, with the PC pointing to the next instruction of a GOTO.
void try_filter_value_sets(goto_symex_statet &state, exprt condition, const value_sett &original_value_set, value_sett *jump_taken_value_set, value_sett *jump_not_taken_value_set, const namespacet &ns)
Try to filter value sets based on whether possible values of a pointer-typed symbol make the conditio...
Definition: symex_main.cpp:780
virtual symbol_tablet symex_with_state(statet &state, const get_goto_functiont &get_goto_functions)
Symbolically execute the entire program starting from entry point.
Definition: symex_main.cpp:323
void rewrite_quantifiers(exprt &, statet &)
Definition: symex_main.cpp:251
virtual void symex_assume(statet &state, const exprt &cond)
Symbolically execute an ASSUME instruction or simulate such an execution for a synthetic assumption.
Definition: symex_main.cpp:199
void symex_threaded_step(statet &state, const get_goto_functiont &get_goto_function)
Invokes symex_step and verifies whether additional threads can be executed.
Definition: symex_main.cpp:299
void symex_unreachable_goto(statet &state)
Symbolically execute a GOTO instruction in the context of unreachable code.
Definition: symex_goto.cpp:544
complexity_limitert complexity_module
Definition: goto_symex.h:836
virtual void symex_atomic_begin(statet &state)
Symbolically execute an ATOMIC_BEGIN instruction.
const symbol_table_baset & outer_symbol_table
The symbol table associated with the goto-program being executed.
Definition: goto_symex.h:249
irep_idt language_mode
language_mode: ID_java, ID_C or another language identifier if we know the source language in use,...
Definition: goto_symex.h:241
void symex_set_return_value(statet &state, const exprt &return_value)
Symbolically execute a SET_RETURN_VALUE instruction.
bool ignore_assertions
If this flag is set to true then assertions will be temporarily ignored by the symbolic executions.
Definition: goto_symex.h:171
static get_goto_functiont get_goto_function(abstract_goto_modelt &goto_model)
Return a function to get/load a goto function from the given goto model Create a default delegate to ...
Definition: symex_main.cpp:492
virtual void symex_step(const get_goto_functiont &get_goto_function, statet &state)
Called for each step in the symbolic execution This calls print_symex_step to print symex's current i...
Definition: symex_main.cpp:591
virtual void symex_goto(statet &state)
Symbolically execute a GOTO instruction.
Definition: symex_goto.cpp:230
virtual void symex_decl(statet &state)
Symbolically execute a DECL instruction.
Definition: symex_decl.cpp:18
void symex_catch(statet &state)
Symbolically execute a CATCH instruction.
Definition: symex_catch.cpp:14
path_storaget & path_storage
Symbolic execution paths to be resumed later.
Definition: goto_symex.h:810
std::unique_ptr< statet > initialize_entry_point_state(const get_goto_functiont &get_goto_function)
Initialize the symbolic execution and the given state with the beginning of the entry point function.
Definition: symex_main.cpp:397
unsigned _total_vccs
Definition: goto_symex.h:833
symex_target_equationt & target
The equation that this execution is building up.
Definition: goto_symex.h:266
guard_managert & guard_manager
Used to create guards.
Definition: goto_symex.h:263
virtual symbol_tablet resume_symex_from_saved_state(const get_goto_functiont &get_goto_function, const statet &saved_state, symex_target_equationt *saved_equation)
Performs symbolic execution using a state and equation that have already been used to symbolically ex...
Definition: symex_main.cpp:379
void symex_assert(const goto_programt::instructiont &, statet &)
Definition: symex_main.cpp:151
exprt clean_expr(exprt expr, statet &state, bool write)
Clean up an expression.
virtual void symex_dead(statet &state)
Symbolically execute a DEAD instruction.
Definition: symex_dead.cpp:16
std::size_t path_segment_vccs
Number of VCCs generated during the run of this goto_symext object.
Definition: goto_symex.h:822
virtual void symex_start_thread(statet &state)
Symbolically execute a START_THREAD instruction.
virtual symbol_tablet symex_from_entry_point_of(const get_goto_functiont &get_goto_function, const shadow_memory_field_definitionst &fields)
Symbolically execute the entire program starting from entry point.
Definition: symex_main.cpp:464
namespacet ns
Initialized just before symbolic execution begins, to point to both outer_symbol_table and the symbol...
Definition: goto_symex.h:258
virtual void vcc(const exprt &cond, const irep_idt &property_id, const std::string &msg, statet &state)
Symbolically execute a verification condition (assertion).
Definition: symex_main.cpp:180
void kill_instruction_local_symbols(statet &state)
Kills any variables in instruction_local_symbols (these are currently always let-bound variables defi...
Definition: symex_main.cpp:744
virtual void symex_end_of_function(statet &)
Symbolically execute a END_FUNCTION instruction.
void symex_assign(statet &state, const exprt &lhs, const exprt &rhs)
Symbolically execute an ASSIGN instruction or simulate such an execution for a synthetic assignment.
Definition: goto_symex.cpp:38
void print_symex_step(statet &state)
Prints the route of symex as it walks through the code.
Definition: symex_main.cpp:509
void symex_throw(statet &state)
Symbolically execute a THROW instruction.
Definition: symex_throw.cpp:14
virtual void do_simplify(exprt &expr)
Definition: goto_symex.cpp:32
unsigned _remaining_vccs
Definition: goto_symex.h:833
virtual void symex_other(statet &state)
Symbolically execute an OTHER instruction.
Definition: symex_other.cpp:79
std::function< const goto_functionst::goto_functiont &(const irep_idt &)> get_goto_functiont
The type of delegate functions that retrieve a goto_functiont for a particular function identifier.
Definition: goto_symex.h:93
messaget log
The messaget to write log messages to.
Definition: goto_symex.h:278
const symex_configt symex_config
The configuration to use for this symbolic execution.
Definition: goto_symex.h:185
bool should_pause_symex
Set when states are pushed onto the workqueue If this flag is set at the end of a symbolic execution ...
Definition: goto_symex.h:167
void symex_assume_l2(statet &, const exprt &cond)
Definition: symex_main.cpp:219
void merge_gotos(statet &state)
Merge all branches joining at the current program point.
Definition: symex_goto.cpp:623
messaget::mstreamt & print_callstack_entry(const symex_targett::sourcet &target)
Definition: symex_main.cpp:501
std::vector< symbol_exprt > instruction_local_symbols
Variables that should be killed at the end of the current symex_step invocation.
Definition: goto_symex.h:275
virtual void symex_atomic_end(statet &state)
Symbolically execute an ATOMIC_END instruction.
virtual void symex_function_call(const get_goto_functiont &get_goto_function, statet &state, const goto_programt::instructiont &instruction)
Symbolically execute a FUNCTION_CALL instruction.
void execute_next_instruction(const get_goto_functiont &get_goto_function, statet &state)
Executes the instruction state.source.pc Case-switches over the type of the instruction being execute...
Definition: symex_main.cpp:601
virtual void initialize_path_storage_from_entry_point_of(const get_goto_functiont &get_goto_function, symbol_table_baset &new_symbol_table, const shadow_memory_field_definitionst &fields)
Puts the initial state of the entry point function into the path storage.
Definition: symex_main.cpp:475
void add(const exprt &expr)
Definition: guard_expr.cpp:38
exprt as_expr() const
Definition: guard_expr.h:46
bool is_false() const
Definition: guard_expr.h:65
exprt guard_expr(exprt expr) const
Return guard => dest or a simplified variant thereof if either guard or dest are trivial.
Definition: guard_expr.cpp:18
void populate_dirty_for_function(const irep_idt &id, const goto_functionst::goto_functiont &function)
Analyse the given function with dirtyt if it hasn't been seen before.
Definition: dirty.cpp:112
const irep_idt & id() const
Definition: irep.h:388
bool is_nil() const
Definition: irep.h:368
A very simple, cheap analysis to determine when dereference operations are trivially guarded by a che...
mstreamt & status() const
Definition: message.h:406
static eomt eom
Definition: message.h:289
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
const symbol_table_baset & get_symbol_table() const
Return first symbol table registered with the namespace.
Definition: namespace.h:126
incremental_dirtyt dirty
Local variables are considered 'dirty' if they've had an address taken and therefore may be referred ...
Definition: path_storage.h:116
std::shared_ptr< lexical_loopst > get_loop_analysis(const irep_idt &function_id)
Definition: path_storage.h:131
std::unordered_map< irep_idt, local_safe_pointerst > safe_pointers
Map function identifiers to local_safe_pointerst instances.
Definition: path_storage.h:100
virtual void push(const patht &)=0
Add a path to resume to the storage.
void add_function_loops(const irep_idt &identifier, const goto_programt &body)
Generates a loop analysis for the instructions in goto_programt and keys it against function ID.
Definition: path_storage.h:120
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
Definition: pointer_expr.h:24
The shadow memory field definitions.
const irep_idt & get_property_id() const
const irep_idt & get_comment() const
const exprt & get_original_expr() const
Definition: ssa_expr.h:33
Expression to hold a symbol (variable)
Definition: std_expr.h:131
The symbol table base class interface.
The symbol table.
Definition: symbol_table.h:14
Inheriting the interface of symex_targett this class represents the SSA form of the input program as ...
virtual void assertion(const exprt &guard, const exprt &cond, const irep_idt &property_id, const std::string &msg, const sourcet &source)
Record an assertion.
virtual void assumption(const exprt &guard, const exprt &cond, const sourcet &source)
Record an assumption.
virtual void location(const exprt &guard, const sourcet &source)
Record a location.
void insert(const symbol_exprt &old_expr, const exprt &new_expr)
Thrown when we encounter an instruction, parameters to an instruction etc.
Return value for build_reference_to; see that method for documentation.
static valuet build_reference_to(const exprt &what, const exprt &pointer, const namespacet &ns)
static bool should_ignore_value(const exprt &what, bool exclude_null_derefs, const irep_idt &language_mode)
Determine whether possible alias what should be ignored when replacing a pointer by its referees.
State type in value_set_domaint, used in value-set analysis and goto-symex.
Definition: value_set.h:44
std::vector< exprt > get_value_set(exprt expr, const namespacet &ns) const
Gets values pointed to by expr, including following dereference operators (i.e.
Definition: value_set.cpp:390
void erase_values_from_entry(const irep_idt &index, const std::unordered_set< exprt, irep_hash > &values_to_erase)
Update the entry stored at index by erasing any values listed in values_to_erase.
Definition: value_set.cpp:1986
std::optional< irep_idt > get_index_of_symbol(irep_idt identifier, const typet &type, const std::string &suffix, const namespacet &ns) const
Get the index of the symbol and suffix.
Definition: value_set.cpp:451
complexity_violationt
What sort of symex-complexity violation has taken place.
Forward depth-first search iterators These iterators' copy operations are expensive,...
bool has_subexpr(const exprt &expr, const std::function< bool(const exprt &)> &pred)
returns true if the expression has a subexpression that satisfies pred
Definition: expr_util.cpp:115
Deprecated expression utility functions.
static format_containert< T > format(const T &o)
Definition: format.h:37
@ FUNCTION_CALL
Definition: goto_program.h:49
@ ATOMIC_END
Definition: goto_program.h:44
@ DEAD
Definition: goto_program.h:48
@ END_FUNCTION
Definition: goto_program.h:42
@ ASSIGN
Definition: goto_program.h:46
@ ASSERT
Definition: goto_program.h:36
@ SET_RETURN_VALUE
Definition: goto_program.h:45
@ ATOMIC_BEGIN
Definition: goto_program.h:43
@ CATCH
Definition: goto_program.h:51
@ END_THREAD
Definition: goto_program.h:40
@ SKIP
Definition: goto_program.h:38
@ NO_INSTRUCTION_TYPE
Definition: goto_program.h:33
@ START_THREAD
Definition: goto_program.h:39
@ THROW
Definition: goto_program.h:50
@ DECL
Definition: goto_program.h:47
@ OTHER
Definition: goto_program.h:37
@ GOTO
Definition: goto_program.h:34
@ INCOMPLETE_GOTO
Definition: goto_program.h:52
Symbolic Execution.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
Magic numbers used throughout the codebase.
constexpr std::size_t DEFAULT_MAX_FIELD_SENSITIVITY_ARRAY_SIZE
Limit the size of arrays for which field_sensitivity gets applied.
Definition: magic.h:21
API to expression classes for 'mathematical' expressions.
const quantifier_exprt & to_quantifier_expr(const exprt &expr)
Cast an exprt to a quantifier_exprt.
Storage of symbolic execution paths to resume.
bool can_cast_type< pointer_typet >(const typet &type)
Check whether a reference to a typet is a pointer_typet.
Definition: pointer_expr.h:80
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
@ L1
Definition: renamed.h:24
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
Definition: ssa_expr.h:145
API to expression classes.
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
Information saved at a conditional goto to resume execution.
Definition: path_storage.h:42
goto_symex_statet state
Definition: path_storage.h:44
bool complexity_limits_active
Whether this run of symex is under complexity limits.
Definition: symex_config.h:54
unsigned max_depth
The maximum depth to take the execution to.
Definition: symex_config.h:23
std::size_t max_field_sensitivity_array_size
Maximum sizes for which field sensitivity will be applied to array cells.
Definition: symex_config.h:50
bool run_validation_checks
Should the additional validation checks be run? If this flag is set the checks for renaming (both lev...
Definition: symex_config.h:42
bool show_symex_steps
Prints out the path that symex is actively taking during execution, includes diagnostic information a...
Definition: symex_config.h:46
symex_configt(const optionst &options)
Construct a symex_configt using options specified in an optionst.
Definition: symex_main.cpp:30
bool doing_path_exploration
Definition: symex_config.h:25
Identifies source in the context of symbolic execution.
Definition: symex_target.h:37
goto_programt::const_targett pc
Definition: symex_target.h:42
void symex_transition(goto_symext::statet &state, goto_programt::const_targett to, bool is_backwards_goto)
Definition: symex_main.cpp:73
static void switch_to_thread(goto_symex_statet &state, const unsigned int thread_nb)
Definition: symex_main.cpp:279
static void pop_exited_loops(const goto_programt::const_targett &to, std::vector< framet::active_loop_infot > &active_loops)
If 'to' is not an instruction in our currently top-most active loop, pop and re-check until we find a...
Definition: symex_main.cpp:60
static std::optional< symbol_exprt > find_unique_pointer_typed_symbol(const exprt &expr)
Check if an expression only contains one unique symbol (possibly repeated multiple times)
Definition: symex_main.cpp:757
Pointer Dereferencing.