CBMC
goto_program.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Program Transformation
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "goto_program.h"
13 
14 #include <util/expr_iterator.h>
15 #include <util/find_symbols.h>
16 #include <util/format_expr.h>
17 #include <util/format_type.h>
18 #include <util/invariant.h>
19 #include <util/namespace.h>
20 #include <util/pointer_expr.h>
21 #include <util/std_code.h>
22 #include <util/std_expr.h>
23 #include <util/symbol.h>
24 #include <util/validate.h>
25 
26 #include <langapi/language_util.h>
27 
28 #include "validate_code.h"
29 
30 #include <iomanip>
31 #include <map>
32 
34  const code_gotot &_code,
35  const source_locationt &l)
36 {
37  return instructiont(_code, l, INCOMPLETE_GOTO, true_exprt(), {});
38 }
39 
49 std::ostream &goto_programt::instructiont::output(std::ostream &out) const
50 {
51  out << " // " << location_number << " ";
52 
53  if(!source_location().is_nil())
54  out << source_location().as_string();
55  else
56  out << "no location";
57 
58  out << "\n";
59 
60  if(!labels.empty())
61  {
62  out << " // Labels:";
63  for(const auto &label : labels)
64  out << " " << label;
65 
66  out << '\n';
67  }
68 
69  if(is_target())
70  out << std::setw(6) << target_number << ": ";
71  else
72  out << " ";
73 
74  switch(type())
75  {
77  out << "NO INSTRUCTION TYPE SET" << '\n';
78  break;
79 
80  case GOTO:
81  case INCOMPLETE_GOTO:
82  if(!condition().is_true())
83  {
84  out << "IF " << format(condition()) << " THEN ";
85  }
86 
87  out << "GOTO ";
88 
89  if(is_incomplete_goto())
90  {
91  out << "(incomplete)";
92  }
93  else
94  {
95  for(auto gt_it = targets.begin(); gt_it != targets.end(); gt_it++)
96  {
97  if(gt_it != targets.begin())
98  out << ", ";
99  out << (*gt_it)->target_number;
100  }
101  }
102 
103  out << '\n';
104  break;
105 
106  case OTHER:
107  if(get_other().id() == ID_code)
108  {
109  const auto &code = get_other();
110  if(code.get_statement() == ID_array_copy)
111  {
112  out << "ARRAY_COPY " << format(code.op0()) << ' ' << format(code.op1())
113  << '\n';
114  break;
115  }
116  else if(code.get_statement() == ID_array_replace)
117  {
118  out << "ARRAY_REPLACE " << format(code.op0()) << ' '
119  << format(code.op1()) << '\n';
120  break;
121  }
122  else if(code.get_statement() == ID_array_set)
123  {
124  out << "ARRAY_SET " << format(code.op0()) << ' ' << format(code.op1())
125  << '\n';
126  break;
127  }
128  else if(code.get_statement() == ID_expression)
129  {
130  out << "EXPRESSION " << format(code.op0()) << '\n';
131  break;
132  }
133  else if(code.get_statement() == ID_havoc_object)
134  {
135  out << "HAVOC_OBJECT " << format(code.op0()) << '\n';
136  break;
137  }
138  else if(code.get_statement() == ID_fence)
139  {
140  out << "FENCE";
141  if(code.get_bool(ID_WWfence))
142  out << " WW";
143  if(code.get_bool(ID_RRfence))
144  out << " RR";
145  if(code.get_bool(ID_RWfence))
146  out << " RW";
147  if(code.get_bool(ID_WRfence))
148  out << " WR";
149  out << '\n';
150  break;
151  }
152  else if(code.get_statement() == ID_input)
153  {
154  out << "INPUT";
155  for(const auto &op : code.operands())
156  out << ' ' << format(op);
157  out << '\n';
158  break;
159  }
160  else if(code.get_statement() == ID_output)
161  {
162  out << "OUTPUT " << format(code.op0()) << '\n';
163  break;
164  }
165  // fallthrough
166  }
167 
168  out << "OTHER " << format(get_other()) << '\n';
169  break;
170 
171  case SET_RETURN_VALUE:
172  out << "SET RETURN VALUE " << format(return_value()) << '\n';
173  break;
174 
175  case DECL:
176  out << "DECL " << format(decl_symbol()) << " : "
177  << format(decl_symbol().type()) << '\n';
178  break;
179 
180  case DEAD:
181  out << "DEAD " << format(dead_symbol()) << '\n';
182  break;
183 
184  case FUNCTION_CALL:
185  out << "CALL ";
186  {
187  if(call_lhs().is_not_nil())
188  out << format(call_lhs()) << " := ";
189  out << format(call_function());
190  out << '(';
191  bool first = true;
192  for(const auto &argument : call_arguments())
193  {
194  if(first)
195  first = false;
196  else
197  out << ", ";
198  out << format(argument);
199  }
200  out << ')';
201  out << '\n';
202  }
203  break;
204 
205  case ASSIGN:
206  out << "ASSIGN " << format(assign_lhs()) << " := " << format(assign_rhs())
207  << '\n';
208  break;
209 
210  case ASSUME:
211  case ASSERT:
212  if(is_assume())
213  out << "ASSUME ";
214  else
215  out << "ASSERT ";
216 
217  {
218  out << format(condition());
219 
221  if(!comment.empty())
222  out << " // " << comment;
223  }
224 
225  out << '\n';
226  break;
227 
228  case SKIP:
229  out << "SKIP" << '\n';
230  break;
231 
232  case END_FUNCTION:
233  out << "END_FUNCTION" << '\n';
234  break;
235 
236  case LOCATION:
237  out << "LOCATION" << '\n';
238  break;
239 
240  case THROW:
241  out << "THROW";
242 
243  {
244  const irept::subt &exception_list =
245  code().find(ID_exception_list).get_sub();
246 
247  for(const auto &ex : exception_list)
248  out << " " << ex.id();
249  }
250 
251  if(code().operands().size() == 1)
252  out << ": " << format(code().op0());
253 
254  out << '\n';
255  break;
256 
257  case CATCH:
258  {
259  if(code().get_statement() == ID_exception_landingpad)
260  {
261  const auto &landingpad = to_code_landingpad(code());
262  out << "EXCEPTION LANDING PAD (" << format(landingpad.catch_expr().type())
263  << ' ' << format(landingpad.catch_expr()) << ")";
264  }
265  else if(code().get_statement() == ID_push_catch)
266  {
267  out << "CATCH-PUSH ";
268 
269  unsigned i=0;
270  const irept::subt &exception_list =
271  code().find(ID_exception_list).get_sub();
273  targets.size() == exception_list.size(),
274  "unexpected discrepancy between sizes of instruction"
275  "targets and exception list");
276  for(instructiont::targetst::const_iterator gt_it = targets.begin();
277  gt_it != targets.end();
278  gt_it++, i++)
279  {
280  if(gt_it != targets.begin())
281  out << ", ";
282  out << exception_list[i].id() << "->"
283  << (*gt_it)->target_number;
284  }
285  }
286  else if(code().get_statement() == ID_pop_catch)
287  {
288  out << "CATCH-POP";
289  }
290  else
291  {
292  UNREACHABLE;
293  }
294 
295  out << '\n';
296  break;
297  }
298 
299  case ATOMIC_BEGIN:
300  out << "ATOMIC_BEGIN" << '\n';
301  break;
302 
303  case ATOMIC_END:
304  out << "ATOMIC_END" << '\n';
305  break;
306 
307  case START_THREAD:
308  out << "START THREAD " << get_target()->target_number << '\n';
309  break;
310 
311  case END_THREAD:
312  out << "END THREAD" << '\n';
313  break;
314  }
315 
316  return out;
317 }
318 
320  decl_identifierst &decl_identifiers) const
321 {
322  for(const auto &instruction : instructions)
323  {
324  if(instruction.is_decl())
325  {
327  instruction.code().get_statement() == ID_decl,
328  "expected statement to be declaration statement");
330  instruction.code().operands().size() == 1,
331  "declaration statement expects one operand");
332  decl_identifiers.insert(instruction.decl_symbol().get_identifier());
333  }
334  }
335 }
336 
337 void parse_lhs_read(const exprt &src, std::list<exprt> &dest)
338 {
339  if(src.id()==ID_dereference)
340  {
341  dest.push_back(to_dereference_expr(src).pointer());
342  }
343  else if(src.id()==ID_index)
344  {
345  auto &index_expr = to_index_expr(src);
346  dest.push_back(index_expr.index());
347  parse_lhs_read(index_expr.array(), dest);
348  }
349  else if(src.id()==ID_member)
350  {
351  parse_lhs_read(to_member_expr(src).compound(), dest);
352  }
353  else if(src.id()==ID_if)
354  {
355  auto &if_expr = to_if_expr(src);
356  dest.push_back(if_expr.cond());
357  parse_lhs_read(if_expr.true_case(), dest);
358  parse_lhs_read(if_expr.false_case(), dest);
359  }
360 }
361 
362 std::list<exprt> expressions_read(
363  const goto_programt::instructiont &instruction)
364 {
365  std::list<exprt> dest;
366 
367  switch(instruction.type())
368  {
369  case ASSUME:
370  case ASSERT:
371  case GOTO:
372  dest.push_back(instruction.condition());
373  break;
374 
375  case SET_RETURN_VALUE:
376  dest.push_back(instruction.return_value());
377  break;
378 
379  case FUNCTION_CALL:
380  for(const auto &argument : instruction.call_arguments())
381  dest.push_back(argument);
382  if(instruction.call_lhs().is_not_nil())
383  parse_lhs_read(instruction.call_lhs(), dest);
384  break;
385 
386  case ASSIGN:
387  dest.push_back(instruction.assign_rhs());
388  parse_lhs_read(instruction.assign_lhs(), dest);
389  break;
390 
391  case CATCH:
392  case THROW:
393  case DEAD:
394  case DECL:
395  case ATOMIC_BEGIN:
396  case ATOMIC_END:
397  case START_THREAD:
398  case END_THREAD:
399  case END_FUNCTION:
400  case LOCATION:
401  case SKIP:
402  case OTHER:
403  case INCOMPLETE_GOTO:
404  case NO_INSTRUCTION_TYPE:
405  break;
406  }
407 
408  return dest;
409 }
410 
411 std::list<exprt> expressions_written(
412  const goto_programt::instructiont &instruction)
413 {
414  std::list<exprt> dest;
415 
416  switch(instruction.type())
417  {
418  case FUNCTION_CALL:
419  if(instruction.call_lhs().is_not_nil())
420  dest.push_back(instruction.call_lhs());
421  break;
422 
423  case ASSIGN:
424  dest.push_back(instruction.assign_lhs());
425  break;
426 
427  case CATCH:
428  case THROW:
429  case GOTO:
430  case SET_RETURN_VALUE:
431  case DEAD:
432  case DECL:
433  case ATOMIC_BEGIN:
434  case ATOMIC_END:
435  case START_THREAD:
436  case END_THREAD:
437  case END_FUNCTION:
438  case ASSERT:
439  case ASSUME:
440  case LOCATION:
441  case SKIP:
442  case OTHER:
443  case INCOMPLETE_GOTO:
444  case NO_INSTRUCTION_TYPE:
445  break;
446  }
447 
448  return dest;
449 }
450 
452  const exprt &src,
453  std::list<exprt> &dest)
454 {
455  if(src.id()==ID_symbol)
456  dest.push_back(src);
457  else if(src.id()==ID_address_of)
458  {
459  // don't traverse!
460  }
461  else if(src.id()==ID_dereference)
462  {
463  // this reads what is pointed to plus the pointer
464  auto &deref = to_dereference_expr(src);
465  dest.push_back(deref);
466  objects_read(deref.pointer(), dest);
467  }
468  else
469  {
470  for(const auto &op : src.operands())
471  objects_read(op, dest);
472  }
473 }
474 
475 std::list<exprt> objects_read(
476  const goto_programt::instructiont &instruction)
477 {
478  std::list<exprt> expressions=expressions_read(instruction);
479 
480  std::list<exprt> dest;
481 
482  for(const auto &expr : expressions)
483  objects_read(expr, dest);
484 
485  return dest;
486 }
487 
489  const exprt &src,
490  std::list<exprt> &dest)
491 {
492  if(src.id()==ID_if)
493  {
494  auto &if_expr = to_if_expr(src);
495  objects_written(if_expr.true_case(), dest);
496  objects_written(if_expr.false_case(), dest);
497  }
498  else
499  dest.push_back(src);
500 }
501 
502 std::list<exprt> objects_written(
503  const goto_programt::instructiont &instruction)
504 {
505  std::list<exprt> expressions=expressions_written(instruction);
506 
507  std::list<exprt> dest;
508 
509  for(const auto &expr : expressions)
510  objects_written(expr, dest);
511 
512  return dest;
513 }
514 
515 std::string as_string(
516  const class namespacet &ns,
517  const irep_idt &function,
519 {
520  std::string result;
521 
522  switch(i.type())
523  {
524  case NO_INSTRUCTION_TYPE:
525  return "(NO INSTRUCTION TYPE)";
526 
527  case GOTO:
528  if(!i.condition().is_true())
529  {
530  result += "IF " + from_expr(ns, function, i.condition()) + " THEN ";
531  }
532 
533  result+="GOTO ";
534 
535  for(goto_programt::instructiont::targetst::const_iterator
536  gt_it=i.targets.begin();
537  gt_it!=i.targets.end();
538  gt_it++)
539  {
540  if(gt_it!=i.targets.begin())
541  result+=", ";
542  result+=std::to_string((*gt_it)->target_number);
543  }
544  return result;
545 
546  case SET_RETURN_VALUE:
547  case OTHER:
548  case DECL:
549  case DEAD:
550  case FUNCTION_CALL:
551  case ASSIGN:
552  return from_expr(ns, function, i.code());
553 
554  case ASSUME:
555  case ASSERT:
556  if(i.is_assume())
557  result+="ASSUME ";
558  else
559  result+="ASSERT ";
560 
561  result += from_expr(ns, function, i.condition());
562 
563  {
565  if(!comment.empty())
566  result+=" /* "+id2string(comment)+" */";
567  }
568  return result;
569 
570  case SKIP:
571  return "SKIP";
572 
573  case END_FUNCTION:
574  return "END_FUNCTION";
575 
576  case LOCATION:
577  return "LOCATION";
578 
579  case THROW:
580  return "THROW";
581 
582  case CATCH:
583  return "CATCH";
584 
585  case ATOMIC_BEGIN:
586  return "ATOMIC_BEGIN";
587 
588  case ATOMIC_END:
589  return "ATOMIC_END";
590 
591  case START_THREAD:
592  result+="START THREAD ";
593 
594  if(i.targets.size()==1)
595  result+=std::to_string(i.targets.front()->target_number);
596  return result;
597 
598  case END_THREAD:
599  return "END THREAD";
600 
601  case INCOMPLETE_GOTO:
602  UNREACHABLE;
603  }
604 
605  UNREACHABLE;
606 }
607 
612 {
613  unsigned nr=0;
614  for(auto &i : instructions)
615  if(i.is_backwards_goto())
616  i.loop_number=nr++;
617 }
618 
620 {
625 }
626 
627 std::ostream &goto_programt::output(std::ostream &out) const
628 {
629  // output the program
630 
631  for(const auto &instruction : instructions)
632  instruction.output(out);
633 
634  return out;
635 }
636 
648 {
649  // reset marking
650 
651  for(auto &i : instructions)
652  i.target_number=instructiont::nil_target;
653 
654  // mark the goto targets
655 
656  for(const auto &i : instructions)
657  {
658  for(const auto &t : i.targets)
659  {
660  if(t!=instructions.end())
661  t->target_number=0;
662  }
663  }
664 
665  // number the targets properly
666  unsigned cnt=0;
667 
668  for(auto &i : instructions)
669  {
670  if(i.is_target())
671  {
672  i.target_number=++cnt;
674  i.target_number != 0, "GOTO instruction target cannot be zero");
675  }
676  }
677 
678  // check the targets!
679  // (this is a consistency check only)
680 
681  for(const auto &i : instructions)
682  {
683  for(const auto &t : i.targets)
684  {
685  if(t!=instructions.end())
686  {
688  t->target_number != 0, "instruction's number cannot be zero");
690  t->target_number != instructiont::nil_target,
691  "GOTO instruction target cannot be nil_target");
692  }
693  }
694  }
695 }
696 
702 {
703  // Definitions for mapping between the two programs
704  typedef std::map<const_targett, targett, target_less_than> targets_mappingt;
705  targets_mappingt targets_mapping;
706 
707  clear();
708 
709  // Loop over program - 1st time collects targets and copy
710 
711  for(instructionst::const_iterator
712  it=src.instructions.begin();
713  it!=src.instructions.end();
714  ++it)
715  {
716  auto new_instruction=add_instruction();
717  targets_mapping[it]=new_instruction;
718  *new_instruction=*it;
719  }
720 
721  // Loop over program - 2nd time updates targets
722 
723  for(auto &i : instructions)
724  {
725  for(auto &t : i.targets)
726  {
727  targets_mappingt::iterator
728  m_target_it=targets_mapping.find(t);
729 
730  CHECK_RETURN(m_target_it != targets_mapping.end());
731 
732  t=m_target_it->second;
733  }
734  }
735 
738 }
739 
743 {
744  for(const auto &i : instructions)
745  if(i.is_assert() && !i.condition().is_true())
746  return true;
747 
748  return false;
749 }
750 
753 {
754  for(auto &i : instructions)
755  {
756  i.incoming_edges.clear();
757  }
758 
759  for(instructionst::iterator
760  it=instructions.begin();
761  it!=instructions.end();
762  ++it)
763  {
764  for(const auto &s : get_successors(it))
765  {
766  if(s!=instructions.end())
767  s->incoming_edges.insert(it);
768  }
769  }
770 }
771 
773 {
774  // clang-format off
775  return
776  _type == other._type &&
777  _code == other._code &&
778  guard == other.guard &&
779  targets.size() == other.targets.size() &&
780  labels == other.labels;
781  // clang-format on
782 }
783 
785  const namespacet &ns,
786  const validation_modet vm) const
787 {
788  validate_full_code(_code, ns, vm);
789  validate_full_expr(guard, ns, vm);
790 
791  auto expr_symbol_finder = [&](const exprt &e) {
792  find_symbols_sett typetags;
793  find_type_and_expr_symbols(e, typetags);
794  const symbolt *symbol;
795  for(const auto &identifier : typetags)
796  {
798  vm,
799  !ns.lookup(identifier, symbol),
800  id2string(identifier) + " not found",
801  source_location());
802  }
803  };
804 
805  auto &current_source_location = source_location();
806  auto type_finder =
807  [&ns, vm, &current_source_location](const exprt &e) {
808  if(e.id() == ID_symbol)
809  {
810  const auto &goto_symbol_expr = to_symbol_expr(e);
811  const auto &goto_id = goto_symbol_expr.get_identifier();
812 
813  const symbolt *table_symbol;
814  if(!ns.lookup(goto_id, table_symbol))
815  {
816  bool symbol_expr_type_matches_symbol_table =
817  goto_symbol_expr.type() == table_symbol->type;
818 
819  if(
820  !symbol_expr_type_matches_symbol_table &&
821  table_symbol->type.id() == ID_code)
822  {
823  // If a function declaration and its definition are in different
824  // translation units they may have different return types.
825  // Thus, the return type in the symbol table may differ
826  // from the return type in the symbol expr.
827  if(
828  goto_symbol_expr.type().source_location().get_file() !=
829  table_symbol->type.source_location().get_file())
830  {
831  // temporarily fixup the return types
832  auto goto_symbol_expr_type =
833  to_code_type(goto_symbol_expr.type());
834  auto table_symbol_type = to_code_type(table_symbol->type);
835 
836  goto_symbol_expr_type.return_type() =
837  table_symbol_type.return_type();
838 
839  symbol_expr_type_matches_symbol_table =
840  goto_symbol_expr_type == table_symbol_type;
841  }
842  }
843 
844  if(
845  !symbol_expr_type_matches_symbol_table &&
846  goto_symbol_expr.type().id() == ID_array &&
847  to_array_type(goto_symbol_expr.type()).is_incomplete())
848  {
849  // If the symbol expr has an incomplete array type, it may not have
850  // a constant size value, whereas the symbol table entry may have
851  // an (assumed) constant size of 1 (which mimics gcc behaviour)
852  if(table_symbol->type.id() == ID_array)
853  {
854  auto symbol_table_array_type = to_array_type(table_symbol->type);
855  symbol_table_array_type.size() = nil_exprt();
856 
857  symbol_expr_type_matches_symbol_table =
858  goto_symbol_expr.type() == symbol_table_array_type;
859  }
860  }
861 
863  vm,
864  symbol_expr_type_matches_symbol_table,
865  id2string(goto_id) + " type inconsistency\n" +
866  "goto program type: " + goto_symbol_expr.type().id_string() +
867  "\n" + "symbol table type: " + table_symbol->type.id_string(),
868  current_source_location);
869  }
870  }
871  };
872 
873  const symbolt *table_symbol;
874  switch(_type)
875  {
876  case NO_INSTRUCTION_TYPE:
877  break;
878  case GOTO:
880  vm,
881  has_target(),
882  "goto instruction expects at least one target",
883  source_location());
884  // get_target checks that targets.size()==1
886  vm,
887  get_target()->is_target() && get_target()->target_number != 0,
888  "goto target has to be a target",
889  source_location());
890  break;
891  case ASSUME:
893  vm,
894  targets.empty(),
895  "assume instruction should not have a target",
896  source_location());
897  break;
898  case ASSERT:
900  vm,
901  targets.empty(),
902  "assert instruction should not have a target",
903  source_location());
904 
905  expr_symbol_finder(guard);
906  std::for_each(guard.depth_begin(), guard.depth_end(), type_finder);
907  break;
908  case OTHER:
909  break;
910  case SKIP:
911  break;
912  case START_THREAD:
913  break;
914  case END_THREAD:
915  break;
916  case LOCATION:
917  break;
918  case END_FUNCTION:
919  break;
920  case ATOMIC_BEGIN:
921  break;
922  case ATOMIC_END:
923  break;
924  case SET_RETURN_VALUE:
926  vm,
927  _code.get_statement() == ID_return,
928  "SET_RETURN_VALUE instruction should contain a return statement",
929  source_location());
930  break;
931  case ASSIGN:
932  DATA_CHECK(
933  vm,
934  _code.get_statement() == ID_assign,
935  "assign instruction should contain an assign statement");
936  DATA_CHECK(
937  vm, targets.empty(), "assign instruction should not have a target");
938  break;
939  case DECL:
941  vm,
942  _code.get_statement() == ID_decl,
943  "declaration instructions should contain a declaration statement",
944  source_location());
946  vm,
947  !ns.lookup(decl_symbol().get_identifier(), table_symbol),
948  "declared symbols should be known",
949  id2string(decl_symbol().get_identifier()),
950  source_location());
951  break;
952  case DEAD:
954  vm,
955  _code.get_statement() == ID_dead,
956  "dead instructions should contain a dead statement",
957  source_location());
959  vm,
960  !ns.lookup(dead_symbol().get_identifier(), table_symbol),
961  "removed symbols should be known",
962  id2string(dead_symbol().get_identifier()),
963  source_location());
964  break;
965  case FUNCTION_CALL:
967  vm,
968  _code.get_statement() == ID_function_call,
969  "function call instruction should contain a call statement",
970  source_location());
971 
972  expr_symbol_finder(_code);
973  std::for_each(_code.depth_begin(), _code.depth_end(), type_finder);
974  break;
975  case THROW:
976  break;
977  case CATCH:
978  break;
979  case INCOMPLETE_GOTO:
980  break;
981  }
982 }
983 
985  std::function<std::optional<exprt>(exprt)> f)
986 {
987  switch(_type)
988  {
989  case OTHER:
990  if(get_other().get_statement() == ID_expression)
991  {
992  auto new_expression = f(to_code_expression(get_other()).expression());
993  if(new_expression.has_value())
994  {
995  auto new_other = to_code_expression(get_other());
996  new_other.expression() = *new_expression;
997  set_other(new_other);
998  }
999  }
1000  break;
1001 
1002  case SET_RETURN_VALUE:
1003  {
1004  auto new_return_value = f(return_value());
1005  if(new_return_value.has_value())
1006  return_value() = *new_return_value;
1007  }
1008  break;
1009 
1010  case ASSIGN:
1011  {
1012  auto new_assign_lhs = f(assign_lhs());
1013  auto new_assign_rhs = f(assign_rhs());
1014  if(new_assign_lhs.has_value())
1015  assign_lhs_nonconst() = new_assign_lhs.value();
1016  if(new_assign_rhs.has_value())
1017  assign_rhs_nonconst() = new_assign_rhs.value();
1018  }
1019  break;
1020 
1021  case DECL:
1022  {
1023  auto new_symbol = f(decl_symbol());
1024  if(new_symbol.has_value())
1025  decl_symbol() = to_symbol_expr(*new_symbol);
1026  }
1027  break;
1028 
1029  case DEAD:
1030  {
1031  auto new_symbol = f(dead_symbol());
1032  if(new_symbol.has_value())
1033  dead_symbol() = to_symbol_expr(*new_symbol);
1034  }
1035  break;
1036 
1037  case FUNCTION_CALL:
1038  {
1039  auto new_lhs = f(as_const(*this).call_lhs());
1040  if(new_lhs.has_value())
1041  call_lhs() = *new_lhs;
1042 
1043  auto new_call_function = f(as_const(*this).call_function());
1044  if(new_call_function.has_value())
1045  call_function() = *new_call_function;
1046 
1047  exprt::operandst new_arguments = as_const(*this).call_arguments();
1048  bool argument_changed = false;
1049 
1050  for(auto &a : new_arguments)
1051  {
1052  auto new_a = f(a);
1053  if(new_a.has_value())
1054  {
1055  a = *new_a;
1056  argument_changed = true;
1057  }
1058  }
1059 
1060  if(argument_changed)
1061  call_arguments() = std::move(new_arguments);
1062  }
1063  break;
1064 
1065  case GOTO:
1066  case ASSUME:
1067  case ASSERT:
1068  case SKIP:
1069  case START_THREAD:
1070  case END_THREAD:
1071  case LOCATION:
1072  case END_FUNCTION:
1073  case ATOMIC_BEGIN:
1074  case ATOMIC_END:
1075  case THROW:
1076  case CATCH:
1077  case INCOMPLETE_GOTO:
1078  case NO_INSTRUCTION_TYPE:
1079  if(has_condition())
1080  {
1081  auto new_condition = f(condition());
1082  if(new_condition.has_value())
1083  condition_nonconst() = new_condition.value();
1084  }
1085  }
1086 }
1087 
1089  std::function<void(const exprt &)> f) const
1090 {
1091  switch(_type)
1092  {
1093  case OTHER:
1094  if(get_other().get_statement() == ID_expression)
1095  f(to_code_expression(get_other()).expression());
1096  break;
1097 
1098  case SET_RETURN_VALUE:
1099  f(return_value());
1100  break;
1101 
1102  case ASSIGN:
1103  f(assign_lhs());
1104  f(assign_rhs());
1105  break;
1106 
1107  case DECL:
1108  f(decl_symbol());
1109  break;
1110 
1111  case DEAD:
1112  f(dead_symbol());
1113  break;
1114 
1115  case FUNCTION_CALL:
1116  f(call_lhs());
1117  for(auto &a : call_arguments())
1118  f(a);
1119  break;
1120 
1121  case GOTO:
1122  case ASSUME:
1123  case ASSERT:
1124  case SKIP:
1125  case START_THREAD:
1126  case END_THREAD:
1127  case LOCATION:
1128  case END_FUNCTION:
1129  case ATOMIC_BEGIN:
1130  case ATOMIC_END:
1131  case THROW:
1132  case CATCH:
1133  case INCOMPLETE_GOTO:
1134  case NO_INSTRUCTION_TYPE:
1135  if(has_condition())
1136  f(condition());
1137  }
1138 }
1139 
1140 bool goto_programt::equals(const goto_programt &other) const
1141 {
1142  if(instructions.size() != other.instructions.size())
1143  return false;
1144 
1145  goto_programt::const_targett other_it = other.instructions.begin();
1146  for(const auto &ins : instructions)
1147  {
1148  if(!ins.equals(*other_it))
1149  return false;
1150 
1151  // the number of targets is the same as instructiont::equals returned "true"
1152  auto other_target_it = other_it->targets.begin();
1153  for(const auto &t : ins.targets)
1154  {
1155  if(
1156  t->location_number - ins.location_number !=
1157  (*other_target_it)->location_number - other_it->location_number)
1158  {
1159  return false;
1160  }
1161 
1162  ++other_target_it;
1163  }
1164 
1165  ++other_it;
1166  }
1167 
1168  return true;
1169 }
1170 
1172 std::ostream &operator<<(std::ostream &out, goto_program_instruction_typet t)
1173 {
1174  switch(t)
1175  {
1176  case NO_INSTRUCTION_TYPE:
1177  out << "NO_INSTRUCTION_TYPE";
1178  break;
1179  case GOTO:
1180  out << "GOTO";
1181  break;
1182  case ASSUME:
1183  out << "ASSUME";
1184  break;
1185  case ASSERT:
1186  out << "ASSERT";
1187  break;
1188  case OTHER:
1189  out << "OTHER";
1190  break;
1191  case DECL:
1192  out << "DECL";
1193  break;
1194  case DEAD:
1195  out << "DEAD";
1196  break;
1197  case SKIP:
1198  out << "SKIP";
1199  break;
1200  case START_THREAD:
1201  out << "START_THREAD";
1202  break;
1203  case END_THREAD:
1204  out << "END_THREAD";
1205  break;
1206  case LOCATION:
1207  out << "LOCATION";
1208  break;
1209  case END_FUNCTION:
1210  out << "END_FUNCTION";
1211  break;
1212  case ATOMIC_BEGIN:
1213  out << "ATOMIC_BEGIN";
1214  break;
1215  case ATOMIC_END:
1216  out << "ATOMIC_END";
1217  break;
1218  case SET_RETURN_VALUE:
1219  out << "SET_RETURN_VALUE";
1220  break;
1221  case ASSIGN:
1222  out << "ASSIGN";
1223  break;
1224  case FUNCTION_CALL:
1225  out << "FUNCTION_CALL";
1226  break;
1227  case THROW:
1228  out << "THROW";
1229  break;
1230  case CATCH:
1231  out << "CATCH";
1232  break;
1233  case INCOMPLETE_GOTO:
1234  out << "INCOMPLETE_GOTO";
1235  break;
1236  }
1237 
1238  return out;
1239 }
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition: as_const.h:14
static exprt guard(const exprt::operandst &guards, exprt cond)
bool is_incomplete() const
Definition: std_types.h:857
codet representation of a goto statement.
Definition: std_code.h:841
exprt & op1()
Definition: expr.h:136
exprt & op0()
Definition: expr.h:133
const irep_idt & get_statement() const
Definition: std_code_base.h:65
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
std::vector< exprt > operandst
Definition: expr.h:58
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:27
depth_iteratort depth_end()
Definition: expr.cpp:249
depth_iteratort depth_begin()
Definition: expr.cpp:247
operandst & operands()
Definition: expr.h:94
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:181
unsigned target_number
A number to identify branch targets.
Definition: goto_program.h:566
const exprt & condition() const
Get the condition of gotos, assume, assert.
Definition: goto_program.h:366
const exprt & call_lhs() const
Get the lhs of a FUNCTION_CALL (may be nil)
Definition: goto_program.h:286
bool is_target() const
Is this node a branch target?
Definition: goto_program.h:453
const exprt & call_function() const
Get the function that is called for FUNCTION_CALL.
Definition: goto_program.h:272
goto_instruction_codet _code
Do not read or modify directly – use code() and code_nonconst() instead.
Definition: goto_program.h:184
void apply(std::function< void(const exprt &)>) const
Apply given function to all expressions.
targetst targets
The list of successor instructions.
Definition: goto_program.h:414
const exprt & return_value() const
Get the return value of a SET_RETURN_VALUE instruction.
Definition: goto_program.h:258
const goto_instruction_codet & code() const
Get the code represented by this instruction.
Definition: goto_program.h:188
goto_program_instruction_typet _type
Definition: goto_program.h:352
const goto_instruction_codet & get_other() const
Get the statement for OTHER.
Definition: goto_program.h:314
bool equals(const instructiont &other) const
Syntactic equality: two instructiont are equal if they have the same type, code, guard,...
void transform(std::function< std::optional< exprt >(exprt)>)
Apply given transformer to all expressions; no return value means no change needed.
unsigned location_number
A globally unique number to identify a program location.
Definition: goto_program.h:559
static const unsigned nil_target
Uniquely identify an invalid target or location.
Definition: goto_program.h:553
const exprt & assign_rhs() const
Get the rhs of the assignment for ASSIGN.
Definition: goto_program.h:214
const source_locationt & source_location() const
Definition: goto_program.h:333
std::ostream & output(std::ostream &) const
Output this instruction to the given stream.
const symbol_exprt & dead_symbol() const
Get the symbol for DEAD.
Definition: goto_program.h:244
exprt guard
Guard for gotos, assume, assert Use condition() method to access.
Definition: goto_program.h:356
const symbol_exprt & decl_symbol() const
Get the declared symbol for DECL.
Definition: goto_program.h:228
const_targett get_target() const
Returns the first (and only) successor for the usual case of a single target.
Definition: goto_program.h:418
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
void validate(const namespacet &ns, const validation_modet vm) const
Check that the instruction is well-formed.
const exprt::operandst & call_arguments() const
Get the arguments of a FUNCTION_CALL.
Definition: goto_program.h:300
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
void copy_from(const goto_programt &src)
Copy a full goto program, preserving targets.
void clear()
Clear the goto program.
Definition: goto_program.h:820
void update()
Update all indices.
std::ostream & output(std::ostream &out) const
Output goto-program to given stream.
bool has_assertion() const
Does the goto program have an assertion?
instructionst::const_iterator const_targett
Definition: goto_program.h:615
targett add_instruction()
Adds an instruction at the end.
Definition: goto_program.h:747
void compute_incoming_edges()
Compute for each instruction the set of instructions it is a successor of.
std::set< irep_idt > decl_identifierst
Definition: goto_program.h:853
void get_decl_identifiers(decl_identifierst &decl_identifiers) const
get the variables in decl statements
std::list< Target > get_successors(Target target) const
Get control-flow successors of a given instruction.
void compute_location_numbers()
Compute location numbers.
Definition: goto_program.h:778
void compute_target_numbers()
Compute the target numbers.
bool equals(const goto_programt &other) const
Syntactic equality: two goto_programt are equal if, and only if, they have the same number of instruc...
static instructiont make_incomplete_goto(const exprt &_cond, const source_locationt &l=source_locationt::nil())
void compute_loop_numbers()
Compute loop numbers.
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
subt & get_sub()
Definition: irep.h:444
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
const std::string & id_string() const
Definition: irep.h:387
bool is_not_nil() const
Definition: irep.h:368
const irep_idt & id() const
Definition: irep.h:384
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
The NIL expression.
Definition: std_expr.h:3073
const irep_idt & get_comment() const
const irep_idt & get_file() const
std::string as_string() const
Symbol table entry.
Definition: symbol.h:28
typet type
Type of symbol.
Definition: symbol.h:31
The Boolean constant true.
Definition: std_expr.h:3055
const source_locationt & source_location() const
Definition: type.h:72
Forward depth-first search iterators These iterators' copy operations are expensive,...
void find_type_and_expr_symbols(const exprt &src, find_symbols_sett &dest)
Find identifiers of the sub expressions with id ID_symbol, considering both free and bound variables,...
std::unordered_set< irep_idt > find_symbols_sett
Definition: find_symbols.h:20
static format_containert< T > format(const T &o)
Definition: format.h:37
void parse_lhs_read(const exprt &src, std::list< exprt > &dest)
std::list< exprt > expressions_written(const goto_programt::instructiont &instruction)
std::string as_string(const class namespacet &ns, const irep_idt &function, const goto_programt::instructiont &i)
void objects_read(const exprt &src, std::list< exprt > &dest)
std::ostream & operator<<(std::ostream &out, goto_program_instruction_typet t)
Outputs a string representation of a goto_program_instruction_typet
void objects_written(const exprt &src, std::list< exprt > &dest)
std::list< exprt > expressions_read(const goto_programt::instructiont &instruction)
Concrete Goto Program.
goto_program_instruction_typet
The type of an instruction in a GOTO program.
Definition: goto_program.h:32
@ 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
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
bool is_true(const literalt &l)
Definition: literal.h:198
API to expression classes for Pointers.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:890
static std::string comment(const rw_set_baset::entryt &entry, bool write)
Definition: race_check.cpp:108
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
static code_landingpadt & to_code_landingpad(codet &code)
Definition: std_code.h:1972
code_expressiont & to_code_expression(codet &code)
Definition: std_code.h:1428
API to expression classes.
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2450
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2933
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Symbol table entry.
#define DATA_CHECK_WITH_DIAGNOSTICS(vm, condition, message,...)
Definition: validate.h:37
#define DATA_CHECK(vm, condition, message)
This macro takes a condition which denotes a well-formedness criterion on goto programs,...
Definition: validate.h:22
void validate_full_code(const codet &code, const namespacet &ns, const validation_modet vm)
Check that the given code statement is well-formed (full check, including checks of all subexpression...
void validate_full_expr(const exprt &expr, const namespacet &ns, const validation_modet vm)
Check that the given expression is well-formed (full check, including checks of all subexpressions an...
validation_modet