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  {
1755  if(property_class == "division-by-zero")
1756  annotated_location.property_fatal(true);
1757 
1759  std::move(guarded_expr), annotated_location));
1760  }
1761  }
1762 }
1763 
1765 {
1766  // we don't look into quantifiers
1767  if(expr.id() == ID_exists || expr.id() == ID_forall)
1768  return;
1769 
1770  if(expr.id() == ID_dereference)
1771  {
1772  check_rec(to_dereference_expr(expr).pointer(), guard);
1773  }
1774  else if(expr.id() == ID_index)
1775  {
1776  const index_exprt &index_expr = to_index_expr(expr);
1777  check_rec_address(index_expr.array(), guard);
1778  check_rec(index_expr.index(), guard);
1779  }
1780  else
1781  {
1782  for(const auto &operand : expr.operands())
1783  check_rec_address(operand, guard);
1784  }
1785 }
1786 
1788 {
1789  PRECONDITION(
1790  expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_implies);
1791  INVARIANT(
1792  expr.is_boolean(),
1793  "'" + expr.id_string() + "' must be Boolean, but got " + expr.pretty());
1794 
1795  exprt::operandst constraints;
1796 
1797  for(const auto &op : expr.operands())
1798  {
1799  INVARIANT(
1800  op.is_boolean(),
1801  "'" + expr.id_string() + "' takes Boolean operands only, but got " +
1802  op.pretty());
1803 
1804  auto new_guard = [&guard, &constraints](exprt expr) {
1805  return guard(implication(conjunction(constraints), expr));
1806  };
1807 
1808  check_rec(op, new_guard);
1809 
1810  constraints.push_back(expr.id() == ID_or ? boolean_negate(op) : op);
1811  }
1812 }
1813 
1814 void goto_check_ct::check_rec_if(const if_exprt &if_expr, const guardt &guard)
1815 {
1816  INVARIANT(
1817  if_expr.cond().is_boolean(),
1818  "first argument of if must be boolean, but got " + if_expr.cond().pretty());
1819 
1820  check_rec(if_expr.cond(), guard);
1821 
1822  {
1823  auto new_guard = [&guard, &if_expr](exprt expr) {
1824  return guard(implication(if_expr.cond(), std::move(expr)));
1825  };
1826  check_rec(if_expr.true_case(), new_guard);
1827  }
1828 
1829  {
1830  auto new_guard = [&guard, &if_expr](exprt expr) {
1831  return guard(implication(not_exprt(if_expr.cond()), std::move(expr)));
1832  };
1833  check_rec(if_expr.false_case(), new_guard);
1834  }
1835 }
1836 
1838  const member_exprt &member,
1839  const guardt &guard)
1840 {
1841  const dereference_exprt &deref = to_dereference_expr(member.struct_op());
1842 
1843  check_rec(deref.pointer(), guard);
1844 
1845  // avoid building the following expressions when pointer_validity_check
1846  // would return immediately anyway
1848  return true;
1849 
1850  // we rewrite s->member into *(s+member_offset)
1851  // to avoid requiring memory safety of the entire struct
1852  auto member_offset_opt = member_offset_expr(member, ns);
1853 
1854  if(member_offset_opt.has_value())
1855  {
1856  pointer_typet new_pointer_type = to_pointer_type(deref.pointer().type());
1857  new_pointer_type.base_type() = member.type();
1858 
1859  const exprt char_pointer = typecast_exprt::conditional_cast(
1860  deref.pointer(), pointer_type(char_type()));
1861 
1862  const exprt new_address_casted = typecast_exprt::conditional_cast(
1863  plus_exprt{
1864  char_pointer,
1866  member_offset_opt.value(), pointer_diff_type())},
1867  new_pointer_type);
1868 
1869  dereference_exprt new_deref{new_address_casted};
1870  new_deref.add_source_location() = deref.source_location();
1871  pointer_validity_check(new_deref, member, guard);
1872 
1873  return true;
1874  }
1875  return false;
1876 }
1877 
1879  const div_exprt &div_expr,
1880  const guardt &guard)
1881 {
1882  if(
1883  div_expr.type().id() == ID_signedbv ||
1884  div_expr.type().id() == ID_unsignedbv || div_expr.type().id() == ID_c_bool)
1885  {
1886  // Division by zero is undefined behavior for all integer types.
1887  div_by_zero_check(to_div_expr(div_expr), guard);
1888  }
1889  else if(div_expr.type().id() == ID_floatbv)
1890  {
1891  // Division by zero on floating-point numbers may be undefined behavior.
1892  // Annex F of the ISO C21 suggests that implementations that
1893  // define __STDC_IEC_559__ follow IEEE 754 semantics,
1894  // which defines the outcome of division by zero.
1896  }
1897 
1898  if(div_expr.type().id() == ID_signedbv)
1899  integer_overflow_check(div_expr, guard);
1900  else if(div_expr.type().id() == ID_floatbv)
1901  {
1902  nan_check(div_expr, guard);
1903  float_overflow_check(div_expr, guard);
1904  }
1905 }
1906 
1908  const exprt &expr,
1909  const guardt &guard)
1910 {
1911  if(expr.type().id() == ID_signedbv || expr.type().id() == ID_unsignedbv)
1912  {
1914 
1915  if(
1916  expr.operands().size() == 2 && expr.id() == ID_minus &&
1917  expr.operands()[0].type().id() == ID_pointer &&
1918  expr.operands()[1].type().id() == ID_pointer)
1919  {
1921  }
1922  }
1923  else if(expr.type().id() == ID_floatbv)
1924  {
1925  nan_check(expr, guard);
1926  float_overflow_check(expr, guard);
1927  }
1928  else if(expr.type().id() == ID_pointer)
1929  {
1931  }
1932 }
1933 
1934 void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
1935 {
1936  if(expr.id() == ID_exists || expr.id() == ID_forall)
1937  {
1938  // the scoped variables may be used in the assertion
1939  const auto &quantifier_expr = to_quantifier_expr(expr);
1940 
1941  auto new_guard = [&guard, &quantifier_expr](exprt expr) {
1942  return guard(forall_exprt(quantifier_expr.symbol(), expr));
1943  };
1944 
1945  check_rec(quantifier_expr.where(), new_guard);
1946  return;
1947  }
1948  else if(expr.id() == ID_address_of)
1949  {
1950  check_rec_address(to_address_of_expr(expr).object(), guard);
1951  return;
1952  }
1953  else if(expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_implies)
1954  {
1955  check_rec_logical_op(expr, guard);
1956  return;
1957  }
1958  else if(expr.id() == ID_if)
1959  {
1960  check_rec_if(to_if_expr(expr), guard);
1961  return;
1962  }
1963  else if(
1964  expr.id() == ID_member &&
1965  to_member_expr(expr).struct_op().id() == ID_dereference)
1966  {
1968  return;
1969  }
1970 
1971  for(const auto &op : expr.operands())
1972  check_rec(op, guard);
1973 
1974  if(expr.type().id() == ID_c_enum_tag)
1975  enum_range_check(expr, guard);
1976 
1977  if(expr.id() == ID_index)
1978  {
1979  bounds_check(expr, guard);
1980  }
1981  else if(expr.id() == ID_div)
1982  {
1984  }
1985  else if(expr.id() == ID_shl || expr.id() == ID_ashr || expr.id() == ID_lshr)
1986  {
1988 
1989  if(expr.id() == ID_shl && expr.type().id() == ID_signedbv)
1991  }
1992  else if(expr.id() == ID_mod)
1993  {
1996  }
1997  else if(
1998  expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult ||
1999  expr.id() == ID_unary_minus)
2000  {
2002  }
2003  else if(expr.id() == ID_typecast)
2004  conversion_check(expr, guard);
2005  else if(
2006  expr.id() == ID_le || expr.id() == ID_lt || expr.id() == ID_ge ||
2007  expr.id() == ID_gt)
2009  else if(expr.id() == ID_dereference)
2010  {
2012  }
2013  else if(requires_pointer_primitive_check(expr))
2014  {
2016  }
2017  else if(
2018  expr.id() == ID_count_leading_zeros || expr.id() == ID_count_trailing_zeros)
2019  {
2020  bounds_check(expr, guard);
2021  }
2022 }
2023 
2024 void goto_check_ct::check(const exprt &expr)
2025 {
2026  check_rec(expr, identity);
2027 }
2028 
2030 {
2031  const symbolt &leak = ns.lookup(CPROVER_PREFIX "memory_leak");
2032  const symbol_exprt leak_expr = leak.symbol_expr();
2033 
2034  // add self-assignment to get helpful counterexample output
2035  new_code.add(goto_programt::make_assignment(leak_expr, leak_expr));
2036 
2037  source_locationt source_location;
2038  source_location.set_function(function_id);
2039 
2040  equal_exprt eq(leak_expr, null_pointer_exprt(to_pointer_type(leak.type)));
2041 
2043  eq,
2044  "dynamically allocated memory never freed",
2045  "memory-leak",
2046  source_location,
2047  eq,
2048  identity);
2049 }
2050 
2052  const irep_idt &function_identifier,
2053  goto_functiont &goto_function)
2054 {
2055  const auto &function_symbol = ns.lookup(function_identifier);
2056  mode = function_symbol.mode;
2057 
2058  if(mode != ID_C && mode != ID_cpp)
2059  return;
2060 
2061  assertions.clear();
2062 
2063  bool did_something = false;
2064 
2066  std::make_unique<local_bitvector_analysist>(goto_function, ns);
2067 
2068  goto_programt &goto_program = goto_function.body;
2069 
2070  Forall_goto_program_instructions(it, goto_program)
2071  {
2072  current_target = it;
2073  goto_programt::instructiont &i = *it;
2074 
2075  flag_overridet resetter(i.source_location());
2076  const auto &pragmas = i.source_location().get_pragmas();
2077  for(const auto &d : pragmas)
2078  {
2079  // match named-check related pragmas
2080  auto matched = match_named_check(d.first);
2081  if(matched.has_value())
2082  {
2083  auto named_check = matched.value();
2084  auto name = named_check.first;
2085  auto status = named_check.second;
2086  bool *flag = name_to_flag.find(name)->second;
2087  switch(status)
2088  {
2089  case check_statust::ENABLE:
2090  resetter.set_flag(*flag, true, name);
2091  break;
2092  case check_statust::DISABLE:
2093  resetter.set_flag(*flag, false, name);
2094  break;
2095  case check_statust::CHECKED:
2096  resetter.disable_flag(*flag, name);
2097  break;
2098  }
2099  }
2100  }
2101 
2102  // add checked pragmas for all active checks
2104 
2105  new_code.clear();
2106 
2107  // we clear all recorded assertions if
2108  // 1) we want to generate all assertions or
2109  // 2) the instruction is a branch target
2110  if(retain_trivial || i.is_target())
2111  assertions.clear();
2112 
2113  if(i.has_condition())
2114  {
2115  check(i.condition());
2116  }
2117 
2118  // magic ERROR label?
2119  for(const auto &label : error_labels)
2120  {
2121  if(std::find(i.labels.begin(), i.labels.end(), label) != i.labels.end())
2122  {
2123  source_locationt annotated_location = i.source_location();
2124  annotated_location.set_property_class("error label");
2125  annotated_location.set_comment("error label " + label);
2126  annotated_location.set("user-provided", true);
2127 
2129  {
2130  new_code.add(
2131  goto_programt::make_assumption(false_exprt{}, annotated_location));
2132  }
2133  else
2134  {
2135  new_code.add(
2136  goto_programt::make_assertion(false_exprt{}, annotated_location));
2137  }
2138  }
2139  }
2140 
2141  if(i.is_other())
2142  {
2143  const auto &code = i.get_other();
2144  const irep_idt &statement = code.get_statement();
2145 
2146  if(statement == ID_expression)
2147  {
2148  check(code);
2149  }
2150  else if(statement == ID_printf)
2151  {
2152  for(const auto &op : code.operands())
2153  check(op);
2154  }
2155  }
2156  else if(i.is_assign())
2157  {
2158  const exprt &assign_lhs = i.assign_lhs();
2159  const exprt &assign_rhs = i.assign_rhs();
2160 
2161  // Disable enum range checks for left-hand sides as their values are yet
2162  // to be set (by this assignment).
2163  {
2164  flag_overridet resetter(i.source_location());
2165  resetter.disable_flag(enable_enum_range_check, "enum_range_check");
2166  check(assign_lhs);
2167  }
2168 
2169  check(assign_rhs);
2170 
2171  // the LHS might invalidate any assertion
2172  invalidate(assign_lhs);
2173  }
2174  else if(i.is_function_call())
2175  {
2176  // Disable enum range checks for left-hand sides as their values are yet
2177  // to be set (by this function call).
2178  {
2179  flag_overridet resetter(i.source_location());
2180  resetter.disable_flag(enable_enum_range_check, "enum_range_check");
2181  check(i.call_lhs());
2182  }
2183  check(i.call_function());
2184 
2185  for(const auto &arg : i.call_arguments())
2186  check(arg);
2187 
2189 
2190  // the call might invalidate any assertion
2191  assertions.clear();
2192  }
2193  else if(i.is_set_return_value())
2194  {
2195  check(i.return_value());
2196  // the return value invalidate any assertion
2197  invalidate(i.return_value());
2198  }
2199  else if(i.is_throw())
2200  {
2201  // this has no successor
2202  assertions.clear();
2203  }
2204  else if(i.is_assume())
2205  {
2206  // These are further 'exit points' of the program
2207  const exprt simplified_guard = simplify_expr(i.condition(), ns);
2208  if(
2209  enable_memory_cleanup_check && simplified_guard.is_false() &&
2210  (function_identifier == "abort" || function_identifier == "exit" ||
2211  function_identifier == "_Exit" ||
2212  (i.labels.size() == 1 && i.labels.front() == "__VERIFIER_abort")))
2213  {
2214  memory_leak_check(function_identifier);
2215  }
2216  }
2217  else if(i.is_dead())
2218  {
2220  {
2221  const symbol_exprt &variable = i.dead_symbol();
2222 
2223  // is it dirty?
2224  if(local_bitvector_analysis->dirty(variable))
2225  {
2226  // need to mark the dead variable as dead
2227  exprt lhs = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
2228  exprt address_of_expr = typecast_exprt::conditional_cast(
2229  address_of_exprt(variable), lhs.type());
2230  if_exprt rhs(
2232  std::move(address_of_expr),
2233  lhs);
2235  code_assignt{std::move(lhs), std::move(rhs), i.source_location()},
2236  i.source_location()));
2237  }
2238  }
2239  }
2240  else if(i.is_end_function())
2241  {
2242  if(
2243  function_identifier == goto_functionst::entry_point() &&
2245  {
2246  memory_leak_check(function_identifier);
2247  }
2248  }
2249 
2250  for(auto &instruction : new_code.instructions)
2251  {
2252  if(instruction.source_location().is_nil())
2253  {
2254  instruction.source_location_nonconst().id(irep_idt());
2255 
2256  if(!it->source_location().get_file().empty())
2257  instruction.source_location_nonconst().set_file(
2258  it->source_location().get_file());
2259 
2260  if(!it->source_location().get_line().empty())
2261  instruction.source_location_nonconst().set_line(
2262  it->source_location().get_line());
2263 
2264  if(!it->source_location().get_function().empty())
2265  instruction.source_location_nonconst().set_function(
2266  it->source_location().get_function());
2267 
2268  if(!it->source_location().get_column().empty())
2269  {
2270  instruction.source_location_nonconst().set_column(
2271  it->source_location().get_column());
2272  }
2273  }
2274  }
2275 
2276  // insert new instructions -- make sure targets are not moved
2277  did_something |= !new_code.instructions.empty();
2278 
2279  while(!new_code.instructions.empty())
2280  {
2281  goto_program.insert_before_swap(it, new_code.instructions.front());
2282  new_code.instructions.pop_front();
2283  it++;
2284  }
2285  }
2286 
2287  if(did_something)
2288  remove_skip(goto_program);
2289 }
2290 
2292  const goto_programt::instructiont &i)
2293 {
2294  if(i.call_function().id() != ID_symbol)
2295  return;
2296 
2297  const irep_idt &identifier =
2299 
2300  if(
2301  identifier == CPROVER_PREFIX "get_field" || identifier == CPROVER_PREFIX
2302  "set_field")
2303  {
2304  const exprt &expr = i.call_arguments()[0];
2305  PRECONDITION(expr.type().id() == ID_pointer);
2306  check(dereference_exprt(expr));
2307  }
2308 }
2309 
2312  const exprt &address,
2313  const exprt &size)
2314 {
2316  PRECONDITION(address.type().id() == ID_pointer);
2319 
2320  conditionst conditions;
2321 
2322  const exprt in_bounds_of_some_explicit_allocation =
2324 
2325  const bool unknown = flags.is_unknown() || flags.is_uninitialized();
2326 
2327  if(unknown)
2328  {
2329  conditions.push_back(conditiont{
2330  not_exprt{is_invalid_pointer_exprt{address}}, "pointer invalid"});
2331  }
2332 
2333  if(unknown || flags.is_dynamic_heap())
2334  {
2335  conditions.push_back(conditiont(
2336  or_exprt(
2337  in_bounds_of_some_explicit_allocation,
2338  not_exprt(deallocated(address, ns))),
2339  "deallocated dynamic object"));
2340  }
2341 
2342  if(unknown || flags.is_dynamic_local())
2343  {
2344  conditions.push_back(conditiont(
2345  or_exprt(
2346  in_bounds_of_some_explicit_allocation,
2347  not_exprt(dead_object(address, ns))),
2348  "dead object"));
2349  }
2350 
2351  if(flags.is_dynamic_heap())
2352  {
2353  const or_exprt object_bounds_violation(
2354  object_lower_bound(address, nil_exprt()),
2355  object_upper_bound(address, size));
2356 
2357  conditions.push_back(conditiont(
2358  or_exprt(
2359  in_bounds_of_some_explicit_allocation,
2360  not_exprt(object_bounds_violation)),
2361  "pointer outside dynamic object bounds"));
2362  }
2363 
2364  if(unknown || flags.is_dynamic_local() || flags.is_static_lifetime())
2365  {
2366  const or_exprt object_bounds_violation(
2367  object_lower_bound(address, nil_exprt()),
2368  object_upper_bound(address, size));
2369 
2370  conditions.push_back(conditiont(
2371  or_exprt(
2372  in_bounds_of_some_explicit_allocation,
2373  not_exprt(object_bounds_violation)),
2374  "pointer outside object bounds"));
2375  }
2376 
2377  if(unknown || flags.is_integer_address())
2378  {
2379  conditions.push_back(conditiont(
2380  implies_exprt(
2381  integer_address(address), in_bounds_of_some_explicit_allocation),
2382  "invalid integer address"));
2383  }
2384 
2385  return conditions;
2386 }
2387 
2388 std::optional<goto_check_ct::conditiont>
2390  const exprt &address,
2391  const exprt &size)
2392 {
2394  PRECONDITION(address.type().id() == ID_pointer);
2397 
2398  if(flags.is_unknown() || flags.is_uninitialized() || flags.is_null())
2399  {
2400  return {conditiont{
2401  or_exprt{
2403  not_exprt(null_object(address))},
2404  "pointer NULL"}};
2405  }
2406 
2407  return {};
2408 }
2409 
2411  const exprt &pointer,
2412  const exprt &size)
2413 {
2414  exprt::operandst alloc_disjuncts;
2415  for(const auto &a : allocations)
2416  {
2417  typecast_exprt int_ptr(pointer, a.first.type());
2418 
2419  binary_relation_exprt lb_check(a.first, ID_le, int_ptr);
2420 
2421  plus_exprt upper_bound{
2422  int_ptr, typecast_exprt::conditional_cast(size, int_ptr.type())};
2423 
2424  binary_relation_exprt ub_check{
2425  std::move(upper_bound), ID_le, plus_exprt{a.first, a.second}};
2426 
2427  alloc_disjuncts.push_back(
2428  and_exprt{std::move(lb_check), std::move(ub_check)});
2429  }
2430  return disjunction(alloc_disjuncts);
2431 }
2432 
2434  const irep_idt &function_identifier,
2435  goto_functionst::goto_functiont &goto_function,
2436  const namespacet &ns,
2437  const optionst &options,
2438  message_handlert &message_handler)
2439 {
2440  goto_check_ct goto_check(ns, options, message_handler);
2441  goto_check.goto_check(function_identifier, goto_function);
2442 }
2443 
2445  const namespacet &ns,
2446  const optionst &options,
2447  goto_functionst &goto_functions,
2448  message_handlert &message_handler)
2449 {
2450  goto_check_ct goto_check(ns, options, message_handler);
2451 
2452  goto_check.collect_allocations(goto_functions);
2453 
2454  for(auto &gf_entry : goto_functions.function_map)
2455  {
2456  goto_check.goto_check(gf_entry.first, gf_entry.second);
2457  }
2458 }
2459 
2461  const optionst &options,
2462  goto_modelt &goto_model,
2463  message_handlert &message_handler)
2464 {
2465  const namespacet ns(goto_model.symbol_table);
2466  goto_check_c(ns, options, goto_model.goto_functions, message_handler);
2467 }
2468 
2470  source_locationt &source_location) const
2471 {
2472  for(const auto &entry : name_to_flag)
2473  if(*(entry.second))
2474  source_location.add_pragma("checked:" + id2string(entry.first));
2475 }
2476 
2478  source_locationt &source_location) const
2479 {
2480  for(const auto &entry : name_to_flag)
2481  source_location.add_pragma("checked:" + id2string(entry.first));
2482 }
2483 
2486 {
2487  auto s = id2string(named_check);
2488  auto col = s.find(":");
2489 
2490  if(col == std::string::npos)
2491  return {}; // separator not found
2492 
2493  auto name = s.substr(col + 1);
2494 
2495  if(name_to_flag.find(name) == name_to_flag.end())
2496  return {}; // name unknown
2497 
2498  check_statust status;
2499  if(!s.compare(0, 6, "enable"))
2500  status = check_statust::ENABLE;
2501  else if(!s.compare(0, 7, "disable"))
2502  status = check_statust::DISABLE;
2503  else if(!s.compare(0, 7, "checked"))
2504  status = check_statust::CHECKED;
2505  else
2506  return {}; // prefix unknow
2507 
2508  // success
2509  return std::pair<irep_idt, check_statust>{name, status};
2510 }
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)
bool property_fatal() const
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