CBMC
builtin_functions.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_convert_class.h"
13 
14 #include <util/arith_tools.h>
15 #include <util/c_types.h>
16 #include <util/cprover_prefix.h>
17 #include <util/expr_initializer.h>
18 #include <util/expr_util.h>
19 #include <util/fresh_symbol.h>
20 #include <util/mathematical_expr.h>
22 #include <util/pointer_expr.h>
23 #include <util/rational.h>
24 #include <util/rational_tools.h>
25 #include <util/simplify_expr.h>
26 #include <util/symbol.h>
27 
28 #include <langapi/language_util.h>
29 
30 #include "format_strings.h"
31 
33  const exprt &lhs,
34  const symbol_exprt &function,
35  const exprt::operandst &arguments,
36  goto_programt &dest)
37 {
38  const irep_idt &identifier = function.get_identifier();
39 
40  // make it a side effect if there is an LHS
41  if(arguments.size() != 2)
42  {
43  error().source_location = function.find_source_location();
44  error() << "'" << identifier << "' expected to have two arguments" << eom;
45  throw 0;
46  }
47 
48  if(lhs.is_nil())
49  {
50  error().source_location = function.find_source_location();
51  error() << "'" << identifier << "' expected to have LHS" << eom;
52  throw 0;
53  }
54 
55  auto rhs =
56  side_effect_exprt("prob_uniform", lhs.type(), function.source_location());
57 
58  if(lhs.type().id() != ID_unsignedbv && lhs.type().id() != ID_signedbv)
59  {
60  error().source_location = function.find_source_location();
61  error() << "'" << identifier << "' expected other type" << eom;
62  throw 0;
63  }
64 
65  if(
66  arguments[0].type().id() != lhs.type().id() ||
67  arguments[1].type().id() != lhs.type().id())
68  {
69  error().source_location = function.find_source_location();
70  error() << "'" << identifier
71  << "' expected operands to be of same type as LHS" << eom;
72  throw 0;
73  }
74 
75  if(!arguments[0].is_constant() || !arguments[1].is_constant())
76  {
77  error().source_location = function.find_source_location();
78  error() << "'" << identifier
79  << "' expected operands to be constant literals" << eom;
80  throw 0;
81  }
82 
83  mp_integer lb, ub;
84 
85  if(
86  to_integer(to_constant_expr(arguments[0]), lb) ||
87  to_integer(to_constant_expr(arguments[1]), ub))
88  {
89  error().source_location = function.find_source_location();
90  error() << "error converting operands" << eom;
91  throw 0;
92  }
93 
94  if(lb > ub)
95  {
96  error().source_location = function.find_source_location();
97  error() << "expected lower bound to be smaller or equal to the "
98  << "upper bound" << eom;
99  throw 0;
100  }
101 
102  rhs.add_to_operands(exprt{arguments[0]}, exprt{arguments[1]});
103 
104  code_assignt assignment(lhs, rhs);
105  assignment.add_source_location() = function.source_location();
106  copy(assignment, ASSIGN, dest);
107 }
108 
110  const exprt &lhs,
111  const symbol_exprt &function,
112  const exprt::operandst &arguments,
113  goto_programt &dest)
114 {
115  const irep_idt &identifier = function.get_identifier();
116 
117  // make it a side effect if there is an LHS
118  if(arguments.size() != 2)
119  {
120  error().source_location = function.find_source_location();
121  error() << "'" << identifier << "' expected to have two arguments" << eom;
122  throw 0;
123  }
124 
125  if(lhs.is_nil())
126  {
127  error().source_location = function.find_source_location();
128  error() << "'" << identifier << "' expected to have LHS" << eom;
129  throw 0;
130  }
131 
132  side_effect_exprt rhs("prob_coin", lhs.type(), function.source_location());
133 
134  if(lhs.type() != bool_typet())
135  {
136  error().source_location = function.find_source_location();
137  error() << "'" << identifier << "' expected bool" << eom;
138  throw 0;
139  }
140 
141  if(arguments[0].type().id() != ID_unsignedbv || !arguments[0].is_constant())
142  {
143  error().source_location = function.find_source_location();
144  error() << "'" << identifier << "' expected first operand to be "
145  << "a constant literal of type unsigned long" << eom;
146  throw 0;
147  }
148 
149  if(arguments[1].type().id() != ID_unsignedbv || !arguments[1].is_constant())
150  {
151  error().source_location = function.find_source_location();
152  error() << "'" << identifier << "' expected second operand to be "
153  << "a constant literal of type unsigned long" << eom;
154  throw 0;
155  }
156 
157  mp_integer num, den;
158 
159  if(
160  to_integer(to_constant_expr(arguments[0]), num) ||
161  to_integer(to_constant_expr(arguments[1]), den))
162  {
163  error().source_location = function.find_source_location();
164  error() << "error converting operands" << eom;
165  throw 0;
166  }
167 
168  if(num - den > mp_integer(0))
169  {
170  error().source_location = function.find_source_location();
171  error() << "probability has to be smaller than 1" << eom;
172  throw 0;
173  }
174 
175  if(den == mp_integer(0))
176  {
177  error().source_location = function.find_source_location();
178  error() << "denominator may not be zero" << eom;
179  throw 0;
180  }
181 
182  rationalt numerator(num), denominator(den);
183  rationalt prob = numerator / denominator;
184 
185  rhs.copy_to_operands(from_rational(prob));
186 
187  code_assignt assignment(lhs, rhs);
188  assignment.add_source_location() = function.source_location();
189  copy(assignment, ASSIGN, dest);
190 }
191 
193  const exprt &lhs,
194  const symbol_exprt &function,
195  const exprt::operandst &arguments,
196  goto_programt &dest)
197 {
198  const irep_idt &f_id = function.get_identifier();
199 
200  PRECONDITION(f_id == CPROVER_PREFIX "printf");
201 
202  codet printf_code(ID_printf, arguments, function.source_location());
203  copy(printf_code, OTHER, dest);
204 }
205 
207  const exprt &lhs,
208  const symbol_exprt &function,
209  const exprt::operandst &arguments,
210  goto_programt &dest)
211 {
212  const irep_idt &f_id = function.get_identifier();
213 
214  if(f_id == CPROVER_PREFIX "scanf")
215  {
216  if(arguments.empty())
217  {
218  error().source_location = function.find_source_location();
219  error() << "scanf takes at least one argument" << eom;
220  throw 0;
221  }
222 
223  irep_idt format_string;
224 
225  if(!get_string_constant(arguments[0], format_string))
226  {
227  // use our model
228  format_token_listt token_list =
229  parse_format_string(id2string(format_string));
230 
231  std::size_t argument_number = 1;
232 
233  for(const auto &t : token_list)
234  {
235  const auto type = get_type(t);
236 
237  if(type.has_value())
238  {
239  if(argument_number < arguments.size())
240  {
241  const typecast_exprt ptr(
242  arguments[argument_number], pointer_type(*type));
243  argument_number++;
244 
245  if(type->id() == ID_array)
246  {
247 #if 0
248  // A string. We first need a nondeterministic size.
250  to_array_type(*type).size()=size;
251 
252  const symbolt &tmp_symbol=
254  *type, "scanf_string", dest, function.source_location());
255 
256  const address_of_exprt rhs(
257  index_exprt(
258  tmp_symbol.symbol_expr(),
259  from_integer(0, c_index_type())));
260 
261  // now use array copy
262  codet array_copy_statement;
263  array_copy_statement.set_statement(ID_array_copy);
264  array_copy_statement.operands().resize(2);
265  array_copy_statement.op0()=ptr;
266 \ array_copy_statement.op1()=rhs;
267  array_copy_statement.add_source_location()=
268  function.source_location();
269 
270  copy(array_copy_statement, OTHER, dest);
271 #else
272  const index_exprt new_lhs(
274  const side_effect_expr_nondett rhs(
275  to_array_type(*type).element_type(),
276  function.source_location());
277  code_assignt assign(new_lhs, rhs);
278  assign.add_source_location() = function.source_location();
279  copy(assign, ASSIGN, dest);
280 #endif
281  }
282  else
283  {
284  // make it nondet for now
285  const dereference_exprt new_lhs{ptr};
286  const side_effect_expr_nondett rhs(
287  *type, function.source_location());
288  code_assignt assign(new_lhs, rhs);
289  assign.add_source_location() = function.source_location();
290  copy(assign, ASSIGN, dest);
291  }
292  }
293  }
294  }
295  }
296  else
297  {
298  // we'll just do nothing
299  code_function_callt function_call(lhs, function, arguments);
300  function_call.add_source_location() = function.source_location();
301 
302  copy(function_call, FUNCTION_CALL, dest);
303  }
304  }
305  else
306  UNREACHABLE;
307 }
308 
310  const exprt &function,
311  const exprt::operandst &arguments,
312  goto_programt &dest)
313 {
314  if(arguments.size() < 2)
315  {
316  error().source_location = function.find_source_location();
317  error() << "input takes at least two arguments" << eom;
318  throw 0;
319  }
320 
321  copy(code_inputt{arguments, function.source_location()}, OTHER, dest);
322 }
323 
325  const exprt &function,
326  const exprt::operandst &arguments,
327  goto_programt &dest)
328 {
329  if(arguments.size() < 2)
330  {
331  error().source_location = function.find_source_location();
332  error() << "output takes at least two arguments" << eom;
333  throw 0;
334  }
335 
336  copy(code_outputt{arguments, function.source_location()}, OTHER, dest);
337 }
338 
340  const exprt &lhs,
341  const symbol_exprt &function,
342  const exprt::operandst &arguments,
343  goto_programt &dest)
344 {
345  if(lhs.is_not_nil())
346  {
348  error() << "atomic_begin does not expect an LHS" << eom;
349  throw 0;
350  }
351 
352  if(!arguments.empty())
353  {
354  error().source_location = function.find_source_location();
355  error() << "atomic_begin takes no arguments" << eom;
356  throw 0;
357  }
358 
359  dest.add(goto_programt::make_atomic_begin(function.source_location()));
360 }
361 
363  const exprt &lhs,
364  const symbol_exprt &function,
365  const exprt::operandst &arguments,
366  goto_programt &dest)
367 {
368  if(lhs.is_not_nil())
369  {
371  error() << "atomic_end does not expect an LHS" << eom;
372  throw 0;
373  }
374 
375  if(!arguments.empty())
376  {
377  error().source_location = function.find_source_location();
378  error() << "atomic_end takes no arguments" << eom;
379  throw 0;
380  }
381 
382  dest.add(goto_programt::make_atomic_end(function.source_location()));
383 }
384 
386  const exprt &lhs,
387  const side_effect_exprt &rhs,
388  goto_programt &dest)
389 {
390  if(lhs.is_nil())
391  {
393  error() << "do_cpp_new without lhs is yet to be implemented" << eom;
394  throw 0;
395  }
396 
397  // build size expression
398  exprt object_size = static_cast<const exprt &>(rhs.find(ID_sizeof));
399 
400  bool new_array = rhs.get(ID_statement) == ID_cpp_new_array;
401 
402  exprt count;
403 
404  if(new_array)
405  {
407  static_cast<const exprt &>(rhs.find(ID_size)), object_size.type());
408 
409  // might have side-effect
410  clean_expr(count, dest, ID_cpp);
411  }
412 
413  exprt tmp_symbol_expr;
414 
415  // is this a placement new?
416  if(rhs.operands().empty()) // no, "regular" one
417  {
418  // call __new or __new_array
419  exprt new_symbol =
420  ns.lookup(new_array ? "__new_array" : "__new").symbol_expr();
421 
422  const code_typet &code_type = to_code_type(new_symbol.type());
423 
424  const typet &return_type = code_type.return_type();
425 
427  code_type.parameters().size() == 1 || code_type.parameters().size() == 2,
428  "new has one or two parameters");
429 
430  const symbolt &tmp_symbol =
431  new_tmp_symbol(return_type, "new", dest, rhs.source_location(), ID_cpp);
432 
433  tmp_symbol_expr = tmp_symbol.symbol_expr();
434 
435  code_function_callt new_call(new_symbol);
436  if(new_array)
437  new_call.arguments().push_back(count);
438  new_call.arguments().push_back(object_size);
439  new_call.set(
440  ID_C_cxx_alloc_type, to_type_with_subtype(lhs.type()).subtype());
441  new_call.lhs() = tmp_symbol_expr;
442  new_call.add_source_location() = rhs.source_location();
443 
444  convert(new_call, dest, ID_cpp);
445  }
446  else if(rhs.operands().size() == 1)
447  {
448  // call __placement_new
449  exprt new_symbol =
450  ns.lookup(new_array ? "__placement_new_array" : "__placement_new")
451  .symbol_expr();
452 
453  const code_typet &code_type = to_code_type(new_symbol.type());
454 
455  const typet &return_type = code_type.return_type();
456 
458  code_type.parameters().size() == 2 || code_type.parameters().size() == 3,
459  "placement new has two or three parameters");
460 
461  const symbolt &tmp_symbol =
462  new_tmp_symbol(return_type, "new", dest, rhs.source_location(), ID_cpp);
463 
464  tmp_symbol_expr = tmp_symbol.symbol_expr();
465 
466  code_function_callt new_call(new_symbol);
467  if(new_array)
468  new_call.arguments().push_back(count);
469  new_call.arguments().push_back(object_size);
470  new_call.arguments().push_back(to_unary_expr(rhs).op()); // memory location
471  new_call.set(
472  ID_C_cxx_alloc_type, to_type_with_subtype(lhs.type()).subtype());
473  new_call.lhs() = tmp_symbol_expr;
474  new_call.add_source_location() = rhs.source_location();
475 
476  for(std::size_t i = 0; i < code_type.parameters().size(); i++)
477  {
479  new_call.arguments()[i], code_type.parameters()[i].type());
480  }
481 
482  convert(new_call, dest, ID_cpp);
483  }
484  else
485  {
487  error() << "cpp_new expected to have 0 or 1 operands" << eom;
488  throw 0;
489  }
490 
492  lhs,
493  typecast_exprt(tmp_symbol_expr, lhs.type()),
494  rhs.find_source_location()));
495 
496  // grab initializer
497  goto_programt tmp_initializer;
498  cpp_new_initializer(lhs, rhs, tmp_initializer);
499 
500  dest.destructive_append(tmp_initializer);
501 }
502 
505  const exprt &lhs,
506  const side_effect_exprt &rhs,
507  goto_programt &dest)
508 {
509  exprt initializer = static_cast<const exprt &>(rhs.find(ID_initializer));
510 
511  if(initializer.is_not_nil())
512  {
513  if(rhs.get_statement() == "cpp_new[]")
514  {
515  // build loop
516  }
517  else if(rhs.get_statement() == ID_cpp_new)
518  {
519  // just one object
520  const dereference_exprt deref_lhs(
521  lhs, to_pointer_type(rhs.type()).base_type());
522 
523  replace_new_object(deref_lhs, initializer);
524  convert(to_code(initializer), dest, ID_cpp);
525  }
526  else
527  UNREACHABLE;
528  }
529 }
530 
532 {
533  if(src.id() == ID_typecast)
534  return get_array_argument(to_typecast_expr(src).op());
535 
536  if(src.id() != ID_address_of)
537  {
539  error() << "expected array-pointer as argument" << eom;
540  throw 0;
541  }
542 
543  const auto &address_of_expr = to_address_of_expr(src);
544 
545  if(address_of_expr.object().id() != ID_index)
546  {
548  error() << "expected array-element as argument" << eom;
549  throw 0;
550  }
551 
552  const auto &index_expr = to_index_expr(address_of_expr.object());
553 
554  if(index_expr.array().type().id() != ID_array)
555  {
557  error() << "expected array as argument" << eom;
558  throw 0;
559  }
560 
561  return index_expr.array();
562 }
563 
565  const irep_idt &id,
566  const exprt &lhs,
567  const symbol_exprt &function,
568  const exprt::operandst &arguments,
569  goto_programt &dest)
570 {
571  if(arguments.size() != 2)
572  {
573  error().source_location = function.find_source_location();
574  error() << id << " expects two arguments" << eom;
575  throw 0;
576  }
577 
578  codet array_op_statement(id);
579  array_op_statement.operands() = arguments;
580  array_op_statement.add_source_location() = function.source_location();
581 
582  // lhs is only used with array_equal, in all other cases it should be nil (as
583  // they are of type void)
584  if(id == ID_array_equal)
585  array_op_statement.copy_to_operands(lhs);
586 
587  copy(array_op_statement, OTHER, dest);
588 }
589 
591 {
592  exprt result = skip_typecast(expr);
593 
594  // if it's an address of an lvalue, we take that
595  if(result.id() == ID_address_of)
596  {
597  const auto &address_of_expr = to_address_of_expr(result);
598  if(is_assignable(address_of_expr.object()))
599  result = address_of_expr.object();
600  }
601 
602  while(result.type().id() == ID_array &&
603  to_array_type(result.type()).size().is_one())
604  {
605  result = index_exprt{result, from_integer(0, c_index_type())};
606  }
607 
608  return result;
609 }
610 
612  const exprt &lhs,
613  const symbol_exprt &function,
614  const exprt::operandst &arguments,
615  goto_programt &dest,
616  const irep_idt &mode)
617 {
618  irep_idt identifier = CPROVER_PREFIX "havoc_slice";
619 
620  // We disable checks on the generated instructions
621  // because we add our own rw_ok assertion that takes size into account
622  auto source_location = function.find_source_location();
623  source_location.add_pragma("disable:pointer-check");
624  source_location.add_pragma("disable:pointer-overflow-check");
625  source_location.add_pragma("disable:pointer-primitive-check");
626 
627  // check # arguments
628  if(arguments.size() != 2)
629  {
630  error().source_location = source_location;
631  error() << "'" << identifier << "' expected to have two arguments" << eom;
632  throw 0;
633  }
634 
635  // check argument types
636  if(arguments[0].type().id() != ID_pointer)
637  {
638  error().source_location = source_location;
639  error() << "'" << identifier
640  << "' first argument expected to have `void *` type" << eom;
641  throw 0;
642  }
643 
644  if(arguments[1].type().id() != ID_unsignedbv)
645  {
646  error().source_location = source_location;
647  error() << "'" << identifier
648  << "' second argument expected to have `size_t` type" << eom;
649  throw 0;
650  }
651 
652  // check nil lhs
653  if(lhs.is_not_nil())
654  {
655  error().source_location = source_location;
656  error() << "'" << identifier << "' not expected to have a LHS" << eom;
657  throw 0;
658  }
659 
660  // insert instructions
661  // assert(rw_ok(argument[0], argument[1]));
662  // char nondet_contents[argument[1]];
663  // __CPROVER_array_replace(p, nondet_contents);
664 
665  r_or_w_ok_exprt ok_expr(ID_w_ok, arguments[0], arguments[1]);
666  ok_expr.add_source_location() = source_location;
667  source_locationt annotated_location = source_location;
668  annotated_location.set("user-provided", false);
669  annotated_location.set_property_class(ID_assertion);
670  annotated_location.set_comment(
671  "assertion havoc_slice " + from_expr(ns, identifier, ok_expr));
672  dest.add(goto_programt::make_assertion(ok_expr, annotated_location));
673 
674  const array_typet array_type(char_type(), simplify_expr(arguments[1], ns));
675 
676  const symbolt &nondet_contents =
677  new_tmp_symbol(array_type, "nondet_contents", dest, source_location, mode);
678  const exprt &nondet_contents_expr = address_of_exprt{index_exprt{
679  nondet_contents.symbol_expr(), from_integer(0, c_index_type())}};
680 
681  const exprt &arg0 =
684  nondet_contents_expr, pointer_type(empty_typet{}));
685 
686  codet array_replace(ID_array_replace, {arg0, arg1}, source_location);
687  dest.add(goto_programt::make_other(array_replace, source_location));
688 }
689 
693  const exprt &lhs,
694  const symbol_exprt &function,
695  const exprt::operandst &arguments,
696  goto_programt &dest,
697  const irep_idt &mode)
698 {
699  const source_locationt &source_location = function.source_location();
700  const auto alloca_type = to_code_type(function.type());
701 
702  if(alloca_type.return_type() != pointer_type(void_type()))
703  {
704  error().source_location = source_location;
705  error() << "'alloca' function called, but 'alloca' has not been declared "
706  << "with expected 'void *' return type." << eom;
707  throw 0;
708  }
709  if(
710  alloca_type.parameters().size() != 1 ||
711  alloca_type.parameters()[0].type() != size_type())
712  {
713  error().source_location = source_location;
714  error() << "'alloca' function called, but 'alloca' has not been declared "
715  << "with expected single 'size_t' parameter." << eom;
716  throw 0;
717  }
718 
719  exprt new_lhs = lhs;
720 
721  // make sure we have a left-hand side to track the allocation even when the
722  // original program did not
723  if(lhs.is_nil())
724  {
725  new_lhs =
727  alloca_type.return_type(), "alloca", dest, source_location, mode)
728  .symbol_expr();
729  }
730 
731  // do the actual function call
732  code_function_callt function_call(new_lhs, function, arguments);
733  function_call.add_source_location() = source_location;
734  copy(function_call, FUNCTION_CALL, dest);
735 
736  // Don't add instrumentation when we're in alloca (which might in turn call
737  // __builtin_alloca) -- the instrumentation will be done for the call of
738  // alloca. Also, we can only add instrumentation when we're in a function
739  // context.
740  if(
741  function.source_location().get_function() == "alloca" || !targets.prefix ||
742  !targets.suffix)
743  {
744  return;
745  }
746 
747  // create a symbol to eventually (and non-deterministically) mark the
748  // allocation as dead; this symbol has function scope and is initialised to
749  // NULL
750  symbol_exprt this_alloca_ptr =
752  alloca_type.return_type(),
753  id2string(function.source_location().get_function()),
754  "tmp_alloca",
755  source_location,
756  mode,
757  symbol_table)
758  .symbol_expr();
759  goto_programt decl_prg;
760  decl_prg.add(goto_programt::make_decl(this_alloca_ptr, source_location));
762  this_alloca_ptr,
763  null_pointer_exprt{to_pointer_type(this_alloca_ptr.type())},
764  source_location));
766  targets.prefix->instructions.begin(), decl_prg);
767 
768  // non-deterministically update this_alloca_ptr
769  if_exprt rhs{
770  side_effect_expr_nondett{bool_typet(), source_location},
771  new_lhs,
772  this_alloca_ptr};
774  this_alloca_ptr, std::move(rhs), source_location));
775 
776  // mark pointer to alloca result as dead, unless the alloca result (in
777  // this_alloca_ptr) is still NULL
778  symbol_exprt dead_object_sym =
779  ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
780  exprt alloca_result =
781  typecast_exprt::conditional_cast(this_alloca_ptr, dead_object_sym.type());
782  if_exprt not_null{
783  equal_exprt{
784  this_alloca_ptr,
785  null_pointer_exprt{to_pointer_type(this_alloca_ptr.type())}},
786  dead_object_sym,
787  std::move(alloca_result)};
788  auto assign = goto_programt::make_assignment(
789  std::move(dead_object_sym), std::move(not_null), source_location);
791  targets.suffix->instructions.begin(), assign);
793  targets.suffix->instructions.begin(),
794  goto_programt::make_dead(this_alloca_ptr, source_location));
795 }
796 
799  const exprt &lhs,
800  const symbol_exprt &function,
801  const exprt::operandst &arguments,
802  goto_programt &dest,
803  const irep_idt &mode)
804 {
805  if(function.get_bool(ID_C_invalid_object))
806  return; // ignore
807 
808  // lookup symbol
809  const irep_idt &identifier = function.get_identifier();
810 
811  const symbolt *symbol;
812  if(ns.lookup(identifier, symbol))
813  {
814  error().source_location = function.find_source_location();
815  error() << "function '" << identifier << "' not found" << eom;
816  throw 0;
817  }
818 
819  if(symbol->type.id() != ID_code)
820  {
821  error().source_location = function.find_source_location();
822  error() << "function '" << identifier << "' type mismatch: expected code"
823  << eom;
824  throw 0;
825  }
826 
827  // User-provided function definitions always take precedence over built-ins.
828  // Front-ends do not (yet) consistently set ID_C_incomplete, thus also test
829  // whether the symbol actually has some non-nil value (which might be
830  // "compiled").
831  if(!symbol->type.get_bool(ID_C_incomplete) && symbol->value.is_not_nil())
832  {
833  do_function_call_symbol(*symbol);
834 
835  // use symbol->symbol_expr() to ensure we use the type from the symbol table
836  code_function_callt function_call(
837  lhs, symbol->symbol_expr().with_source_location(function), arguments);
838  function_call.add_source_location() = function.source_location();
839 
840  // remove void-typed assignments, which may have been created when the
841  // front-end was unable to detect them in type checking for a lack of
842  // available declarations
843  if(
844  lhs.is_not_nil() &&
845  to_code_type(symbol->type).return_type().id() == ID_empty)
846  {
847  function_call.lhs().make_nil();
848  }
849 
850  copy(function_call, FUNCTION_CALL, dest);
851 
852  return;
853  }
854 
855  if(identifier == CPROVER_PREFIX "havoc_slice")
856  {
857  do_havoc_slice(lhs, function, arguments, dest, mode);
858  }
859  else if(
860  identifier == CPROVER_PREFIX "assume" || identifier == "__VERIFIER_assume")
861  {
862  if(arguments.size() != 1)
863  {
864  error().source_location = function.find_source_location();
865  error() << "'" << identifier << "' expected to have one argument" << eom;
866  throw 0;
867  }
868 
869  // let's double-check the type of the argument
870  source_locationt annotated_location = function.source_location();
871  annotated_location.set("user-provided", true);
873  typecast_exprt::conditional_cast(arguments.front(), bool_typet()),
874  annotated_location));
875 
876  if(lhs.is_not_nil())
877  {
878  error().source_location = function.find_source_location();
879  error() << identifier << " expected not to have LHS" << eom;
880  throw 0;
881  }
882  }
883  else if(identifier == "__VERIFIER_error")
884  {
885  if(!arguments.empty())
886  {
887  error().source_location = function.find_source_location();
888  error() << "'" << identifier << "' expected to have no arguments" << eom;
889  throw 0;
890  }
891 
892  source_locationt annotated_location = function.source_location();
893  annotated_location.set("user-provided", true);
894  annotated_location.set_property_class(ID_assertion);
895  dest.add(goto_programt::make_assertion(false_exprt(), annotated_location));
896 
897  if(lhs.is_not_nil())
898  {
899  error().source_location = function.find_source_location();
900  error() << identifier << " expected not to have LHS" << eom;
901  throw 0;
902  }
903 
904  // __VERIFIER_error has abort() semantics, even if no assertions
905  // are being checked
906  annotated_location = function.source_location();
907  annotated_location.set("user-provided", true);
908  dest.add(goto_programt::make_assumption(false_exprt(), annotated_location));
909  dest.instructions.back().labels.push_back("__VERIFIER_abort");
910  }
911  else if(
912  identifier == "assert" &&
914  {
915  if(arguments.size() != 1)
916  {
917  error().source_location = function.find_source_location();
918  error() << "'" << identifier << "' expected to have one argument" << eom;
919  throw 0;
920  }
921 
922  // let's double-check the type of the argument
923  source_locationt annotated_location = function.source_location();
924  annotated_location.set("user-provided", true);
925  annotated_location.set_property_class(ID_assertion);
926  annotated_location.set_comment(
927  "assertion " + from_expr(ns, identifier, arguments.front()));
929  typecast_exprt::conditional_cast(arguments.front(), bool_typet()),
930  annotated_location));
931 
932  if(lhs.is_not_nil())
933  {
934  error().source_location = function.find_source_location();
935  error() << identifier << " expected not to have LHS" << eom;
936  throw 0;
937  }
938  }
939  else if(
940  identifier == CPROVER_PREFIX "assert" ||
941  identifier == CPROVER_PREFIX "precondition" ||
942  identifier == CPROVER_PREFIX "postcondition")
943  {
944  if(arguments.size() != 2)
945  {
946  error().source_location = function.find_source_location();
947  error() << "'" << identifier << "' expected to have two arguments" << eom;
948  throw 0;
949  }
950 
951  bool is_precondition = identifier == CPROVER_PREFIX "precondition";
952  bool is_postcondition = identifier == CPROVER_PREFIX "postcondition";
953 
954  const irep_idt description = get_string_constant(arguments[1]);
955 
956  // let's double-check the type of the argument
957  source_locationt annotated_location = function.source_location();
958  if(is_precondition)
959  {
960  annotated_location.set_property_class(ID_precondition);
961  }
962  else if(is_postcondition)
963  {
964  annotated_location.set_property_class(ID_postcondition);
965  }
966  else
967  {
968  annotated_location.set(
969  "user-provided", !function.source_location().is_built_in());
970  annotated_location.set_property_class(ID_assertion);
971  }
972 
973  annotated_location.set_comment(description);
974 
977  annotated_location));
978 
979  if(lhs.is_not_nil())
980  {
981  error().source_location = function.find_source_location();
982  error() << identifier << " expected not to have LHS" << eom;
983  throw 0;
984  }
985  }
986  else if(identifier == CPROVER_PREFIX "havoc_object")
987  {
988  if(arguments.size() != 1)
989  {
990  error().source_location = function.find_source_location();
991  error() << "'" << identifier << "' expected to have one argument" << eom;
992  throw 0;
993  }
994 
995  if(lhs.is_not_nil())
996  {
997  error().source_location = function.find_source_location();
998  error() << identifier << " expected not to have LHS" << eom;
999  throw 0;
1000  }
1001 
1002  codet havoc(ID_havoc_object);
1003  havoc.add_source_location() = function.source_location();
1004  havoc.copy_to_operands(arguments[0]);
1005 
1006  dest.add(goto_programt::make_other(havoc, function.source_location()));
1007  }
1008  else if(identifier == CPROVER_PREFIX "printf")
1009  {
1010  do_printf(lhs, function, arguments, dest);
1011  }
1012  else if(identifier == CPROVER_PREFIX "scanf")
1013  {
1014  do_scanf(lhs, function, arguments, dest);
1015  }
1016  else if(
1017  identifier == CPROVER_PREFIX "input" || identifier == "__CPROVER::input")
1018  {
1019  if(lhs.is_not_nil())
1020  {
1021  error().source_location = function.find_source_location();
1022  error() << identifier << " expected not to have LHS" << eom;
1023  throw 0;
1024  }
1025 
1026  do_input(function, arguments, dest);
1027  }
1028  else if(
1029  identifier == CPROVER_PREFIX "output" || identifier == "__CPROVER::output")
1030  {
1031  if(lhs.is_not_nil())
1032  {
1033  error().source_location = function.find_source_location();
1034  error() << identifier << " expected not to have LHS" << eom;
1035  throw 0;
1036  }
1037 
1038  do_output(function, arguments, dest);
1039  }
1040  else if(
1041  identifier == CPROVER_PREFIX "atomic_begin" ||
1042  identifier == "__CPROVER::atomic_begin" ||
1043  identifier == "java::org.cprover.CProver.atomicBegin:()V" ||
1044  identifier == "__VERIFIER_atomic_begin")
1045  {
1046  do_atomic_begin(lhs, function, arguments, dest);
1047  }
1048  else if(
1049  identifier == CPROVER_PREFIX "atomic_end" ||
1050  identifier == "__CPROVER::atomic_end" ||
1051  identifier == "java::org.cprover.CProver.atomicEnd:()V" ||
1052  identifier == "__VERIFIER_atomic_end")
1053  {
1054  do_atomic_end(lhs, function, arguments, dest);
1055  }
1056  else if(identifier == CPROVER_PREFIX "prob_biased_coin")
1057  {
1058  do_prob_coin(lhs, function, arguments, dest);
1059  }
1060  else if(identifier.starts_with(CPROVER_PREFIX "prob_uniform_"))
1061  {
1062  do_prob_uniform(lhs, function, arguments, dest);
1063  }
1064  else if(
1065  identifier.starts_with("nondet_") ||
1066  identifier.starts_with("__VERIFIER_nondet_"))
1067  {
1068  // make it a side effect if there is an LHS
1069  if(lhs.is_nil())
1070  return;
1071 
1072  exprt rhs;
1073 
1074  // We need to special-case for _Bool, which
1075  // can only be 0 or 1.
1076  if(lhs.type().id() == ID_c_bool)
1077  {
1078  rhs = side_effect_expr_nondett(bool_typet(), function.source_location());
1079  rhs.set(ID_C_identifier, identifier);
1080  rhs = typecast_exprt(rhs, lhs.type());
1081  }
1082  else
1083  {
1084  rhs = side_effect_expr_nondett(lhs.type(), function.source_location());
1085  rhs.set(ID_C_identifier, identifier);
1086  }
1087 
1088  code_assignt assignment(lhs, rhs);
1089  assignment.add_source_location() = function.source_location();
1090  copy(assignment, ASSIGN, dest);
1091  }
1092  else if(identifier.starts_with(CPROVER_PREFIX "uninterpreted_"))
1093  {
1094  // make it a side effect if there is an LHS
1095  if(lhs.is_nil())
1096  return;
1097 
1098  if(function.type().get_bool(ID_C_incomplete))
1099  {
1100  error().source_location = function.find_source_location();
1101  error() << "'" << identifier << "' is not declared, "
1102  << "missing type information required to construct call to "
1103  << "uninterpreted function" << eom;
1104  throw 0;
1105  }
1106 
1107  const code_typet &function_call_type = to_code_type(function.type());
1109  for(const auto &parameter : function_call_type.parameters())
1110  domain.push_back(parameter.type());
1111  mathematical_function_typet function_type{
1112  domain, function_call_type.return_type()};
1113  const function_application_exprt rhs(
1114  symbol_exprt{function.get_identifier(), function_type}, arguments);
1115 
1116  code_assignt assignment(lhs, rhs);
1117  assignment.add_source_location() = function.source_location();
1118  copy(assignment, ASSIGN, dest);
1119  }
1120  else if(identifier == CPROVER_PREFIX "array_equal")
1121  {
1122  do_array_op(ID_array_equal, lhs, function, arguments, dest);
1123  }
1124  else if(identifier == CPROVER_PREFIX "array_set")
1125  {
1126  do_array_op(ID_array_set, lhs, function, arguments, dest);
1127  }
1128  else if(identifier == CPROVER_PREFIX "array_copy")
1129  {
1130  do_array_op(ID_array_copy, lhs, function, arguments, dest);
1131  }
1132  else if(identifier == CPROVER_PREFIX "array_replace")
1133  {
1134  do_array_op(ID_array_replace, lhs, function, arguments, dest);
1135  }
1136  else if(
1137  identifier == "__assert_fail" || identifier == "_assert" ||
1138  identifier == "__assert_c99" || identifier == "_wassert")
1139  {
1140  // __assert_fail is Linux
1141  // These take four arguments:
1142  // "expression", "file.c", line, __func__
1143  // klibc has __assert_fail with 3 arguments
1144  // "expression", "file.c", line
1145 
1146  // MingW has
1147  // void _assert (const char*, const char*, int);
1148  // with three arguments:
1149  // "expression", "file.c", line
1150 
1151  // This has been seen in Solaris 11.
1152  // Signature:
1153  // void __assert_c99(
1154  // const char *desc, const char *file, int line, const char *func);
1155 
1156  // _wassert is Windows. The arguments are
1157  // L"expression", L"file.c", line
1158 
1159  if(arguments.size() != 4 && arguments.size() != 3)
1160  {
1161  error().source_location = function.find_source_location();
1162  error() << "'" << identifier << "' expected to have four arguments"
1163  << eom;
1164  throw 0;
1165  }
1166 
1167  const irep_idt description =
1168  "assertion " + id2string(get_string_constant(arguments[0]));
1169 
1170  source_locationt annotated_location = function.source_location();
1171  annotated_location.set("user-provided", true);
1172  annotated_location.set_property_class(ID_assertion);
1173  annotated_location.set_comment(description);
1174  dest.add(goto_programt::make_assertion(false_exprt(), annotated_location));
1175  // we ignore any LHS
1176  }
1177  else if(identifier == "__assert_rtn" || identifier == "__assert")
1178  {
1179  // __assert_rtn has been seen on MacOS;
1180  // __assert is FreeBSD and Solaris 11.
1181  // These take four arguments:
1182  // __func__, "file.c", line, "expression"
1183  // On Solaris 11, it's three arguments:
1184  // "expression", "file", line
1185 
1186  irep_idt description;
1187 
1188  if(arguments.size() == 4)
1189  {
1190  description = "assertion " + id2string(get_string_constant(arguments[3]));
1191  }
1192  else if(arguments.size() == 3)
1193  {
1194  description = "assertion " + id2string(get_string_constant(arguments[1]));
1195  }
1196  else
1197  {
1198  error().source_location = function.find_source_location();
1199  error() << "'" << identifier << "' expected to have four arguments"
1200  << eom;
1201  throw 0;
1202  }
1203 
1204  source_locationt annotated_location = function.source_location();
1205  annotated_location.set("user-provided", true);
1206  annotated_location.set_property_class(ID_assertion);
1207  annotated_location.set_comment(description);
1208  dest.add(goto_programt::make_assertion(false_exprt(), annotated_location));
1209  // we ignore any LHS
1210  }
1211  else if(
1212  identifier == "__assert_func" || identifier == "__assert2" ||
1213  identifier == "__assert13")
1214  {
1215  // __assert_func is newlib (used by, e.g., cygwin)
1216  // __assert2 is OpenBSD
1217  // __assert13 is NetBSD
1218  // These take four arguments:
1219  // "file.c", line, __func__, "expression"
1220  if(arguments.size() != 4)
1221  {
1222  error().source_location = function.find_source_location();
1223  error() << "'" << identifier << "' expected to have four arguments"
1224  << eom;
1225  throw 0;
1226  }
1227 
1228  irep_idt description;
1229  try
1230  {
1231  description = "assertion " + id2string(get_string_constant(arguments[3]));
1232  }
1233  catch(int)
1234  {
1235  // we might be building newlib, where __assert_func is passed
1236  // a pointer-typed symbol; the warning will still have been
1237  // printed
1238  description = "assertion";
1239  }
1240 
1241  source_locationt annotated_location = function.source_location();
1242  annotated_location.set("user-provided", true);
1243  annotated_location.set_property_class(ID_assertion);
1244  annotated_location.set_comment(description);
1245  dest.add(goto_programt::make_assertion(false_exprt(), annotated_location));
1246  // we ignore any LHS
1247  }
1248  else if(identifier == CPROVER_PREFIX "fence")
1249  {
1250  if(arguments.empty())
1251  {
1252  error().source_location = function.find_source_location();
1253  error() << "'" << identifier << "' expected to have at least one argument"
1254  << eom;
1255  throw 0;
1256  }
1257 
1258  codet fence(ID_fence);
1259 
1260  for(const auto &argument : arguments)
1261  fence.set(get_string_constant(argument), true);
1262 
1263  dest.add(goto_programt::make_other(fence, function.source_location()));
1264  }
1265  else if(identifier == "__builtin_prefetch")
1266  {
1267  // does nothing
1268  }
1269  else if(identifier == "__builtin_unreachable")
1270  {
1271  // says something like UNREACHABLE;
1272  }
1273  else if(identifier == ID_gcc_builtin_va_arg)
1274  {
1275  // This does two things.
1276  // 1) Return value of argument.
1277  // This is just dereferencing.
1278  // 2) Move list pointer to next argument.
1279  // This is just an increment.
1280 
1281  if(arguments.size() != 1)
1282  {
1283  error().source_location = function.find_source_location();
1284  error() << "'" << identifier << "' expected to have one argument" << eom;
1285  throw 0;
1286  }
1287 
1288  exprt list_arg = make_va_list(arguments[0]);
1289 
1290  if(lhs.is_not_nil())
1291  {
1292  exprt list_arg_cast = list_arg;
1293  if(
1294  list_arg.type().id() == ID_pointer &&
1295  to_pointer_type(list_arg.type()).base_type().id() == ID_empty)
1296  {
1297  list_arg_cast =
1299  }
1300 
1301  typet t = pointer_type(lhs.type());
1302  dereference_exprt rhs{
1303  typecast_exprt{dereference_exprt{std::move(list_arg_cast)}, t}};
1304  rhs.add_source_location() = function.source_location();
1305  dest.add(
1306  goto_programt::make_assignment(lhs, rhs, function.source_location()));
1307  }
1308 
1309  code_assignt assign{
1310  list_arg, plus_exprt{list_arg, from_integer(1, pointer_diff_type())}};
1311  assign.rhs().set(
1312  ID_C_va_arg_type, to_code_type(function.type()).return_type());
1314  std::move(assign), function.source_location()));
1315  }
1316  else if(identifier == "__builtin_va_copy")
1317  {
1318  if(arguments.size() != 2)
1319  {
1320  error().source_location = function.find_source_location();
1321  error() << "'" << identifier << "' expected to have two arguments" << eom;
1322  throw 0;
1323  }
1324 
1325  exprt dest_expr = make_va_list(arguments[0]);
1326  const typecast_exprt src_expr(arguments[1], dest_expr.type());
1327 
1328  if(!is_assignable(dest_expr))
1329  {
1330  error().source_location = dest_expr.find_source_location();
1331  error() << "va_copy argument expected to be lvalue" << eom;
1332  throw 0;
1333  }
1334 
1336  dest_expr, src_expr, function.source_location()));
1337  }
1338  else if(identifier == "__builtin_va_start" || identifier == "__va_start")
1339  {
1340  // Set the list argument to be the address of the
1341  // parameter argument.
1342  if(arguments.size() != 2)
1343  {
1344  error().source_location = function.find_source_location();
1345  error() << "'" << identifier << "' expected to have two arguments" << eom;
1346  throw 0;
1347  }
1348 
1349  exprt dest_expr = make_va_list(arguments[0]);
1350 
1351  if(!is_assignable(dest_expr))
1352  {
1353  error().source_location = dest_expr.find_source_location();
1354  error() << "va_start argument expected to be lvalue" << eom;
1355  throw 0;
1356  }
1357 
1358  if(
1359  dest_expr.type().id() == ID_pointer &&
1360  to_pointer_type(dest_expr.type()).base_type().id() == ID_empty)
1361  {
1362  dest_expr =
1364  }
1365 
1366  side_effect_exprt rhs{
1367  ID_va_start, dest_expr.type(), function.source_location()};
1368  rhs.add_to_operands(
1369  typecast_exprt{address_of_exprt{arguments[1]}, dest_expr.type()});
1370 
1372  std::move(dest_expr), std::move(rhs), function.source_location()));
1373  }
1374  else if(identifier == "__builtin_va_end")
1375  {
1376  // Invalidates the argument. We do so by setting it to NULL.
1377  if(arguments.size() != 1)
1378  {
1379  error().source_location = function.find_source_location();
1380  error() << "'" << identifier << "' expected to have one argument" << eom;
1381  throw 0;
1382  }
1383 
1384  exprt dest_expr = make_va_list(arguments[0]);
1385 
1386  if(!is_assignable(dest_expr))
1387  {
1388  error().source_location = dest_expr.find_source_location();
1389  error() << "va_end argument expected to be lvalue" << eom;
1390  throw 0;
1391  }
1392 
1393  // our __builtin_va_list is a pointer
1394  if(dest_expr.type().id() == ID_pointer)
1395  {
1396  const auto zero =
1397  zero_initializer(dest_expr.type(), function.source_location(), ns);
1398  CHECK_RETURN(zero.has_value());
1400  dest_expr, *zero, function.source_location()));
1401  }
1402  }
1403  else if(
1404  identifier == "__builtin_isgreater" ||
1405  identifier == "__builtin_isgreaterequal" ||
1406  identifier == "__builtin_isless" || identifier == "__builtin_islessequal" ||
1407  identifier == "__builtin_islessgreater" ||
1408  identifier == "__builtin_isunordered")
1409  {
1410  // these support two double or two float arguments; we call the
1411  // appropriate internal version
1412  if(
1413  arguments.size() != 2 ||
1414  (arguments[0].type() != double_type() &&
1415  arguments[0].type() != float_type()) ||
1416  (arguments[1].type() != double_type() &&
1417  arguments[1].type() != float_type()))
1418  {
1419  error().source_location = function.find_source_location();
1420  error() << "'" << identifier
1421  << "' expected to have two float/double arguments" << eom;
1422  throw 0;
1423  }
1424 
1425  exprt::operandst new_arguments = arguments;
1426 
1427  bool use_double = arguments[0].type() == double_type();
1428  if(arguments[0].type() != arguments[1].type())
1429  {
1430  if(use_double)
1431  {
1432  new_arguments[1] =
1433  typecast_exprt(new_arguments[1], arguments[0].type());
1434  }
1435  else
1436  {
1437  new_arguments[0] =
1438  typecast_exprt(new_arguments[0], arguments[1].type());
1439  use_double = true;
1440  }
1441  }
1442 
1443  code_typet f_type = to_code_type(function.type());
1444  f_type.remove_ellipsis();
1445  const typet &a_t = new_arguments[0].type();
1446  f_type.parameters() =
1448 
1449  // replace __builtin_ by CPROVER_PREFIX
1450  std::string name = CPROVER_PREFIX + id2string(identifier).substr(10);
1451  // append d or f for double/float
1452  name += use_double ? 'd' : 'f';
1453 
1455  ns.lookup(name).type == f_type,
1456  "builtin declaration should match constructed type");
1457 
1458  symbol_exprt new_function = function;
1459  new_function.set_identifier(name);
1460  new_function.type() = f_type;
1461 
1462  code_function_callt function_call(lhs, new_function, new_arguments);
1463  function_call.add_source_location() = function.source_location();
1464 
1465  copy(function_call, FUNCTION_CALL, dest);
1466  }
1467  else if(identifier == "alloca" || identifier == "__builtin_alloca")
1468  {
1469  do_alloca(lhs, function, arguments, dest, mode);
1470  }
1471  else
1472  {
1473  do_function_call_symbol(*symbol);
1474 
1475  // insert function call
1476  // use symbol->symbol_expr() to ensure we use the type from the symbol table
1477  code_function_callt function_call(
1478  lhs, symbol->symbol_expr().with_source_location(function), arguments);
1479  function_call.add_source_location() = function.source_location();
1480 
1481  // remove void-typed assignments, which may have been created when the
1482  // front-end was unable to detect them in type checking for a lack of
1483  // available declarations
1484  if(
1485  lhs.is_not_nil() &&
1486  to_code_type(symbol->type).return_type().id() == ID_empty)
1487  {
1488  function_call.lhs().make_nil();
1489  }
1490 
1491  copy(function_call, FUNCTION_CALL, dest);
1492  }
1493 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
Definition: arith_tools.cpp:20
exprt make_va_list(const exprt &expr)
floatbv_typet float_type()
Definition: c_types.cpp:177
empty_typet void_type()
Definition: c_types.cpp:245
signedbv_typet signed_int_type()
Definition: c_types.cpp:22
pointer_typet pointer_type(const typet &subtype)
Definition: c_types.cpp:235
signedbv_typet pointer_diff_type()
Definition: c_types.cpp:220
bitvector_typet char_type()
Definition: c_types.cpp:106
bitvector_typet c_index_type()
Definition: c_types.cpp:16
floatbv_typet double_type()
Definition: c_types.cpp:185
Operator to return the address of an object.
Definition: pointer_expr.h:540
Arrays with given size.
Definition: std_types.h:807
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:827
const exprt & size() const
Definition: std_types.h:840
The Boolean type.
Definition: std_types.h:36
A goto_instruction_codet representing an assignment in the program.
goto_instruction_codet representation of a function call statement.
A goto_instruction_codet representing the declaration that an input of a particular description has a...
A goto_instruction_codet representing the declaration that an output of a particular description has ...
Base type of functions.
Definition: std_types.h:583
std::vector< parametert > parameterst
Definition: std_types.h:585
const typet & return_type() const
Definition: std_types.h:689
void remove_ellipsis()
Definition: std_types.h:684
const parameterst & parameters() const
Definition: std_types.h:699
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:29
exprt & op0()
Definition: expr.h:133
void set_statement(const irep_idt &statement)
Definition: std_code_base.h:60
Operator to dereference a pointer.
Definition: pointer_expr.h:834
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool starts_with(const char *s) const
equivalent of as_string().starts_with(s)
Definition: dstring.h:95
The empty type.
Definition: std_types.h:51
Equality.
Definition: std_expr.h:1361
Base class for all expressions.
Definition: expr.h:56
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition: expr.cpp:147
std::vector< exprt > operandst
Definition: expr.h:58
bool is_one() const
Return whether the expression is a constant representing 1.
Definition: expr.cpp:96
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
Definition: expr.h:163
source_locationt & add_source_location()
Definition: expr.h:236
const source_locationt & source_location() const
Definition: expr.h:231
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
The Boolean constant false.
Definition: std_expr.h:3064
Application of (mathematical) function.
void do_havoc_slice(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
symbol_table_baset & symbol_table
void do_input(const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest)
void do_array_op(const irep_idt &id, const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
irep_idt get_string_constant(const exprt &expr)
void copy(const codet &code, goto_program_instruction_typet type, goto_programt &dest)
void do_prob_coin(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
struct goto_convertt::targetst targets
symbolt & new_tmp_symbol(const typet &type, const std::string &suffix, goto_programt &dest, const source_locationt &, const irep_idt &mode)
void do_atomic_end(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
virtual void do_function_call_symbol(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
add function calls to function queue for later processing
void clean_expr(exprt &expr, goto_programt &dest, const irep_idt &mode, bool result_is_used=true)
void do_output(const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest)
void cpp_new_initializer(const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest)
builds a goto program for object initialization after new
void do_printf(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
exprt get_array_argument(const exprt &src)
void do_alloca(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
alloca allocates memory that is freed when leaving the function (and not the block,...
void do_scanf(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
void convert(const codet &code, goto_programt &dest, const irep_idt &mode)
converts 'code' and appends the result to 'dest'
void do_atomic_begin(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
static void replace_new_object(const exprt &object, exprt &dest)
virtual void do_cpp_new(const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest)
void do_prob_uniform(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:945
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
static instructiont make_dead(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:971
void insert_before_swap(targett target)
Insertion that preserves jumps to "target".
Definition: goto_program.h:643
void destructive_insert(const_targett target, goto_programt &p)
Inserts the given program p before target.
Definition: goto_program.h:730
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
Definition: goto_program.h:722
static instructiont make_atomic_end(const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:990
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
targett insert_after(const_targett target)
Insertion after the instruction pointed-to by the given instruction iterator target.
Definition: goto_program.h:708
static instructiont make_other(const goto_instruction_codet &_code, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:957
static instructiont make_atomic_begin(const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:979
targett add(instructiont &&instruction)
Adds a given instruction at the end.
Definition: goto_program.h:739
static instructiont make_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:964
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:933
The trinary if-then-else operator.
Definition: std_expr.h:2370
Array index operator.
Definition: std_expr.h:1465
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:408
bool is_not_nil() const
Definition: irep.h:368
const irep_idt & id() const
Definition: irep.h:384
void make_nil()
Definition: irep.h:442
bool is_nil() const
Definition: irep.h:364
A type for mathematical functions (do not confuse with functions/methods in code)
std::vector< typet > domaint
source_locationt source_location
Definition: message.h:247
mstreamt & error() const
Definition: message.h:399
static eomt eom
Definition: message.h:297
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
The null pointer constant.
Definition: pointer_expr.h:909
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
A base class for a predicate that indicates that an address range is ok to read or write or both.
Definition: pointer_expr.h:920
A side_effect_exprt that returns a non-deterministically chosen value.
Definition: std_code.h:1520
An expression containing a side effect.
Definition: std_code.h:1450
const irep_idt & get_statement() const
Definition: std_code.h:1472
void set_comment(const irep_idt &comment)
void set_property_class(const irep_idt &property_class)
Expression to hold a symbol (variable)
Definition: std_expr.h:131
void set_identifier(const irep_idt &identifier)
Definition: std_expr.h:155
symbol_exprt & with_source_location(source_locationt location) &
Add the source location from location, if it is non-nil.
Definition: std_expr.h:166
const irep_idt & get_identifier() const
Definition: std_expr.h:160
Symbol table entry.
Definition: symbol.h:28
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
typet type
Type of symbol.
Definition: symbol.h:31
exprt value
Initial value of symbol.
Definition: symbol.h:34
const typet & subtype() const
Definition: type.h:187
Semantic type conversion.
Definition: std_expr.h:2068
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2076
The type of an expression, extends irept.
Definition: type.h:29
const source_locationt & source_location() const
Definition: type.h:72
source_locationt & add_source_location()
Definition: type.h:77
const exprt & op1() const =delete
#define CPROVER_PREFIX
std::optional< exprt > zero_initializer(const typet &type, const source_locationt &source_location, const namespacet &ns)
Create the equivalent of zero for type type.
Expression Initialization.
bool is_assignable(const exprt &expr)
Returns true iff the argument is one of the following:
Definition: expr_util.cpp:24
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
Definition: expr_util.cpp:219
Deprecated expression utility functions.
std::optional< typet > get_type(const format_tokent &token)
format_token_listt parse_format_string(const std::string &arg_string)
Format String Parser.
std::list< format_tokent > format_token_listt
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
Program Transformation.
@ FUNCTION_CALL
Definition: goto_program.h:49
@ ASSIGN
Definition: goto_program.h:46
@ OTHER
Definition: goto_program.h:37
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)
API to expression classes for 'mathematical' expressions.
Mathematical types.
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
exprt object_size(const exprt &pointer)
constant_exprt from_rational(const rationalt &a)
exprt simplify_expr(exprt src, const namespacet &ns)
BigInt mp_integer
Definition: smt_terms.h:17
#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
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
const codet & to_code(const exprt &expr)
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3037
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition: std_expr.h:426
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
bool is_constant(const typet &type)
This method tests, if the given typet is a constant.
Definition: std_types.h:29
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
Symbol table entry.
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208
#define size_type
Definition: unistd.c:347