CBMC
goto_check_c.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Checks for Errors in C/C++ Programs
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "goto_check_c.h"
13 
14 #include <util/arith_tools.h>
15 #include <util/array_name.h>
16 #include <util/bitvector_expr.h>
17 #include <util/c_types.h>
18 #include <util/config.h>
19 #include <util/cprover_prefix.h>
20 #include <util/expr_util.h>
21 #include <util/find_symbols.h>
22 #include <util/floatbv_expr.h>
23 #include <util/ieee_float.h>
24 #include <util/invariant.h>
25 #include <util/mathematical_expr.h>
26 #include <util/message.h>
27 #include <util/options.h>
28 #include <util/pointer_expr.h>
31 #include <util/simplify_expr.h>
32 #include <util/std_code.h>
33 #include <util/std_expr.h>
34 
37 
39 #include <langapi/language.h>
40 #include <langapi/mode.h>
41 
42 #include "c_expr.h"
43 
44 #include <algorithm>
45 
47 {
48 public:
50  const namespacet &_ns,
51  const optionst &_options,
52  message_handlert &_message_handler)
53  : ns(_ns), local_bitvector_analysis(nullptr), log(_message_handler)
54  {
55  enable_bounds_check = _options.get_bool_option("bounds-check");
56  enable_pointer_check = _options.get_bool_option("pointer-check");
57  enable_memory_leak_check = _options.get_bool_option("memory-leak-check");
59  _options.get_bool_option("memory-cleanup-check");
60  enable_div_by_zero_check = _options.get_bool_option("div-by-zero-check");
62  _options.get_bool_option("float-div-by-zero-check");
63  enable_enum_range_check = _options.get_bool_option("enum-range-check");
65  _options.get_bool_option("signed-overflow-check");
67  _options.get_bool_option("unsigned-overflow-check");
69  _options.get_bool_option("pointer-overflow-check");
70  enable_conversion_check = _options.get_bool_option("conversion-check");
72  _options.get_bool_option("undefined-shift-check");
74  _options.get_bool_option("float-overflow-check");
75  enable_simplify = _options.get_bool_option("simplify");
76  enable_nan_check = _options.get_bool_option("nan-check");
77  retain_trivial = _options.get_bool_option("retain-trivial-checks");
78  enable_assert_to_assume = _options.get_bool_option("assert-to-assume");
79  error_labels = _options.get_list_option("error-label");
81  _options.get_bool_option("pointer-primitive-check");
82  }
83 
85 
86  void goto_check(
87  const irep_idt &function_identifier,
88  goto_functiont &goto_function);
89 
95  void collect_allocations(const goto_functionst &goto_functions);
96 
97 protected:
98  const namespacet &ns;
99  std::unique_ptr<local_bitvector_analysist> local_bitvector_analysis;
102 
103  using guardt = std::function<exprt(exprt)>;
104  const guardt identity = [](exprt expr) { return expr; };
105 
107 
113  void check_rec_address(const exprt &expr, const guardt &guard);
114 
122  void check_rec_logical_op(const exprt &expr, const guardt &guard);
123 
130  void check_rec_if(const if_exprt &if_expr, const guardt &guard);
131 
142  bool check_rec_member(const member_exprt &member, const guardt &guard);
143 
148  void check_rec_div(const div_exprt &div_expr, const guardt &guard);
149 
154  void check_rec_arithmetic_op(const exprt &expr, const guardt &guard);
155 
161  void check_rec(const exprt &expr, const guardt &guard);
162 
165  void check(const exprt &expr);
166 
167  struct conditiont
168  {
169  conditiont(const exprt &_assertion, const std::string &_description)
170  : assertion(_assertion), description(_description)
171  {
172  }
173 
175  std::string description;
176  };
177 
178  using conditionst = std::list<conditiont>;
179 
180  void bounds_check(const exprt &, const guardt &);
181  void bounds_check_index(const index_exprt &, const guardt &);
182  void bounds_check_bit_count(const unary_exprt &, const guardt &);
183  void div_by_zero_check(const div_exprt &, const guardt &);
184  void float_div_by_zero_check(const div_exprt &, const guardt &);
185  void mod_by_zero_check(const mod_exprt &, const guardt &);
186  void mod_overflow_check(const mod_exprt &, const guardt &);
187  void enum_range_check(const exprt &, const guardt &);
188  void undefined_shift_check(const shift_exprt &, const guardt &);
189  void pointer_rel_check(const binary_exprt &, const guardt &);
190  void pointer_overflow_check(const exprt &, const guardt &);
191  void memory_leak_check(const irep_idt &function_id);
192 
199  const dereference_exprt &expr,
200  const exprt &src_expr,
201  const guardt &guard);
202 
208  void pointer_primitive_check(const exprt &expr, const guardt &guard);
209 
216  bool requires_pointer_primitive_check(const exprt &expr);
217 
218  std::optional<goto_check_ct::conditiont>
219  get_pointer_is_null_condition(const exprt &address, const exprt &size);
221  const exprt &address,
222  const exprt &size);
224  const exprt &pointer,
225  const exprt &size);
226 
228  const exprt &address,
229  const exprt &size);
230  void integer_overflow_check(const exprt &, const guardt &);
231  void conversion_check(const exprt &, const guardt &);
232  void float_overflow_check(const exprt &, const guardt &);
233  void nan_check(const exprt &, const guardt &);
234 
235  std::string array_name(const exprt &);
236 
246  const exprt &asserted_expr,
247  const std::string &comment,
248  const std::string &property_class,
249  const source_locationt &source_location,
250  const exprt &src_expr,
251  const guardt &guard);
252 
254  typedef std::set<std::pair<exprt, exprt>> assertionst;
256 
261  void invalidate(const exprt &lhs);
262 
281 
283  std::map<irep_idt, bool *> name_to_flag{
284  {"bounds-check", &enable_bounds_check},
285  {"pointer-check", &enable_pointer_check},
286  {"memory-leak-check", &enable_memory_leak_check},
287  {"memory-cleanup-check", &enable_memory_cleanup_check},
288  {"div-by-zero-check", &enable_div_by_zero_check},
289  {"float-div-by-zero-check", &enable_float_div_by_zero_check},
290  {"enum-range-check", &enable_enum_range_check},
291  {"signed-overflow-check", &enable_signed_overflow_check},
292  {"unsigned-overflow-check", &enable_unsigned_overflow_check},
293  {"pointer-overflow-check", &enable_pointer_overflow_check},
294  {"conversion-check", &enable_conversion_check},
295  {"undefined-shift-check", &enable_undefined_shift_check},
296  {"float-overflow-check", &enable_float_overflow_check},
297  {"nan-check", &enable_nan_check},
298  {"pointer-primitive-check", &enable_pointer_primitive_check}};
299 
302 
303  // the first element of the pair is the base address,
304  // and the second is the size of the region
305  typedef std::pair<exprt, exprt> allocationt;
306  typedef std::list<allocationt> allocationst;
308 
310 
313  void add_active_named_check_pragmas(source_locationt &source_location) const;
314 
317  void
319 
321  typedef enum
322  {
325  CHECKED
327 
329  using named_check_statust = std::optional<std::pair<irep_idt, check_statust>>;
330 
339  named_check_statust match_named_check(const irep_idt &named_check) const;
340 };
341 
350 {
351 public:
354  {
355  }
356 
362  void set_flag(bool &flag, bool new_value, const irep_idt &flag_name)
363  {
364  // make this a no-op if the flag is disabled
365  if(disabled_flags.find(&flag) != disabled_flags.end())
366  return;
367 
368  // detect double sets
369  INVARIANT(
370  flags_to_reset.find(&flag) == flags_to_reset.end(),
371  "Flag " + id2string(flag_name) + " set twice at \n" +
373  if(flag != new_value)
374  {
375  flags_to_reset[&flag] = flag;
376  flag = new_value;
377  }
378  }
379 
384  void disable_flag(bool &flag, const irep_idt &flag_name)
385  {
386  INVARIANT(
387  disabled_flags.find(&flag) == disabled_flags.end(),
388  "Flag " + id2string(flag_name) + " disabled twice at \n" +
390 
391  disabled_flags.insert(&flag);
392 
393  // If the flag has not already been set,
394  // we store its current value in the reset map.
395  // Otherwise, the reset map already holds
396  // the initial value we want to reset it to, keep it as is.
397  if(flags_to_reset.find(&flag) == flags_to_reset.end())
398  flags_to_reset[&flag] = flag;
399 
400  // set the flag to false in all cases.
401  flag = false;
402  }
403 
407  {
408  for(const auto &flag_pair : flags_to_reset)
409  *flag_pair.first = flag_pair.second;
410  }
411 
412 private:
414  std::map<bool *, bool> flags_to_reset;
415  std::set<bool *> disabled_flags;
416 };
417 
418 static exprt implication(exprt lhs, exprt rhs)
419 {
420  // rewrite a => (b => c) to (a && b) => c
421  if(rhs.id() == ID_implies)
422  {
423  const auto &rhs_implication = to_implies_expr(rhs);
424  return implies_exprt(
425  and_exprt(std::move(lhs), rhs_implication.lhs()), rhs_implication.rhs());
426  }
427  else
428  {
429  return implies_exprt(std::move(lhs), std::move(rhs));
430  }
431 }
432 
434 {
435  for(const auto &gf_entry : goto_functions.function_map)
436  {
437  for(const auto &instruction : gf_entry.second.body.instructions)
438  {
439  if(!instruction.is_function_call())
440  continue;
441 
442  const auto &function = instruction.call_function();
443  if(
444  function.id() != ID_symbol ||
445  to_symbol_expr(function).get_identifier() != CPROVER_PREFIX
446  "allocated_memory")
447  continue;
448 
449  const code_function_callt::argumentst &args =
450  instruction.call_arguments();
451  if(
452  args.size() != 2 || args[0].type().id() != ID_unsignedbv ||
453  args[1].type().id() != ID_unsignedbv)
454  throw "expected two unsigned arguments to " CPROVER_PREFIX
455  "allocated_memory";
456 
458  args[0].type() == args[1].type(),
459  "arguments of allocated_memory must have same type");
460  allocations.push_back({args[0], args[1]});
461  }
462  }
463 }
464 
466 {
467  if(lhs.id() == ID_index)
468  invalidate(to_index_expr(lhs).array());
469  else if(lhs.id() == ID_member)
470  invalidate(to_member_expr(lhs).struct_op());
471  else if(lhs.id() == ID_symbol)
472  {
473  // clear all assertions about 'symbol'
474  const irep_idt &lhs_id = to_symbol_expr(lhs).get_identifier();
475 
476  for(auto it = assertions.begin(); it != assertions.end();)
477  {
478  if(
479  has_symbol_expr(it->second, lhs_id, false) ||
480  has_subexpr(it->second, ID_dereference))
481  {
482  it = assertions.erase(it);
483  }
484  else
485  ++it;
486  }
487  }
488  else
489  {
490  // give up, clear all
491  assertions.clear();
492  }
493 }
494 
496  const div_exprt &expr,
497  const guardt &guard)
498 {
500  return;
501 
502  // add divison by zero subgoal
503 
504  exprt zero = from_integer(0, expr.op1().type());
505  const notequal_exprt inequality(expr.op1(), std::move(zero));
506 
508  inequality,
509  "division by zero",
510  "division-by-zero",
511  expr.find_source_location(),
512  expr,
513  guard);
514 }
515 
517  const div_exprt &expr,
518  const guardt &guard)
519 {
521  return;
522 
523  // add divison by zero subgoal
524 
525  exprt zero = from_integer(0, expr.op1().type());
526  const notequal_exprt inequality(expr.op1(), std::move(zero));
527 
529  inequality,
530  "floating-point division by zero",
531  "float-division-by-zero",
532  expr.find_source_location(),
533  expr,
534  guard);
535 }
536 
538 {
540  return;
541 
542  // we might be looking at a lowered enum_is_in_range_exprt, skip over these
543  const auto &pragmas = expr.source_location().get_pragmas();
544  for(const auto &d : pragmas)
545  {
546  if(d.first == "disable:enum-range-check")
547  return;
548  }
549 
550  const exprt check = enum_is_in_range_exprt{expr}.lower(ns);
551 
553  check,
554  "enum range check",
555  "enum-range-check",
556  expr.find_source_location(),
557  expr,
558  guard);
559 }
560 
562  const shift_exprt &expr,
563  const guardt &guard)
564 {
566  return;
567 
568  // Undefined for all types and shifts if distance exceeds width,
569  // and also undefined for negative distances.
570 
571  const typet &distance_type = expr.distance().type();
572 
573  if(distance_type.id() == ID_signedbv)
574  {
575  binary_relation_exprt inequality(
576  expr.distance(), ID_ge, from_integer(0, distance_type));
577 
579  inequality,
580  "shift distance is negative",
581  "undefined-shift",
582  expr.find_source_location(),
583  expr,
584  guard);
585  }
586 
587  const typet &op_type = expr.op().type();
588 
589  if(op_type.id() == ID_unsignedbv || op_type.id() == ID_signedbv)
590  {
591  exprt width_expr =
592  from_integer(to_bitvector_type(op_type).get_width(), distance_type);
593 
595  binary_relation_exprt(expr.distance(), ID_lt, std::move(width_expr)),
596  "shift distance too large",
597  "undefined-shift",
598  expr.find_source_location(),
599  expr,
600  guard);
601 
602  if(op_type.id() == ID_signedbv && expr.id() == ID_shl)
603  {
604  binary_relation_exprt inequality(
605  expr.op(), ID_ge, from_integer(0, op_type));
606 
608  inequality,
609  "shift operand is negative",
610  "undefined-shift",
611  expr.find_source_location(),
612  expr,
613  guard);
614  }
615  }
616  else
617  {
619  false_exprt(),
620  "shift of non-integer type",
621  "undefined-shift",
622  expr.find_source_location(),
623  expr,
624  guard);
625  }
626 }
627 
629  const mod_exprt &expr,
630  const guardt &guard)
631 {
633  return;
634 
635  // add divison by zero subgoal
636 
637  exprt zero = from_integer(0, expr.divisor().type());
638  const notequal_exprt inequality(expr.divisor(), std::move(zero));
639 
641  inequality,
642  "division by zero",
643  "division-by-zero",
644  expr.find_source_location(),
645  expr,
646  guard);
647 }
648 
651  const mod_exprt &expr,
652  const guardt &guard)
653 {
655  return;
656 
657  const auto &type = expr.type();
658 
659  if(type.id() == ID_signedbv)
660  {
661  // INT_MIN % -1 is, in principle, defined to be zero in
662  // ANSI C, C99, C++98, and C++11. Most compilers, however,
663  // fail to produce 0, and in some cases generate an exception.
664  // C11 explicitly makes this case undefined.
665 
666  notequal_exprt int_min_neq(
667  expr.op0(), to_signedbv_type(type).smallest_expr());
668 
669  notequal_exprt minus_one_neq(
670  expr.op1(), from_integer(-1, expr.op1().type()));
671 
673  or_exprt(int_min_neq, minus_one_neq),
674  "result of signed mod is not representable",
675  "overflow",
676  expr.find_source_location(),
677  expr,
678  guard);
679  }
680 }
681 
683 {
685  return;
686 
687  // First, check type.
688  const typet &type = expr.type();
689 
690  if(type.id() != ID_signedbv && type.id() != ID_unsignedbv)
691  return;
692 
693  if(expr.id() == ID_typecast)
694  {
695  const auto &op = to_typecast_expr(expr).op();
696 
697  // conversion to signed int may overflow
698  const typet &old_type = op.type();
699 
700  if(type.id() == ID_signedbv)
701  {
702  std::size_t new_width = to_signedbv_type(type).get_width();
703 
704  if(old_type.id() == ID_signedbv) // signed -> signed
705  {
706  std::size_t old_width = to_signedbv_type(old_type).get_width();
707  if(new_width >= old_width)
708  return; // always ok
709 
710  const binary_relation_exprt no_overflow_upper(
711  op, ID_le, from_integer(power(2, new_width - 1) - 1, old_type));
712 
713  const binary_relation_exprt no_overflow_lower(
714  op, ID_ge, from_integer(-power(2, new_width - 1), old_type));
715 
717  and_exprt(no_overflow_lower, no_overflow_upper),
718  "arithmetic overflow on signed type conversion",
719  "overflow",
720  expr.find_source_location(),
721  expr,
722  guard);
723  }
724  else if(old_type.id() == ID_unsignedbv) // unsigned -> signed
725  {
726  std::size_t old_width = to_unsignedbv_type(old_type).get_width();
727  if(new_width >= old_width + 1)
728  return; // always ok
729 
730  const binary_relation_exprt no_overflow_upper(
731  op, ID_le, from_integer(power(2, new_width - 1) - 1, old_type));
732 
734  no_overflow_upper,
735  "arithmetic overflow on unsigned to signed type conversion",
736  "overflow",
737  expr.find_source_location(),
738  expr,
739  guard);
740  }
741  else if(old_type.id() == ID_floatbv) // float -> signed
742  {
743  // Note that the fractional part is truncated!
744  ieee_floatt upper(to_floatbv_type(old_type));
745  upper.from_integer(power(2, new_width - 1));
746  const binary_relation_exprt no_overflow_upper(
747  op, ID_lt, upper.to_expr());
748 
749  ieee_floatt lower(to_floatbv_type(old_type));
750  lower.from_integer(-power(2, new_width - 1) - 1);
751  const binary_relation_exprt no_overflow_lower(
752  op, ID_gt, lower.to_expr());
753 
755  and_exprt(no_overflow_lower, no_overflow_upper),
756  "arithmetic overflow on float to signed integer type conversion",
757  "overflow",
758  expr.find_source_location(),
759  expr,
760  guard);
761  }
762  }
763  else if(type.id() == ID_unsignedbv)
764  {
765  std::size_t new_width = to_unsignedbv_type(type).get_width();
766 
767  if(old_type.id() == ID_signedbv) // signed -> unsigned
768  {
769  std::size_t old_width = to_signedbv_type(old_type).get_width();
770 
771  if(new_width >= old_width - 1)
772  {
773  // only need lower bound check
774  const binary_relation_exprt no_overflow_lower(
775  op, ID_ge, from_integer(0, old_type));
776 
778  no_overflow_lower,
779  "arithmetic overflow on signed to unsigned type conversion",
780  "overflow",
781  expr.find_source_location(),
782  expr,
783  guard);
784  }
785  else
786  {
787  // need both
788  const binary_relation_exprt no_overflow_upper(
789  op, ID_le, from_integer(power(2, new_width) - 1, old_type));
790 
791  const binary_relation_exprt no_overflow_lower(
792  op, ID_ge, from_integer(0, old_type));
793 
795  and_exprt(no_overflow_lower, no_overflow_upper),
796  "arithmetic overflow on signed to unsigned type conversion",
797  "overflow",
798  expr.find_source_location(),
799  expr,
800  guard);
801  }
802  }
803  else if(old_type.id() == ID_unsignedbv) // unsigned -> unsigned
804  {
805  std::size_t old_width = to_unsignedbv_type(old_type).get_width();
806  if(new_width >= old_width)
807  return; // always ok
808 
809  const binary_relation_exprt no_overflow_upper(
810  op, ID_le, from_integer(power(2, new_width) - 1, old_type));
811 
813  no_overflow_upper,
814  "arithmetic overflow on unsigned to unsigned type conversion",
815  "overflow",
816  expr.find_source_location(),
817  expr,
818  guard);
819  }
820  else if(old_type.id() == ID_floatbv) // float -> unsigned
821  {
822  // Note that the fractional part is truncated!
823  ieee_floatt upper(to_floatbv_type(old_type));
824  upper.from_integer(power(2, new_width));
825  const binary_relation_exprt no_overflow_upper(
826  op, ID_lt, upper.to_expr());
827 
828  ieee_floatt lower(to_floatbv_type(old_type));
829  lower.from_integer(-1);
830  const binary_relation_exprt no_overflow_lower(
831  op, ID_gt, lower.to_expr());
832 
834  and_exprt(no_overflow_lower, no_overflow_upper),
835  "arithmetic overflow on float to unsigned integer type conversion",
836  "overflow",
837  expr.find_source_location(),
838  expr,
839  guard);
840  }
841  }
842  }
843 }
844 
846  const exprt &expr,
847  const guardt &guard)
848 {
850  return;
851 
852  // First, check type.
853  const typet &type = expr.type();
854 
855  if(type.id() == ID_signedbv && !enable_signed_overflow_check)
856  return;
857 
858  if(type.id() == ID_unsignedbv && !enable_unsigned_overflow_check)
859  return;
860 
861  // add overflow subgoal
862 
863  if(expr.id() == ID_div)
864  {
865  // undefined for signed division INT_MIN/-1
866  if(type.id() == ID_signedbv)
867  {
868  const auto &div_expr = to_div_expr(expr);
869 
870  equal_exprt int_min_eq(
871  div_expr.dividend(), to_signedbv_type(type).smallest_expr());
872 
873  equal_exprt minus_one_eq(div_expr.divisor(), from_integer(-1, type));
874 
876  not_exprt(and_exprt(int_min_eq, minus_one_eq)),
877  "arithmetic overflow on signed division",
878  "overflow",
879  expr.find_source_location(),
880  expr,
881  guard);
882  }
883 
884  return;
885  }
886  else if(expr.id() == ID_unary_minus)
887  {
888  if(type.id() == ID_signedbv)
889  {
890  // overflow on unary- on signed integers can only happen with the
891  // smallest representable number 100....0
892 
893  equal_exprt int_min_eq(
894  to_unary_minus_expr(expr).op(), to_signedbv_type(type).smallest_expr());
895 
897  not_exprt(int_min_eq),
898  "arithmetic overflow on signed unary minus",
899  "overflow",
900  expr.find_source_location(),
901  expr,
902  guard);
903  }
904  else if(type.id() == ID_unsignedbv)
905  {
906  // Overflow on unary- on unsigned integers happens for all operands
907  // that are not zero.
908 
909  notequal_exprt not_eq_zero(
910  to_unary_minus_expr(expr).op(), to_unsignedbv_type(type).zero_expr());
911 
913  not_eq_zero,
914  "arithmetic overflow on unsigned unary minus",
915  "overflow",
916  expr.find_source_location(),
917  expr,
918  guard);
919  }
920 
921  return;
922  }
923  else if(expr.id() == ID_shl)
924  {
925  if(type.id() == ID_signedbv)
926  {
927  const auto &shl_expr = to_shl_expr(expr);
928  const auto &op = shl_expr.op();
929  const auto &op_type = to_signedbv_type(type);
930  const auto op_width = op_type.get_width();
931  const auto &distance = shl_expr.distance();
932  const auto &distance_type = distance.type();
933 
934  // a left shift of a negative value is undefined;
935  // yet this isn't an overflow
936  exprt neg_value_shift;
937 
938  if(op_type.id() == ID_unsignedbv)
939  neg_value_shift = false_exprt();
940  else
941  neg_value_shift =
942  binary_relation_exprt(op, ID_lt, from_integer(0, op_type));
943 
944  // a shift with negative distance is undefined;
945  // yet this isn't an overflow
946  exprt neg_dist_shift;
947 
948  if(distance_type.id() == ID_unsignedbv)
949  neg_dist_shift = false_exprt();
950  else
951  {
952  neg_dist_shift = binary_relation_exprt(
953  distance, ID_lt, from_integer(0, distance_type));
954  }
955 
956  // shifting a non-zero value by more than its width is undefined;
957  // yet this isn't an overflow
958  const exprt dist_too_large = binary_predicate_exprt(
959  distance, ID_gt, from_integer(op_width, distance_type));
960 
961  const exprt op_zero = equal_exprt(op, from_integer(0, op_type));
962 
963  auto new_type = to_bitvector_type(op_type);
964  new_type.set_width(op_width * 2);
965 
966  const exprt op_ext = typecast_exprt(op, new_type);
967 
968  const exprt op_ext_shifted = shl_exprt(op_ext, distance);
969 
970  // The semantics of signed left shifts are contentious for the case
971  // that a '1' is shifted into the signed bit.
972  // Assuming 32-bit integers, 1<<31 is implementation-defined
973  // in ANSI C and C++98, but is explicitly undefined by C99,
974  // C11 and C++11.
975  bool allow_shift_into_sign_bit = true;
976 
977  if(mode == ID_C)
978  {
979  if(
982  {
983  allow_shift_into_sign_bit = false;
984  }
985  }
986  else if(mode == ID_cpp)
987  {
988  if(
992  {
993  allow_shift_into_sign_bit = false;
994  }
995  }
996 
997  const unsigned number_of_top_bits =
998  allow_shift_into_sign_bit ? op_width : op_width + 1;
999 
1000  const exprt top_bits = extractbits_exprt(
1001  op_ext_shifted,
1002  new_type.get_width() - 1,
1003  new_type.get_width() - number_of_top_bits,
1004  unsignedbv_typet(number_of_top_bits));
1005 
1006  const exprt top_bits_zero =
1007  equal_exprt(top_bits, from_integer(0, top_bits.type()));
1008 
1009  // a negative distance shift isn't an overflow;
1010  // a negative value shift isn't an overflow;
1011  // a shift that's too far isn't an overflow;
1012  // a shift of zero isn't overflow;
1013  // else check the top bits
1015  disjunction(
1016  {neg_value_shift,
1017  neg_dist_shift,
1018  dist_too_large,
1019  op_zero,
1020  top_bits_zero}),
1021  "arithmetic overflow on signed shl",
1022  "overflow",
1023  expr.find_source_location(),
1024  expr,
1025  guard);
1026  }
1027 
1028  return;
1029  }
1030 
1031  multi_ary_exprt overflow(
1032  "overflow-" + expr.id_string(), expr.operands(), bool_typet());
1033 
1034  if(expr.operands().size() >= 3)
1035  {
1036  // The overflow checks are binary!
1037  // We break these up.
1038 
1039  for(std::size_t i = 1; i < expr.operands().size(); i++)
1040  {
1041  exprt tmp;
1042 
1043  if(i == 1)
1044  tmp = to_multi_ary_expr(expr).op0();
1045  else
1046  {
1047  tmp = expr;
1048  tmp.operands().resize(i);
1049  }
1050 
1051  std::string kind = type.id() == ID_unsignedbv ? "unsigned" : "signed";
1052 
1054  not_exprt{binary_overflow_exprt{tmp, expr.id(), expr.operands()[i]}},
1055  "arithmetic overflow on " + kind + " " + expr.id_string(),
1056  "overflow",
1057  expr.find_source_location(),
1058  expr,
1059  guard);
1060  }
1061  }
1062  else if(expr.operands().size() == 2)
1063  {
1064  std::string kind = type.id() == ID_unsignedbv ? "unsigned" : "signed";
1065 
1066  const binary_exprt &bexpr = to_binary_expr(expr);
1068  not_exprt{binary_overflow_exprt{bexpr.lhs(), expr.id(), bexpr.rhs()}},
1069  "arithmetic overflow on " + kind + " " + expr.id_string(),
1070  "overflow",
1071  expr.find_source_location(),
1072  expr,
1073  guard);
1074  }
1075  else
1076  {
1077  PRECONDITION(expr.id() == ID_unary_minus);
1078 
1079  std::string kind = type.id() == ID_unsignedbv ? "unsigned" : "signed";
1080 
1083  "arithmetic overflow on " + kind + " " + expr.id_string(),
1084  "overflow",
1085  expr.find_source_location(),
1086  expr,
1087  guard);
1088  }
1089 }
1090 
1092 {
1094  return;
1095 
1096  // First, check type.
1097  const typet &type = expr.type();
1098 
1099  if(type.id() != ID_floatbv)
1100  return;
1101 
1102  // add overflow subgoal
1103 
1104  if(expr.id() == ID_typecast)
1105  {
1106  // Can overflow if casting from larger
1107  // to smaller type.
1108  const auto &op = to_typecast_expr(expr).op();
1109  if(op.type().id() == ID_floatbv)
1110  {
1111  // float-to-float
1112  or_exprt overflow_check{isinf_exprt(op), not_exprt(isinf_exprt(expr))};
1113 
1115  std::move(overflow_check),
1116  "arithmetic overflow on floating-point typecast",
1117  "overflow",
1118  expr.find_source_location(),
1119  expr,
1120  guard);
1121  }
1122  else
1123  {
1124  // non-float-to-float
1126  not_exprt(isinf_exprt(expr)),
1127  "arithmetic overflow on floating-point typecast",
1128  "overflow",
1129  expr.find_source_location(),
1130  expr,
1131  guard);
1132  }
1133 
1134  return;
1135  }
1136  else if(expr.id() == ID_div)
1137  {
1138  // Can overflow if dividing by something small
1139  or_exprt overflow_check(
1140  isinf_exprt(to_div_expr(expr).dividend()), not_exprt(isinf_exprt(expr)));
1141 
1143  std::move(overflow_check),
1144  "arithmetic overflow on floating-point division",
1145  "overflow",
1146  expr.find_source_location(),
1147  expr,
1148  guard);
1149 
1150  return;
1151  }
1152  else if(expr.id() == ID_mod)
1153  {
1154  // Can't overflow
1155  return;
1156  }
1157  else if(expr.id() == ID_unary_minus)
1158  {
1159  // Can't overflow
1160  return;
1161  }
1162  else if(expr.id() == ID_plus || expr.id() == ID_mult || expr.id() == ID_minus)
1163  {
1164  if(expr.operands().size() == 2)
1165  {
1166  // Can overflow
1167  or_exprt overflow_check(
1168  isinf_exprt(to_binary_expr(expr).op0()),
1169  isinf_exprt(to_binary_expr(expr).op1()),
1170  not_exprt(isinf_exprt(expr)));
1171 
1172  std::string kind = expr.id() == ID_plus
1173  ? "addition"
1174  : expr.id() == ID_minus
1175  ? "subtraction"
1176  : expr.id() == ID_mult ? "multiplication" : "";
1177 
1179  std::move(overflow_check),
1180  "arithmetic overflow on floating-point " + kind,
1181  "overflow",
1182  expr.find_source_location(),
1183  expr,
1184  guard);
1185 
1186  return;
1187  }
1188  else if(expr.operands().size() >= 3)
1189  {
1190  DATA_INVARIANT(expr.id() != ID_minus, "minus expression must be binary");
1191 
1192  // break up
1194  return;
1195  }
1196  }
1197 }
1198 
1199 void goto_check_ct::nan_check(const exprt &expr, const guardt &guard)
1200 {
1201  if(!enable_nan_check)
1202  return;
1203 
1204  // first, check type
1205  if(expr.type().id() != ID_floatbv)
1206  return;
1207 
1208  if(
1209  expr.id() != ID_plus && expr.id() != ID_mult && expr.id() != ID_div &&
1210  expr.id() != ID_minus)
1211  return;
1212 
1213  // add NaN subgoal
1214 
1215  exprt isnan;
1216 
1217  if(expr.id() == ID_div)
1218  {
1219  const auto &div_expr = to_div_expr(expr);
1220 
1221  // there a two ways to get a new NaN on division:
1222  // 0/0 = NaN and x/inf = NaN
1223  // (note that x/0 = +-inf for x!=0 and x!=inf)
1224  const and_exprt zero_div_zero(
1226  div_expr.op0(), from_integer(0, div_expr.dividend().type())),
1228  div_expr.op1(), from_integer(0, div_expr.divisor().type())));
1229 
1230  const isinf_exprt div_inf(div_expr.op1());
1231 
1232  isnan = or_exprt(zero_div_zero, div_inf);
1233  }
1234  else if(expr.id() == ID_mult)
1235  {
1236  if(expr.operands().size() >= 3)
1237  return nan_check(make_binary(expr), guard);
1238 
1239  const auto &mult_expr = to_mult_expr(expr);
1240 
1241  // Inf * 0 is NaN
1242  const and_exprt inf_times_zero(
1243  isinf_exprt(mult_expr.op0()),
1245  mult_expr.op1(), from_integer(0, mult_expr.op1().type())));
1246 
1247  const and_exprt zero_times_inf(
1249  mult_expr.op1(), from_integer(0, mult_expr.op1().type())),
1250  isinf_exprt(mult_expr.op0()));
1251 
1252  isnan = or_exprt(inf_times_zero, zero_times_inf);
1253  }
1254  else if(expr.id() == ID_plus)
1255  {
1256  if(expr.operands().size() >= 3)
1257  return nan_check(make_binary(expr), guard);
1258 
1259  const auto &plus_expr = to_plus_expr(expr);
1260 
1261  // -inf + +inf = NaN and +inf + -inf = NaN,
1262  // i.e., signs differ
1263  ieee_float_spect spec = ieee_float_spect(to_floatbv_type(plus_expr.type()));
1264  exprt plus_inf = ieee_floatt::plus_infinity(spec).to_expr();
1265  exprt minus_inf = ieee_floatt::minus_infinity(spec).to_expr();
1266 
1267  isnan = or_exprt(
1268  and_exprt(
1269  equal_exprt(plus_expr.op0(), minus_inf),
1270  equal_exprt(plus_expr.op1(), plus_inf)),
1271  and_exprt(
1272  equal_exprt(plus_expr.op0(), plus_inf),
1273  equal_exprt(plus_expr.op1(), minus_inf)));
1274  }
1275  else if(expr.id() == ID_minus)
1276  {
1277  // +inf - +inf = NaN and -inf - -inf = NaN,
1278  // i.e., signs match
1279 
1280  const auto &minus_expr = to_minus_expr(expr);
1281 
1282  ieee_float_spect spec =
1283  ieee_float_spect(to_floatbv_type(minus_expr.type()));
1284  exprt plus_inf = ieee_floatt::plus_infinity(spec).to_expr();
1285  exprt minus_inf = ieee_floatt::minus_infinity(spec).to_expr();
1286 
1287  isnan = or_exprt(
1288  and_exprt(
1289  equal_exprt(minus_expr.lhs(), plus_inf),
1290  equal_exprt(minus_expr.rhs(), plus_inf)),
1291  and_exprt(
1292  equal_exprt(minus_expr.lhs(), minus_inf),
1293  equal_exprt(minus_expr.rhs(), minus_inf)));
1294  }
1295  else
1296  UNREACHABLE;
1297 
1300  "NaN on " + expr.id_string(),
1301  "NaN",
1302  expr.find_source_location(),
1303  expr,
1304  guard);
1305 }
1306 
1308  const binary_exprt &expr,
1309  const guardt &guard)
1310 {
1312  return;
1313 
1314  if(
1315  expr.op0().type().id() == ID_pointer &&
1316  expr.op1().type().id() == ID_pointer)
1317  {
1318  // add same-object subgoal
1319 
1320  exprt same_object = ::same_object(expr.op0(), expr.op1());
1321 
1323  same_object,
1324  "same object violation",
1325  "pointer",
1326  expr.find_source_location(),
1327  expr,
1328  guard);
1329 
1330  for(const auto &pointer : expr.operands())
1331  {
1332  // just this particular byte must be within object bounds or one past the
1333  // end
1334  const auto size = from_integer(0, size_type());
1335  auto conditions = get_pointer_dereferenceable_conditions(pointer, size);
1336 
1337  for(const auto &c : conditions)
1338  {
1340  c.assertion,
1341  "pointer relation: " + c.description,
1342  "pointer arithmetic",
1343  expr.find_source_location(),
1344  pointer,
1345  guard);
1346  }
1347  }
1348  }
1349 }
1350 
1352  const exprt &expr,
1353  const guardt &guard)
1354 {
1356  return;
1357 
1358  if(expr.id() != ID_plus && expr.id() != ID_minus)
1359  return;
1360 
1362  expr.operands().size() == 2,
1363  "pointer arithmetic expected to have exactly 2 operands");
1364 
1365  // multiplying the offset by the object size must not result in arithmetic
1366  // overflow
1367  const typet &object_type = to_pointer_type(expr.type()).base_type();
1368  if(object_type.id() != ID_empty)
1369  {
1370  auto size_of_expr_opt = size_of_expr(object_type, ns);
1371  CHECK_RETURN(size_of_expr_opt.has_value());
1372  exprt object_size = size_of_expr_opt.value();
1373 
1374  const binary_exprt &binary_expr = to_binary_expr(expr);
1375  exprt offset_operand = binary_expr.lhs().type().id() == ID_pointer
1376  ? binary_expr.rhs()
1377  : binary_expr.lhs();
1378  mult_exprt mul{
1379  offset_operand,
1381  mul.add_source_location() = offset_operand.source_location();
1382 
1383  flag_overridet override_overflow(offset_operand.source_location());
1384  override_overflow.set_flag(
1385  enable_signed_overflow_check, true, "signed_overflow_check");
1386  override_overflow.set_flag(
1387  enable_unsigned_overflow_check, true, "unsigned_overflow_check");
1389  }
1390 
1391  // the result must be within object bounds or one past the end
1392  const auto size = from_integer(0, size_type());
1393  auto conditions = get_pointer_dereferenceable_conditions(expr, size);
1394 
1395  for(const auto &c : conditions)
1396  {
1398  c.assertion,
1399  "pointer arithmetic: " + c.description,
1400  "pointer arithmetic",
1401  expr.find_source_location(),
1402  expr,
1403  guard);
1404  }
1405 }
1406 
1408  const dereference_exprt &expr,
1409  const exprt &src_expr,
1410  const guardt &guard)
1411 {
1413  return;
1414 
1415  const exprt &pointer = expr.pointer();
1416 
1417  exprt size;
1418 
1419  if(expr.type().id() == ID_empty)
1420  {
1421  // a dereference *p (with p being a pointer to void) is valid if p points to
1422  // valid memory (of any size). the smallest possible size of the memory
1423  // segment p could be pointing to is 1, hence we use this size for the
1424  // address check
1425  size = from_integer(1, size_type());
1426  }
1427  else
1428  {
1429  auto size_of_expr_opt = size_of_expr(expr.type(), ns);
1430  CHECK_RETURN(size_of_expr_opt.has_value());
1431  size = size_of_expr_opt.value();
1432  }
1433 
1434  auto conditions = get_pointer_dereferenceable_conditions(pointer, size);
1435 
1436  for(const auto &c : conditions)
1437  {
1439  c.assertion,
1440  "dereference failure: " + c.description,
1441  "pointer dereference",
1442  src_expr.find_source_location(),
1443  src_expr,
1444  guard);
1445  }
1446 }
1447 
1449  const exprt &expr,
1450  const guardt &guard)
1451 {
1453  return;
1454 
1455  if(expr.source_location().is_built_in())
1456  return;
1457 
1458  const exprt pointer =
1459  (expr.id() == ID_r_ok || expr.id() == ID_w_ok || expr.id() == ID_rw_ok)
1460  ? to_r_or_w_ok_expr(expr).pointer()
1463  : to_unary_expr(expr).op();
1464 
1465  CHECK_RETURN(pointer.type().id() == ID_pointer);
1466 
1467  if(pointer.id() == ID_symbol)
1468  {
1469  const auto &symbol_expr = to_symbol_expr(pointer);
1470 
1471  if(symbol_expr.get_identifier().starts_with(CPROVER_PREFIX))
1472  return;
1473  }
1474 
1476  pointer, from_integer(0, size_type()));
1477  for(const auto &c : conditions)
1478  {
1480  or_exprt{null_object(pointer), c.assertion},
1481  c.description,
1482  "pointer primitives",
1483  expr.source_location(),
1484  expr,
1485  guard);
1486  }
1487 }
1488 
1490 {
1491  // we don't need to include the __CPROVER_same_object primitive here as it
1492  // is replaced by lower level primitives in the special function handling
1493  // during typechecking (see c_typecheck_expr.cpp)
1494 
1495  // pointer_object and pointer_offset are well-defined for an arbitrary
1496  // pointer-typed operand (and the operands themselves have been checked
1497  // separately for, e.g., invalid pointer dereferencing via check_rec):
1498  // pointer_object and pointer_offset just extract a subset of bits from the
1499  // pointer. If that pointer was unconstrained (non-deterministic), the result
1500  // will equally be non-deterministic.
1501  return can_cast_expr<object_size_exprt>(expr) || expr.id() == ID_r_ok ||
1502  expr.id() == ID_w_ok || expr.id() == ID_rw_ok ||
1504  expr.id() == ID_is_dynamic_object;
1505 }
1506 
1509  const exprt &address,
1510  const exprt &size)
1511 {
1512  auto conditions =
1514  if(auto maybe_null_condition = get_pointer_is_null_condition(address, size))
1515  {
1516  conditions.push_front(*maybe_null_condition);
1517  }
1518  return conditions;
1519 }
1520 
1521 std::string goto_check_ct::array_name(const exprt &expr)
1522 {
1523  return ::array_name(ns, expr);
1524 }
1525 
1527 {
1528  if(!enable_bounds_check)
1529  return;
1530 
1531  if(expr.id() == ID_index)
1533  else if(
1534  (expr.id() == ID_count_leading_zeros &&
1535  !to_count_leading_zeros_expr(expr).zero_permitted()) ||
1536  (expr.id() == ID_count_trailing_zeros &&
1537  !to_count_trailing_zeros_expr(expr).zero_permitted()))
1538  {
1540  }
1541 }
1542 
1544  const index_exprt &expr,
1545  const guardt &guard)
1546 {
1547  const typet &array_type = expr.array().type();
1548 
1549  if(array_type.id() == ID_pointer)
1550  throw "index got pointer as array type";
1551  else if(array_type.id() != ID_array && array_type.id() != ID_vector)
1552  throw "bounds check expected array or vector type, got " +
1553  array_type.id_string();
1554 
1555  std::string name = array_name(expr.array());
1556 
1557  const exprt &index = expr.index();
1559  ode.build(expr, ns);
1560 
1561  if(index.type().id() != ID_unsignedbv)
1562  {
1563  // we undo typecasts to signedbv
1564  if(
1565  index.id() == ID_typecast &&
1566  to_typecast_expr(index).op().type().id() == ID_unsignedbv)
1567  {
1568  // ok
1569  }
1570  else
1571  {
1572  const auto i = numeric_cast<mp_integer>(index);
1573 
1574  if(!i.has_value() || *i < 0)
1575  {
1576  exprt effective_offset = ode.offset();
1577 
1578  if(ode.root_object().id() == ID_dereference)
1579  {
1580  exprt p_offset =
1582 
1583  effective_offset = plus_exprt{
1584  p_offset,
1586  effective_offset, p_offset.type())};
1587  }
1588 
1589  exprt zero = from_integer(0, effective_offset.type());
1590 
1591  // the final offset must not be negative
1592  binary_relation_exprt inequality(
1593  effective_offset, ID_ge, std::move(zero));
1594 
1596  inequality,
1597  name + " lower bound",
1598  "array bounds",
1599  expr.find_source_location(),
1600  expr,
1601  guard);
1602  }
1603  }
1604  }
1605 
1606  if(ode.root_object().id() == ID_dereference)
1607  {
1608  const exprt &pointer = to_dereference_expr(ode.root_object()).pointer();
1609 
1610  const plus_exprt effective_offset{
1611  ode.offset(),
1613  pointer_offset(pointer), ode.offset().type())};
1614 
1615  binary_relation_exprt inequality{
1616  effective_offset,
1617  ID_lt,
1619  object_size(pointer), effective_offset.type())};
1620 
1621  exprt in_bounds_of_some_explicit_allocation =
1623  pointer,
1624  plus_exprt{ode.offset(), from_integer(1, ode.offset().type())});
1625 
1626  or_exprt precond(
1627  std::move(in_bounds_of_some_explicit_allocation), inequality);
1628 
1630  precond,
1631  name + " dynamic object upper bound",
1632  "array bounds",
1633  expr.find_source_location(),
1634  expr,
1635  guard);
1636 
1637  return;
1638  }
1639 
1640  const exprt &size = array_type.id() == ID_array
1641  ? to_array_type(array_type).size()
1642  : to_vector_type(array_type).size();
1643 
1644  if(size.is_nil() && !array_type.get_bool(ID_C_flexible_array_member))
1645  {
1646  // Linking didn't complete, we don't have a size.
1647  // Not clear what to do.
1648  }
1649  else if(size.id() == ID_infinity)
1650  {
1651  }
1652  else if(
1653  expr.array().id() == ID_member &&
1654  (size.is_zero() || array_type.get_bool(ID_C_flexible_array_member)))
1655  {
1656  // a variable sized struct member
1657  //
1658  // Excerpt from the C standard on flexible array members:
1659  // However, when a . (or ->) operator has a left operand that is (a pointer
1660  // to) a structure with a flexible array member and the right operand names
1661  // that member, it behaves as if that member were replaced with the longest
1662  // array (with the same element type) that would not make the structure
1663  // larger than the object being accessed; [...]
1664  const auto type_size_opt =
1666  CHECK_RETURN(type_size_opt.has_value());
1667 
1668  binary_relation_exprt inequality(
1669  ode.offset(),
1670  ID_lt,
1671  from_integer(type_size_opt.value(), ode.offset().type()));
1672 
1674  inequality,
1675  name + " upper bound",
1676  "array bounds",
1677  expr.find_source_location(),
1678  expr,
1679  guard);
1680  }
1681  else
1682  {
1683  binary_relation_exprt inequality{
1684  typecast_exprt::conditional_cast(index, size.type()), ID_lt, size};
1685 
1687  inequality,
1688  name + " upper bound",
1689  "array bounds",
1690  expr.find_source_location(),
1691  expr,
1692  guard);
1693  }
1694 }
1695 
1697  const unary_exprt &expr,
1698  const guardt &guard)
1699 {
1700  std::string name;
1701 
1702  if(expr.id() == ID_count_leading_zeros)
1703  name = "leading";
1704  else if(expr.id() == ID_count_trailing_zeros)
1705  name = "trailing";
1706  else
1707  PRECONDITION(false);
1708 
1710  notequal_exprt{expr.op(), from_integer(0, expr.op().type())},
1711  "count " + name + " zeros is undefined for value zero",
1712  "bit count",
1713  expr.find_source_location(),
1714  expr,
1715  guard);
1716 }
1717 
1719  const exprt &asserted_expr,
1720  const std::string &comment,
1721  const std::string &property_class,
1722  const source_locationt &source_location,
1723  const exprt &src_expr,
1724  const guardt &guard)
1725 {
1726  // first try simplifier on it
1727  exprt simplified_expr =
1728  enable_simplify ? simplify_expr(asserted_expr, ns) : asserted_expr;
1729 
1730  // throw away trivial properties?
1731  if(!retain_trivial && simplified_expr.is_true())
1732  return;
1733 
1734  // add the guard
1735  exprt guarded_expr = guard(simplified_expr);
1736 
1737  if(assertions.insert(std::make_pair(src_expr, guarded_expr)).second)
1738  {
1739  std::string source_expr_string;
1740  get_language_from_mode(mode)->from_expr(src_expr, source_expr_string, ns);
1741 
1742  source_locationt annotated_location = source_location;
1743  annotated_location.set_comment(comment + " in " + source_expr_string);
1744  annotated_location.set_property_class(property_class);
1745 
1746  add_all_checked_named_check_pragmas(annotated_location);
1747 
1749  {
1751  std::move(guarded_expr), annotated_location));
1752  }
1753  else
1754  {
1756  std::move(guarded_expr), annotated_location));
1757  }
1758  }
1759 }
1760 
1762 {
1763  // we don't look into quantifiers
1764  if(expr.id() == ID_exists || expr.id() == ID_forall)
1765  return;
1766 
1767  if(expr.id() == ID_dereference)
1768  {
1769  check_rec(to_dereference_expr(expr).pointer(), guard);
1770  }
1771  else if(expr.id() == ID_index)
1772  {
1773  const index_exprt &index_expr = to_index_expr(expr);
1774  check_rec_address(index_expr.array(), guard);
1775  check_rec(index_expr.index(), guard);
1776  }
1777  else
1778  {
1779  for(const auto &operand : expr.operands())
1780  check_rec_address(operand, guard);
1781  }
1782 }
1783 
1785 {
1786  PRECONDITION(
1787  expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_implies);
1788  INVARIANT(
1789  expr.is_boolean(),
1790  "'" + expr.id_string() + "' must be Boolean, but got " + expr.pretty());
1791 
1792  exprt::operandst constraints;
1793 
1794  for(const auto &op : expr.operands())
1795  {
1796  INVARIANT(
1797  op.is_boolean(),
1798  "'" + expr.id_string() + "' takes Boolean operands only, but got " +
1799  op.pretty());
1800 
1801  auto new_guard = [&guard, &constraints](exprt expr) {
1802  return guard(implication(conjunction(constraints), expr));
1803  };
1804 
1805  check_rec(op, new_guard);
1806 
1807  constraints.push_back(expr.id() == ID_or ? boolean_negate(op) : op);
1808  }
1809 }
1810 
1811 void goto_check_ct::check_rec_if(const if_exprt &if_expr, const guardt &guard)
1812 {
1813  INVARIANT(
1814  if_expr.cond().is_boolean(),
1815  "first argument of if must be boolean, but got " + if_expr.cond().pretty());
1816 
1817  check_rec(if_expr.cond(), guard);
1818 
1819  {
1820  auto new_guard = [&guard, &if_expr](exprt expr) {
1821  return guard(implication(if_expr.cond(), std::move(expr)));
1822  };
1823  check_rec(if_expr.true_case(), new_guard);
1824  }
1825 
1826  {
1827  auto new_guard = [&guard, &if_expr](exprt expr) {
1828  return guard(implication(not_exprt(if_expr.cond()), std::move(expr)));
1829  };
1830  check_rec(if_expr.false_case(), new_guard);
1831  }
1832 }
1833 
1835  const member_exprt &member,
1836  const guardt &guard)
1837 {
1838  const dereference_exprt &deref = to_dereference_expr(member.struct_op());
1839 
1840  check_rec(deref.pointer(), guard);
1841 
1842  // avoid building the following expressions when pointer_validity_check
1843  // would return immediately anyway
1845  return true;
1846 
1847  // we rewrite s->member into *(s+member_offset)
1848  // to avoid requiring memory safety of the entire struct
1849  auto member_offset_opt = member_offset_expr(member, ns);
1850 
1851  if(member_offset_opt.has_value())
1852  {
1853  pointer_typet new_pointer_type = to_pointer_type(deref.pointer().type());
1854  new_pointer_type.base_type() = member.type();
1855 
1856  const exprt char_pointer = typecast_exprt::conditional_cast(
1857  deref.pointer(), pointer_type(char_type()));
1858 
1859  const exprt new_address_casted = typecast_exprt::conditional_cast(
1860  plus_exprt{
1861  char_pointer,
1863  member_offset_opt.value(), pointer_diff_type())},
1864  new_pointer_type);
1865 
1866  dereference_exprt new_deref{new_address_casted};
1867  new_deref.add_source_location() = deref.source_location();
1868  pointer_validity_check(new_deref, member, guard);
1869 
1870  return true;
1871  }
1872  return false;
1873 }
1874 
1876  const div_exprt &div_expr,
1877  const guardt &guard)
1878 {
1879  if(
1880  div_expr.type().id() == ID_signedbv ||
1881  div_expr.type().id() == ID_unsignedbv || div_expr.type().id() == ID_c_bool)
1882  {
1883  // Division by zero is undefined behavior for all integer types.
1884  div_by_zero_check(to_div_expr(div_expr), guard);
1885  }
1886  else if(div_expr.type().id() == ID_floatbv)
1887  {
1888  // Division by zero on floating-point numbers may be undefined behavior.
1889  // Annex F of the ISO C21 suggests that implementations that
1890  // define __STDC_IEC_559__ follow IEEE 754 semantics,
1891  // which defines the outcome of division by zero.
1893  }
1894 
1895  if(div_expr.type().id() == ID_signedbv)
1896  integer_overflow_check(div_expr, guard);
1897  else if(div_expr.type().id() == ID_floatbv)
1898  {
1899  nan_check(div_expr, guard);
1900  float_overflow_check(div_expr, guard);
1901  }
1902 }
1903 
1905  const exprt &expr,
1906  const guardt &guard)
1907 {
1908  if(expr.type().id() == ID_signedbv || expr.type().id() == ID_unsignedbv)
1909  {
1911 
1912  if(
1913  expr.operands().size() == 2 && expr.id() == ID_minus &&
1914  expr.operands()[0].type().id() == ID_pointer &&
1915  expr.operands()[1].type().id() == ID_pointer)
1916  {
1918  }
1919  }
1920  else if(expr.type().id() == ID_floatbv)
1921  {
1922  nan_check(expr, guard);
1923  float_overflow_check(expr, guard);
1924  }
1925  else if(expr.type().id() == ID_pointer)
1926  {
1928  }
1929 }
1930 
1931 void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
1932 {
1933  if(expr.id() == ID_exists || expr.id() == ID_forall)
1934  {
1935  // the scoped variables may be used in the assertion
1936  const auto &quantifier_expr = to_quantifier_expr(expr);
1937 
1938  auto new_guard = [&guard, &quantifier_expr](exprt expr) {
1939  return guard(forall_exprt(quantifier_expr.symbol(), expr));
1940  };
1941 
1942  check_rec(quantifier_expr.where(), new_guard);
1943  return;
1944  }
1945  else if(expr.id() == ID_address_of)
1946  {
1947  check_rec_address(to_address_of_expr(expr).object(), guard);
1948  return;
1949  }
1950  else if(expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_implies)
1951  {
1952  check_rec_logical_op(expr, guard);
1953  return;
1954  }
1955  else if(expr.id() == ID_if)
1956  {
1957  check_rec_if(to_if_expr(expr), guard);
1958  return;
1959  }
1960  else if(
1961  expr.id() == ID_member &&
1962  to_member_expr(expr).struct_op().id() == ID_dereference)
1963  {
1965  return;
1966  }
1967 
1968  for(const auto &op : expr.operands())
1969  check_rec(op, guard);
1970 
1971  if(expr.type().id() == ID_c_enum_tag)
1972  enum_range_check(expr, guard);
1973 
1974  if(expr.id() == ID_index)
1975  {
1976  bounds_check(expr, guard);
1977  }
1978  else if(expr.id() == ID_div)
1979  {
1981  }
1982  else if(expr.id() == ID_shl || expr.id() == ID_ashr || expr.id() == ID_lshr)
1983  {
1985 
1986  if(expr.id() == ID_shl && expr.type().id() == ID_signedbv)
1988  }
1989  else if(expr.id() == ID_mod)
1990  {
1993  }
1994  else if(
1995  expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult ||
1996  expr.id() == ID_unary_minus)
1997  {
1999  }
2000  else if(expr.id() == ID_typecast)
2001  conversion_check(expr, guard);
2002  else if(
2003  expr.id() == ID_le || expr.id() == ID_lt || expr.id() == ID_ge ||
2004  expr.id() == ID_gt)
2006  else if(expr.id() == ID_dereference)
2007  {
2009  }
2010  else if(requires_pointer_primitive_check(expr))
2011  {
2013  }
2014  else if(
2015  expr.id() == ID_count_leading_zeros || expr.id() == ID_count_trailing_zeros)
2016  {
2017  bounds_check(expr, guard);
2018  }
2019 }
2020 
2021 void goto_check_ct::check(const exprt &expr)
2022 {
2023  check_rec(expr, identity);
2024 }
2025 
2027 {
2028  const symbolt &leak = ns.lookup(CPROVER_PREFIX "memory_leak");
2029  const symbol_exprt leak_expr = leak.symbol_expr();
2030 
2031  // add self-assignment to get helpful counterexample output
2032  new_code.add(goto_programt::make_assignment(leak_expr, leak_expr));
2033 
2034  source_locationt source_location;
2035  source_location.set_function(function_id);
2036 
2037  equal_exprt eq(leak_expr, null_pointer_exprt(to_pointer_type(leak.type)));
2038 
2040  eq,
2041  "dynamically allocated memory never freed",
2042  "memory-leak",
2043  source_location,
2044  eq,
2045  identity);
2046 }
2047 
2049  const irep_idt &function_identifier,
2050  goto_functiont &goto_function)
2051 {
2052  const auto &function_symbol = ns.lookup(function_identifier);
2053  mode = function_symbol.mode;
2054 
2055  if(mode != ID_C && mode != ID_cpp)
2056  return;
2057 
2058  assertions.clear();
2059 
2060  bool did_something = false;
2061 
2063  std::make_unique<local_bitvector_analysist>(goto_function, ns);
2064 
2065  goto_programt &goto_program = goto_function.body;
2066 
2067  Forall_goto_program_instructions(it, goto_program)
2068  {
2069  current_target = it;
2070  goto_programt::instructiont &i = *it;
2071 
2072  flag_overridet resetter(i.source_location());
2073  const auto &pragmas = i.source_location().get_pragmas();
2074  for(const auto &d : pragmas)
2075  {
2076  // match named-check related pragmas
2077  auto matched = match_named_check(d.first);
2078  if(matched.has_value())
2079  {
2080  auto named_check = matched.value();
2081  auto name = named_check.first;
2082  auto status = named_check.second;
2083  bool *flag = name_to_flag.find(name)->second;
2084  switch(status)
2085  {
2086  case check_statust::ENABLE:
2087  resetter.set_flag(*flag, true, name);
2088  break;
2089  case check_statust::DISABLE:
2090  resetter.set_flag(*flag, false, name);
2091  break;
2092  case check_statust::CHECKED:
2093  resetter.disable_flag(*flag, name);
2094  break;
2095  }
2096  }
2097  }
2098 
2099  // add checked pragmas for all active checks
2101 
2102  new_code.clear();
2103 
2104  // we clear all recorded assertions if
2105  // 1) we want to generate all assertions or
2106  // 2) the instruction is a branch target
2107  if(retain_trivial || i.is_target())
2108  assertions.clear();
2109 
2110  if(i.has_condition())
2111  {
2112  check(i.condition());
2113  }
2114 
2115  // magic ERROR label?
2116  for(const auto &label : error_labels)
2117  {
2118  if(std::find(i.labels.begin(), i.labels.end(), label) != i.labels.end())
2119  {
2120  source_locationt annotated_location = i.source_location();
2121  annotated_location.set_property_class("error label");
2122  annotated_location.set_comment("error label " + label);
2123  annotated_location.set("user-provided", true);
2124 
2126  {
2127  new_code.add(
2128  goto_programt::make_assumption(false_exprt{}, annotated_location));
2129  }
2130  else
2131  {
2132  new_code.add(
2133  goto_programt::make_assertion(false_exprt{}, annotated_location));
2134  }
2135  }
2136  }
2137 
2138  if(i.is_other())
2139  {
2140  const auto &code = i.get_other();
2141  const irep_idt &statement = code.get_statement();
2142 
2143  if(statement == ID_expression)
2144  {
2145  check(code);
2146  }
2147  else if(statement == ID_printf)
2148  {
2149  for(const auto &op : code.operands())
2150  check(op);
2151  }
2152  }
2153  else if(i.is_assign())
2154  {
2155  const exprt &assign_lhs = i.assign_lhs();
2156  const exprt &assign_rhs = i.assign_rhs();
2157 
2158  // Disable enum range checks for left-hand sides as their values are yet
2159  // to be set (by this assignment).
2160  {
2161  flag_overridet resetter(i.source_location());
2162  resetter.disable_flag(enable_enum_range_check, "enum_range_check");
2163  check(assign_lhs);
2164  }
2165 
2166  check(assign_rhs);
2167 
2168  // the LHS might invalidate any assertion
2169  invalidate(assign_lhs);
2170  }
2171  else if(i.is_function_call())
2172  {
2173  // Disable enum range checks for left-hand sides as their values are yet
2174  // to be set (by this function call).
2175  {
2176  flag_overridet resetter(i.source_location());
2177  resetter.disable_flag(enable_enum_range_check, "enum_range_check");
2178  check(i.call_lhs());
2179  }
2180  check(i.call_function());
2181 
2182  for(const auto &arg : i.call_arguments())
2183  check(arg);
2184 
2186 
2187  // the call might invalidate any assertion
2188  assertions.clear();
2189  }
2190  else if(i.is_set_return_value())
2191  {
2192  check(i.return_value());
2193  // the return value invalidate any assertion
2194  invalidate(i.return_value());
2195  }
2196  else if(i.is_throw())
2197  {
2198  // this has no successor
2199  assertions.clear();
2200  }
2201  else if(i.is_assume())
2202  {
2203  // These are further 'exit points' of the program
2204  const exprt simplified_guard = simplify_expr(i.condition(), ns);
2205  if(
2206  enable_memory_cleanup_check && simplified_guard.is_false() &&
2207  (function_identifier == "abort" || function_identifier == "exit" ||
2208  function_identifier == "_Exit" ||
2209  (i.labels.size() == 1 && i.labels.front() == "__VERIFIER_abort")))
2210  {
2211  memory_leak_check(function_identifier);
2212  }
2213  }
2214  else if(i.is_dead())
2215  {
2217  {
2218  const symbol_exprt &variable = i.dead_symbol();
2219 
2220  // is it dirty?
2221  if(local_bitvector_analysis->dirty(variable))
2222  {
2223  // need to mark the dead variable as dead
2224  exprt lhs = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
2225  exprt address_of_expr = typecast_exprt::conditional_cast(
2226  address_of_exprt(variable), lhs.type());
2227  if_exprt rhs(
2229  std::move(address_of_expr),
2230  lhs);
2232  code_assignt{std::move(lhs), std::move(rhs), i.source_location()},
2233  i.source_location()));
2234  }
2235  }
2236  }
2237  else if(i.is_end_function())
2238  {
2239  if(
2240  function_identifier == goto_functionst::entry_point() &&
2242  {
2243  memory_leak_check(function_identifier);
2244  }
2245  }
2246 
2247  for(auto &instruction : new_code.instructions)
2248  {
2249  if(instruction.source_location().is_nil())
2250  {
2251  instruction.source_location_nonconst().id(irep_idt());
2252 
2253  if(!it->source_location().get_file().empty())
2254  instruction.source_location_nonconst().set_file(
2255  it->source_location().get_file());
2256 
2257  if(!it->source_location().get_line().empty())
2258  instruction.source_location_nonconst().set_line(
2259  it->source_location().get_line());
2260 
2261  if(!it->source_location().get_function().empty())
2262  instruction.source_location_nonconst().set_function(
2263  it->source_location().get_function());
2264 
2265  if(!it->source_location().get_column().empty())
2266  {
2267  instruction.source_location_nonconst().set_column(
2268  it->source_location().get_column());
2269  }
2270  }
2271  }
2272 
2273  // insert new instructions -- make sure targets are not moved
2274  did_something |= !new_code.instructions.empty();
2275 
2276  while(!new_code.instructions.empty())
2277  {
2278  goto_program.insert_before_swap(it, new_code.instructions.front());
2279  new_code.instructions.pop_front();
2280  it++;
2281  }
2282  }
2283 
2284  if(did_something)
2285  remove_skip(goto_program);
2286 }
2287 
2289  const goto_programt::instructiont &i)
2290 {
2291  if(i.call_function().id() != ID_symbol)
2292  return;
2293 
2294  const irep_idt &identifier =
2296 
2297  if(
2298  identifier == CPROVER_PREFIX "get_field" || identifier == CPROVER_PREFIX
2299  "set_field")
2300  {
2301  const exprt &expr = i.call_arguments()[0];
2302  PRECONDITION(expr.type().id() == ID_pointer);
2303  check(dereference_exprt(expr));
2304  }
2305 }
2306 
2309  const exprt &address,
2310  const exprt &size)
2311 {
2313  PRECONDITION(address.type().id() == ID_pointer);
2316 
2317  conditionst conditions;
2318 
2319  const exprt in_bounds_of_some_explicit_allocation =
2321 
2322  const bool unknown = flags.is_unknown() || flags.is_uninitialized();
2323 
2324  if(unknown)
2325  {
2326  conditions.push_back(conditiont{
2327  not_exprt{is_invalid_pointer_exprt{address}}, "pointer invalid"});
2328  }
2329 
2330  if(unknown || flags.is_dynamic_heap())
2331  {
2332  conditions.push_back(conditiont(
2333  or_exprt(
2334  in_bounds_of_some_explicit_allocation,
2335  not_exprt(deallocated(address, ns))),
2336  "deallocated dynamic object"));
2337  }
2338 
2339  if(unknown || flags.is_dynamic_local())
2340  {
2341  conditions.push_back(conditiont(
2342  or_exprt(
2343  in_bounds_of_some_explicit_allocation,
2344  not_exprt(dead_object(address, ns))),
2345  "dead object"));
2346  }
2347 
2348  if(flags.is_dynamic_heap())
2349  {
2350  const or_exprt object_bounds_violation(
2351  object_lower_bound(address, nil_exprt()),
2352  object_upper_bound(address, size));
2353 
2354  conditions.push_back(conditiont(
2355  or_exprt(
2356  in_bounds_of_some_explicit_allocation,
2357  not_exprt(object_bounds_violation)),
2358  "pointer outside dynamic object bounds"));
2359  }
2360 
2361  if(unknown || flags.is_dynamic_local() || flags.is_static_lifetime())
2362  {
2363  const or_exprt object_bounds_violation(
2364  object_lower_bound(address, nil_exprt()),
2365  object_upper_bound(address, size));
2366 
2367  conditions.push_back(conditiont(
2368  or_exprt(
2369  in_bounds_of_some_explicit_allocation,
2370  not_exprt(object_bounds_violation)),
2371  "pointer outside object bounds"));
2372  }
2373 
2374  if(unknown || flags.is_integer_address())
2375  {
2376  conditions.push_back(conditiont(
2377  implies_exprt(
2378  integer_address(address), in_bounds_of_some_explicit_allocation),
2379  "invalid integer address"));
2380  }
2381 
2382  return conditions;
2383 }
2384 
2385 std::optional<goto_check_ct::conditiont>
2387  const exprt &address,
2388  const exprt &size)
2389 {
2391  PRECONDITION(address.type().id() == ID_pointer);
2394 
2395  if(flags.is_unknown() || flags.is_uninitialized() || flags.is_null())
2396  {
2397  return {conditiont{
2398  or_exprt{
2400  not_exprt(null_object(address))},
2401  "pointer NULL"}};
2402  }
2403 
2404  return {};
2405 }
2406 
2408  const exprt &pointer,
2409  const exprt &size)
2410 {
2411  exprt::operandst alloc_disjuncts;
2412  for(const auto &a : allocations)
2413  {
2414  typecast_exprt int_ptr(pointer, a.first.type());
2415 
2416  binary_relation_exprt lb_check(a.first, ID_le, int_ptr);
2417 
2418  plus_exprt upper_bound{
2419  int_ptr, typecast_exprt::conditional_cast(size, int_ptr.type())};
2420 
2421  binary_relation_exprt ub_check{
2422  std::move(upper_bound), ID_le, plus_exprt{a.first, a.second}};
2423 
2424  alloc_disjuncts.push_back(
2425  and_exprt{std::move(lb_check), std::move(ub_check)});
2426  }
2427  return disjunction(alloc_disjuncts);
2428 }
2429 
2431  const irep_idt &function_identifier,
2432  goto_functionst::goto_functiont &goto_function,
2433  const namespacet &ns,
2434  const optionst &options,
2435  message_handlert &message_handler)
2436 {
2437  goto_check_ct goto_check(ns, options, message_handler);
2438  goto_check.goto_check(function_identifier, goto_function);
2439 }
2440 
2442  const namespacet &ns,
2443  const optionst &options,
2444  goto_functionst &goto_functions,
2445  message_handlert &message_handler)
2446 {
2447  goto_check_ct goto_check(ns, options, message_handler);
2448 
2449  goto_check.collect_allocations(goto_functions);
2450 
2451  for(auto &gf_entry : goto_functions.function_map)
2452  {
2453  goto_check.goto_check(gf_entry.first, gf_entry.second);
2454  }
2455 }
2456 
2458  const optionst &options,
2459  goto_modelt &goto_model,
2460  message_handlert &message_handler)
2461 {
2462  const namespacet ns(goto_model.symbol_table);
2463  goto_check_c(ns, options, goto_model.goto_functions, message_handler);
2464 }
2465 
2467  source_locationt &source_location) const
2468 {
2469  for(const auto &entry : name_to_flag)
2470  if(*(entry.second))
2471  source_location.add_pragma("checked:" + id2string(entry.first));
2472 }
2473 
2475  source_locationt &source_location) const
2476 {
2477  for(const auto &entry : name_to_flag)
2478  source_location.add_pragma("checked:" + id2string(entry.first));
2479 }
2480 
2483 {
2484  auto s = id2string(named_check);
2485  auto col = s.find(":");
2486 
2487  if(col == std::string::npos)
2488  return {}; // separator not found
2489 
2490  auto name = s.substr(col + 1);
2491 
2492  if(name_to_flag.find(name) == name_to_flag.end())
2493  return {}; // name unknown
2494 
2495  check_statust status;
2496  if(!s.compare(0, 6, "enable"))
2497  status = check_statust::ENABLE;
2498  else if(!s.compare(0, 7, "disable"))
2499  status = check_statust::DISABLE;
2500  else if(!s.compare(0, 7, "checked"))
2501  status = check_statust::CHECKED;
2502  else
2503  return {}; // prefix unknow
2504 
2505  // success
2506  return std::pair<irep_idt, check_statust>{name, status};
2507 }
configt config
Definition: config.cpp:25
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
std::string array_name(const namespacet &ns, const exprt &expr)
Definition: array_name.cpp:19
Misc Utilities.
API to expression classes for bitvectors.
const shift_exprt & to_shift_expr(const exprt &expr)
Cast an exprt to a shift_exprt.
const count_trailing_zeros_exprt & to_count_trailing_zeros_expr(const exprt &expr)
Cast an exprt to a count_trailing_zeros_exprt.
const shl_exprt & to_shl_expr(const exprt &expr)
Cast an exprt to a shl_exprt.
const count_leading_zeros_exprt & to_count_leading_zeros_expr(const exprt &expr)
Cast an exprt to a count_leading_zeros_exprt.
const floatbv_typet & to_floatbv_type(const typet &type)
Cast a typet to a floatbv_typet.
const signedbv_typet & to_signedbv_type(const typet &type)
Cast a typet to a signedbv_typet.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const unsignedbv_typet & to_unsignedbv_type(const typet &type)
Cast a typet to an unsignedbv_typet.
API to expression classes that are internal to the C frontend.
static exprt guard(const exprt::operandst &guards, exprt cond)
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
Operator to return the address of an object.
Definition: pointer_expr.h:540
Boolean AND.
Definition: std_expr.h:2120
const exprt & size() const
Definition: std_types.h:840
A base class for binary expressions.
Definition: std_expr.h:638
exprt & op1()
Definition: expr.h:136
exprt & lhs()
Definition: std_expr.h:668
exprt & op0()
Definition: expr.h:133
exprt & rhs()
Definition: std_expr.h:678
A Boolean expression returning true, iff operation kind would result in an overflow when applied to o...
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition: std_expr.h:731
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:762
std::size_t get_width() const
Definition: std_types.h:920
The Boolean type.
Definition: std_types.h:36
A goto_instruction_codet representing an assignment in the program.
exprt::operandst argumentst
struct configt::cppt cpp
struct configt::ansi_ct ansi_c
Operator to dereference a pointer.
Definition: pointer_expr.h:834
Division.
Definition: std_expr.h:1152
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
A Boolean expression returning true, iff the value of an enum-typed symbol equals one of the enum's d...
Definition: c_expr.h:326
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_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:27
source_locationt & add_source_location()
Definition: expr.h:236
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition: expr.h:224
const source_locationt & source_location() const
Definition: expr.h:231
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:34
bool is_zero() const
Return whether the expression is a constant representing 0.
Definition: expr.cpp:47
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
Extracts a sub-range of a bit-vector operand.
The Boolean constant false.
Definition: std_expr.h:3064
~flag_overridet()
Restore the values of all flags that have been modified via set_flag.
void disable_flag(bool &flag, const irep_idt &flag_name)
Sets the given flag to false, overriding any previous value.
void set_flag(bool &flag, bool new_value, const irep_idt &flag_name)
Store the current value of flag and then set its value to new_value.
std::map< bool *, bool > flags_to_reset
flag_overridet(const source_locationt &source_location)
std::set< bool * > disabled_flags
const source_locationt & source_location
A forall expression.
std::optional< std::pair< irep_idt, check_statust > > named_check_statust
optional (named-check, status) pair
named_check_statust match_named_check(const irep_idt &named_check) const
Matches a named-check string of the form.
void goto_check(const irep_idt &function_identifier, goto_functiont &goto_function)
void check_rec(const exprt &expr, const guardt &guard)
Recursively descend into expr and run the appropriate check for each sub-expression,...
void check_rec_logical_op(const exprt &expr, const guardt &guard)
Check a logical operation: check each operand in separation while extending the guarding condition as...
bool enable_float_div_by_zero_check
void check_rec_address(const exprt &expr, const guardt &guard)
Check an address-of expression: if it is a dereference then check the pointer if it is an index then ...
std::function< exprt(exprt)> guardt
std::string array_name(const exprt &)
void collect_allocations(const goto_functionst &goto_functions)
Fill the list of allocations allocationst with <address, size> for every allocation instruction.
bool enable_pointer_check
void memory_leak_check(const irep_idt &function_id)
exprt is_in_bounds_of_some_explicit_allocation(const exprt &pointer, const exprt &size)
std::optional< goto_check_ct::conditiont > get_pointer_is_null_condition(const exprt &address, const exprt &size)
void enum_range_check(const exprt &, const guardt &)
void invalidate(const exprt &lhs)
Remove all assertions containing the symbol in lhs as well as all assertions containing dereference.
void float_div_by_zero_check(const div_exprt &, const guardt &)
const namespacet & ns
check_statust
activation statuses for named checks
void float_overflow_check(const exprt &, const guardt &)
bool enable_pointer_primitive_check
void mod_overflow_check(const mod_exprt &, const guardt &)
check a mod expression for the case INT_MIN % -1
bool requires_pointer_primitive_check(const exprt &expr)
Returns true if the given expression is a pointer primitive that requires validation of the operand t...
std::map< irep_idt, bool * > name_to_flag
Maps a named-check name to the corresponding boolean flag.
std::list< conditiont > conditionst
bool enable_float_overflow_check
bool enable_conversion_check
void check_rec_div(const div_exprt &div_expr, const guardt &guard)
Check that a division is valid: check for division by zero, overflow and NaN (for floating point numb...
bool enable_pointer_overflow_check
void pointer_primitive_check(const exprt &expr, const guardt &guard)
Generates VCCs to check that pointers passed to pointer primitives are either null or valid.
void bounds_check_index(const index_exprt &, const guardt &)
bool enable_signed_overflow_check
void check(const exprt &expr)
Initiate the recursively analysis of expr with its ‘guard’ set to TRUE.
conditionst get_pointer_dereferenceable_conditions(const exprt &address, const exprt &size)
bool check_rec_member(const member_exprt &member, const guardt &guard)
Check that a member expression is valid:
goto_functionst::goto_functiont goto_functiont
void bounds_check(const exprt &, const guardt &)
void add_guarded_property(const exprt &asserted_expr, const std::string &comment, const std::string &property_class, const source_locationt &source_location, const exprt &src_expr, const guardt &guard)
Include the asserted_expr in the code conditioned by the guard.
std::pair< exprt, exprt > allocationt
allocationst allocations
void pointer_overflow_check(const exprt &, const guardt &)
bool enable_memory_leak_check
void conversion_check(const exprt &, const guardt &)
void check_rec_if(const if_exprt &if_expr, const guardt &guard)
Check an if expression: check the if-condition alone, and then check the true/false-cases with the gu...
bool enable_bounds_check
void integer_overflow_check(const exprt &, const guardt &)
bool enable_assert_to_assume
bool enable_memory_cleanup_check
void nan_check(const exprt &, const guardt &)
bool enable_undefined_shift_check
std::list< allocationt > allocationst
bool enable_enum_range_check
goto_programt::const_targett current_target
void add_all_checked_named_check_pragmas(source_locationt &source_location) const
Adds "checked" pragmas for all named checks on the given source location (prevents any the instanciat...
const guardt identity
void div_by_zero_check(const div_exprt &, const guardt &)
optionst::value_listt error_labelst
void add_active_named_check_pragmas(source_locationt &source_location) const
Adds "checked" pragmas for all currently active named checks on the given source location.
assertionst assertions
void pointer_rel_check(const binary_exprt &, const guardt &)
goto_programt new_code
goto_check_ct(const namespacet &_ns, const optionst &_options, message_handlert &_message_handler)
conditionst get_pointer_points_to_valid_memory_conditions(const exprt &address, const exprt &size)
bool enable_unsigned_overflow_check
void bounds_check_bit_count(const unary_exprt &, const guardt &)
bool enable_div_by_zero_check
void check_shadow_memory_api_calls(const goto_programt::instructiont &)
error_labelst error_labels
void check_rec_arithmetic_op(const exprt &expr, const guardt &guard)
Check that an arithmetic operation is valid: overflow check, NaN-check (for floating point numbers),...
void undefined_shift_check(const shift_exprt &, const guardt &)
std::unique_ptr< local_bitvector_analysist > local_bitvector_analysis
void mod_by_zero_check(const mod_exprt &, const guardt &)
std::set< std::pair< exprt, exprt > > assertionst
void pointer_validity_check(const dereference_exprt &expr, const exprt &src_expr, const guardt &guard)
Generates VCCs for the validity of the given dereferencing operation.
A collection of goto functions.
function_mapt function_map
::goto_functiont goto_functiont
static irep_idt entry_point()
Get the identifier of the entry point to a goto model.
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
Definition: goto_function.h:24
goto_programt body
Definition: goto_function.h:26
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:34
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:181
const exprt & condition() const
Get the condition of gotos, assume, assert.
Definition: goto_program.h:366
const exprt & 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
bool is_set_return_value() const
Definition: goto_program.h:492
const exprt & call_function() const
Get the function that is called for FUNCTION_CALL.
Definition: goto_program.h:272
bool has_condition() const
Does this instruction have a condition?
Definition: goto_program.h:360
const exprt & return_value() const
Get the return value of a SET_RETURN_VALUE instruction.
Definition: goto_program.h:258
const goto_instruction_codet & get_other() const
Get the statement for OTHER.
Definition: goto_program.h:314
source_locationt & source_location_nonconst()
Definition: goto_program.h:338
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
const symbol_exprt & dead_symbol() const
Get the symbol for DEAD.
Definition: goto_program.h:244
const exprt & assign_lhs() const
Get the lhs of the assignment for ASSIGN.
Definition: goto_program.h:200
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
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
void clear()
Clear the goto program.
Definition: goto_program.h:820
void insert_before_swap(targett target)
Insertion that preserves jumps to "target".
Definition: goto_program.h:643
instructionst::const_iterator const_targett
Definition: goto_program.h:615
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
targett add(instructiont &&instruction)
Adds a given instruction at the end.
Definition: goto_program.h:739
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:933
IEEE-floating-point equality.
Definition: floatbv_expr.h:264
constant_exprt to_expr() const
Definition: ieee_float.cpp:703
static ieee_floatt plus_infinity(const ieee_float_spect &_spec)
Definition: ieee_float.h:211
static ieee_floatt minus_infinity(const ieee_float_spect &_spec)
Definition: ieee_float.h:214
void from_integer(const mp_integer &i)
Definition: ieee_float.cpp:516
The trinary if-then-else operator.
Definition: std_expr.h:2370
exprt & true_case()
Definition: std_expr.h:2397
exprt & false_case()
Definition: std_expr.h:2407
exprt & cond()
Definition: std_expr.h:2387
Boolean implication.
Definition: std_expr.h:2183
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
exprt & index()
Definition: std_expr.h:1505
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
const std::string & id_string() const
Definition: irep.h:387
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:408
const irep_idt & id() const
Definition: irep.h:384
bool is_nil() const
Definition: irep.h:364
Evaluates to true if the operand is infinite.
Definition: floatbv_expr.h:132
Extract member of struct or union.
Definition: std_expr.h:2841
const exprt & struct_op() const
Definition: std_expr.h:2879
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
Definition: std_expr.h:1223
exprt & divisor()
The divisor of a division is the number the dividend is being divided by.
Definition: std_expr.h:1243
Binary multiplication Associativity is not specified.
Definition: std_expr.h:1107
A base class for multi-ary expressions Associativity is not specified.
Definition: std_expr.h:912
exprt & op0()
Definition: std_expr.h:932
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
Boolean negation.
Definition: std_expr.h:2327
Disequality.
Definition: std_expr.h:1420
The null pointer constant.
Definition: pointer_expr.h:909
Split an expression into a base object and a (byte) offset.
Definition: pointer_expr.h:181
void build(const exprt &expr, const namespacet &ns)
Given an expression expr, attempt to find the underlying object it represents by skipping over type c...
static const exprt & root_object(const exprt &expr)
bool get_bool_option(const std::string &option) const
Definition: options.cpp:44
const value_listt & get_list_option(const std::string &option) const
Definition: options.cpp:80
std::list< std::string > value_listt
Definition: options.h:25
Boolean OR.
Definition: std_expr.h:2228
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
Definition: pointer_expr.h:24
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
const exprt & pointer() const
const exprt & pointer() const
Definition: pointer_expr.h:927
A base class for shift and rotate operators.
exprt & distance()
exprt & op()
Left shift.
A side_effect_exprt that returns a non-deterministically chosen value.
Definition: std_code.h:1520
void set_comment(const irep_idt &comment)
void set_property_class(const irep_idt &property_class)
const irept::named_subt & get_pragmas() const
void add_pragma(const irep_idt &pragma)
static bool is_built_in(const std::string &s)
std::string as_string() const
void set_function(const irep_idt &function)
Expression to hold a symbol (variable)
Definition: std_expr.h:131
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
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
Generic base class for unary expressions.
Definition: std_expr.h:361
const exprt & op() const
Definition: std_expr.h:391
A Boolean expression returning true, iff negation would result in an overflow when applied to the (si...
Fixed-width bit-vector with unsigned binary interpretation.
const constant_exprt & size() const
Definition: std_types.cpp:275
#define CPROVER_PREFIX
exprt make_binary(const exprt &expr)
splits an expression with >=3 operands into nested binary expressions
Definition: expr_util.cpp:38
bool has_subexpr(const exprt &expr, const std::function< bool(const exprt &)> &pred)
returns true if the expression has a subexpression that satisfies pred
Definition: expr_util.cpp:141
exprt boolean_negate(const exprt &src)
negate a Boolean expression, possibly removing a not_exprt, and swapping false and true
Definition: expr_util.cpp:129
Deprecated expression utility functions.
bool has_symbol_expr(const exprt &src, const irep_idt &identifier, bool include_bound_symbols)
Returns true if one of the symbol expressions in src has identifier identifier; if include_bound_symb...
API to expression classes for floating-point arithmetic.
void goto_check_c(const irep_idt &function_identifier, goto_functionst::goto_functiont &goto_function, const namespacet &ns, const optionst &options, message_handlert &message_handler)
static exprt implication(exprt lhs, exprt rhs)
Program Transformation.
Symbol Table + CFG.
#define Forall_goto_program_instructions(it, program)
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
Abstract interface to support a programming language.
Field-insensitive, location-sensitive bitvector analysis.
int isnan(double d)
Definition: math.c:163
API to expression classes for 'mathematical' expressions.
const quantifier_exprt & to_quantifier_expr(const exprt &expr)
Cast an exprt to a quantifier_exprt.
std::unique_ptr< languaget > get_language_from_mode(const irep_idt &mode)
Get the language corresponding to the given mode.
Definition: mode.cpp:51
Options.
API to expression classes for Pointers.
const r_or_w_ok_exprt & to_r_or_w_ok_expr(const exprt &expr)
Definition: pointer_expr.h:949
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:890
bool can_cast_expr< object_size_exprt >(const exprt &base)
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const prophecy_r_or_w_ok_exprt & to_prophecy_r_or_w_ok_expr(const exprt &expr)
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
bool can_cast_expr< prophecy_r_or_w_ok_exprt >(const exprt &base)
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
std::optional< exprt > member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
std::optional< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
Pointer Logic.
exprt pointer_offset(const exprt &pointer)
exprt integer_address(const exprt &pointer)
exprt deallocated(const exprt &pointer, const namespacet &ns)
exprt object_size(const exprt &pointer)
exprt object_upper_bound(const exprt &pointer, const exprt &access_size)
exprt dead_object(const exprt &pointer, const namespacet &ns)
exprt same_object(const exprt &p1, const exprt &p2)
exprt null_object(const exprt &pointer)
exprt object_lower_bound(const exprt &pointer, const exprt &offset)
Various predicates over pointers in programs.
static std::string comment(const rw_set_baset::entryt &entry, bool write)
Definition: race_check.cpp:108
void remove_skip(goto_programt &goto_program, goto_programt::targett begin, goto_programt::targett end)
remove unnecessary skip statements
Definition: remove_skip.cpp:87
Program Transformation.
exprt simplify_expr(exprt src, const namespacet &ns)
#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
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:66
exprt disjunction(const exprt::operandst &op)
1) generates a disjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:54
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 mod_exprt & to_mod_expr(const exprt &expr)
Cast an exprt to a mod_exprt.
Definition: std_expr.h:1272
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const unary_minus_exprt & to_unary_minus_expr(const exprt &expr)
Cast an exprt to a unary_minus_exprt.
Definition: std_expr.h:514
const div_exprt & to_div_expr(const exprt &expr)
Cast an exprt to a div_exprt.
Definition: std_expr.h:1201
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition: std_expr.h:1086
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition: std_expr.h:987
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition: std_expr.h:715
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition: std_expr.h:1041
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2933
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition: std_expr.h:426
const implies_exprt & to_implies_expr(const exprt &expr)
Cast an exprt to a implies_exprt.
Definition: std_expr.h:2208
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition: std_expr.h:895
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const mult_exprt & to_mult_expr(const exprt &expr)
Cast an exprt to a mult_exprt.
Definition: std_expr.h:1132
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition: std_types.h:1104
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
enum configt::ansi_ct::c_standardt c_standard
enum configt::cppt::cpp_standardt cpp_standard
conditiont(const exprt &_assertion, const std::string &_description)
#define size_type
Definition: unistd.c:347
dstringt irep_idt