CBMC
bv_pointers_wide.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 #include "bv_pointers_wide.h"
10 
11 #include <util/arith_tools.h>
12 #include <util/byte_operators.h>
13 #include <util/c_types.h>
14 #include <util/exception_utils.h>
15 #include <util/expr_util.h>
16 #include <util/namespace.h>
17 #include <util/pointer_expr.h>
20 
21 std::size_t bv_pointers_widet::get_object_width(const pointer_typet &type) const
22 {
23  return type.get_width();
24 }
25 
26 std::size_t bv_pointers_widet::get_offset_width(const pointer_typet &type) const
27 {
28  const std::size_t pointer_width = 2 * type.get_width();
29  const std::size_t object_width = get_object_width(type);
30  PRECONDITION(pointer_width >= object_width);
31  return pointer_width - object_width;
32 }
33 
35  const
36 {
37  const std::size_t offset_width = get_offset_width(type);
38  const std::size_t object_width = get_object_width(type);
39  PRECONDITION(bv.size() >= offset_width + object_width);
40 
41  return bvt(
42  bv.begin() + offset_width, bv.begin() + offset_width + object_width);
43 }
44 
46  const
47 {
48  const std::size_t offset_width = get_offset_width(type);
49  PRECONDITION(bv.size() >= offset_width);
50 
51  return bvt(bv.begin(), bv.begin() + offset_width);
52 }
53 
55  const bvt &object,
56  const bvt &offset)
57 {
58  bvt result;
59  result.reserve(offset.size() + object.size());
60  result.insert(result.end(), offset.begin(), offset.end());
61  result.insert(result.end(), object.begin(), object.end());
62 
63  return result;
64 }
65 
67 {
68  PRECONDITION(expr.type().id() == ID_bool);
69 
70  const exprt::operandst &operands = expr.operands();
71 
72  if(expr.id() == ID_is_invalid_pointer)
73  {
74  if(operands.size() == 1 && operands[0].type().id() == ID_pointer)
75  {
76  const bvt &bv = convert_bv(operands[0]);
77 
78  if(!bv.empty())
79  {
80  const pointer_typet &type = to_pointer_type(operands[0].type());
81  bvt object_bv = object_literals(bv, type);
82 
83  bvt invalid_bv = object_literals(
84  encode(pointer_logic.get_invalid_object(), type), type);
85 
86  const std::size_t object_bits = get_object_width(type);
87 
88  bvt equal_invalid_bv;
89  equal_invalid_bv.reserve(object_bits);
90 
91  for(std::size_t i = 0; i < object_bits; i++)
92  {
93  equal_invalid_bv.push_back(prop.lequal(object_bv[i], invalid_bv[i]));
94  }
95 
96  return prop.land(equal_invalid_bv);
97  }
98  }
99  }
100  else if(expr.id() == ID_is_dynamic_object)
101  {
102  if(operands.size() == 1 && operands[0].type().id() == ID_pointer)
103  {
104  // we postpone
105  literalt l = prop.new_variable();
106 
107  postponed_list.emplace_back(bvt{1, l}, convert_bv(operands[0]), expr);
108 
109  return l;
110  }
111  }
112  else if(
113  expr.id() == ID_lt || expr.id() == ID_le || expr.id() == ID_gt ||
114  expr.id() == ID_ge)
115  {
116  if(
117  operands.size() == 2 && operands[0].type().id() == ID_pointer &&
118  operands[1].type().id() == ID_pointer)
119  {
120  const bvt &bv0 = convert_bv(operands[0]);
121  const bvt &bv1 = convert_bv(operands[1]);
122 
123  const pointer_typet &type0 = to_pointer_type(operands[0].type());
124  bvt offset_bv0 = offset_literals(bv0, type0);
125 
126  const pointer_typet &type1 = to_pointer_type(operands[1].type());
127  bvt offset_bv1 = offset_literals(bv1, type1);
128 
129  // Comparison over pointers to distinct objects is undefined behavior in
130  // C; we choose to always produce "false" in such a case. Alternatively,
131  // we could do a comparison over the integer representation of a pointer
132 
133  // do the same-object-test via an expression as this may permit re-using
134  // already cached encodings of the equality test
135  const exprt same_object = ::same_object(operands[0], operands[1]);
136  const literalt same_object_lit = convert(same_object);
137  if(same_object_lit.is_false())
138  return same_object_lit;
139 
140  return prop.land(
141  same_object_lit,
142  bv_utils.rel(
143  offset_bv0,
144  expr.id(),
145  offset_bv1,
147  UNSIGNED)); // Note the UNSIGNED comparison
148  }
149  }
150 
151  return SUB::convert_rest(expr);
152 }
153 
155  const namespacet &_ns,
156  propt &_prop,
157  message_handlert &message_handler,
158  bool get_array_constraints)
159  : boolbvt(_ns, _prop, message_handler, get_array_constraints),
160  pointer_logic(_ns)
161 {
162 }
163 
164 std::optional<bvt> bv_pointers_widet::convert_address_of_rec(const exprt &expr)
165 {
166  if(expr.id() == ID_symbol)
167  {
168  return add_addr(expr);
169  }
170  else if(expr.id() == ID_label)
171  {
172  return add_addr(expr);
173  }
174  else if(expr.id() == ID_null_object)
175  {
176  pointer_typet pt = pointer_type(expr.type());
177  return encode(pointer_logic.get_null_object(), pt);
178  }
179  else if(expr.id() == ID_index)
180  {
181  const index_exprt &index_expr = to_index_expr(expr);
182  const exprt &array = index_expr.array();
183  const exprt &index = index_expr.index();
184  const auto &array_type = to_array_type(array.type());
185 
186  pointer_typet type = pointer_type(expr.type());
187  const std::size_t bits = boolbv_width(type);
188 
189  bvt bv;
190 
191  // recursive call
192  if(array_type.id() == ID_pointer)
193  {
194  // this should be gone
195  bv = convert_pointer_type(array);
196  CHECK_RETURN(bv.size() == bits);
197  }
198  else if(
199  array_type.id() == ID_array || array_type.id() == ID_string_constant)
200  {
201  auto bv_opt = convert_address_of_rec(array);
202  if(!bv_opt.has_value())
203  return {};
204  bv = std::move(*bv_opt);
205  CHECK_RETURN(bv.size() == bits);
206  }
207  else
208  UNREACHABLE;
209 
210  // get size
211  auto size = pointer_offset_size(array_type.element_type(), ns);
212  CHECK_RETURN(size.has_value() && *size >= 0);
213 
214  bv = offset_arithmetic(type, bv, *size, index);
215  CHECK_RETURN(bv.size() == bits);
216 
217  return std::move(bv);
218  }
219  else if(
220  expr.id() == ID_byte_extract_little_endian ||
221  expr.id() == ID_byte_extract_big_endian)
222  {
223  const auto &byte_extract_expr = to_byte_extract_expr(expr);
224 
225  // recursive call
226  auto bv_opt = convert_address_of_rec(byte_extract_expr.op());
227  if(!bv_opt.has_value())
228  return {};
229 
230  pointer_typet type = pointer_type(expr.type());
231  const std::size_t bits = boolbv_width(type);
232  CHECK_RETURN(bv_opt->size() == bits);
233 
234  bvt bv = offset_arithmetic(type, *bv_opt, 1, byte_extract_expr.offset());
235  CHECK_RETURN(bv.size() == bits);
236  return std::move(bv);
237  }
238  else if(expr.id() == ID_member)
239  {
240  const member_exprt &member_expr = to_member_expr(expr);
241  const exprt &struct_op = member_expr.compound();
242 
243  // recursive call
244  auto bv_opt = convert_address_of_rec(struct_op);
245  if(!bv_opt.has_value())
246  return {};
247 
248  bvt bv = std::move(*bv_opt);
249  if(struct_op.type().id() == ID_struct_tag)
250  {
251  auto offset = member_offset(
252  ns.follow_tag(to_struct_tag_type(struct_op.type())),
253  member_expr.get_component_name(),
254  ns);
255  CHECK_RETURN(offset.has_value());
256 
257  // add offset
258  pointer_typet type = pointer_type(expr.type());
259  bv = offset_arithmetic(type, bv, *offset);
260  }
261  else
262  {
263  INVARIANT(
264  struct_op.type().id() == ID_union_tag,
265  "member expression should operate on struct or union");
266  // nothing to do, all members have offset 0
267  }
268 
269  return std::move(bv);
270  }
271  else if(
272  expr.is_constant() || expr.id() == ID_string_constant ||
273  expr.id() == ID_array)
274  { // constant
275  return add_addr(expr);
276  }
277  else if(expr.id() == ID_if)
278  {
279  const if_exprt &ifex = to_if_expr(expr);
280 
281  literalt cond = convert(ifex.cond());
282 
283  bvt bv1, bv2;
284 
285  auto bv1_opt = convert_address_of_rec(ifex.true_case());
286  if(!bv1_opt.has_value())
287  return {};
288 
289  auto bv2_opt = convert_address_of_rec(ifex.false_case());
290  if(!bv2_opt.has_value())
291  return {};
292 
293  return bv_utils.select(cond, *bv1_opt, *bv2_opt);
294  }
295 
296  return {};
297 }
298 
300 {
301  const pointer_typet &type = to_pointer_type(expr.type());
302 
303  const std::size_t bits = boolbv_width(expr.type());
304 
305  if(expr.id() == ID_symbol)
306  {
307  const irep_idt &identifier = to_symbol_expr(expr).get_identifier();
308 
309  return map.get_literals(identifier, type, bits);
310  }
311  else if(expr.id() == ID_nondet_symbol)
312  {
313  return prop.new_variables(bits);
314  }
315  else if(expr.id() == ID_typecast)
316  {
317  const typecast_exprt &typecast_expr = to_typecast_expr(expr);
318 
319  const exprt &op = typecast_expr.op();
320  const typet &op_type = op.type();
321 
322  if(op_type.id() == ID_pointer)
323  return convert_bv(op);
324  else if(
325  can_cast_type<bitvector_typet>(op_type) || op_type.id() == ID_bool ||
326  op_type.id() == ID_c_enum || op_type.id() == ID_c_enum_tag)
327  {
328  // Cast from a bitvector type 'i' to pointer.
329  // 1) top bit not set: NULL + i, zero extended
330  // 2) top bit set: numbered pointer
331  const bvt &op_bv = convert_bv(op);
332  auto top_bit = op_bv.back();
333  const auto numbered_pointer_bv = prop.new_variables(bits);
334 
335  for(std::size_t i = 1; i < numbered_pointers.size(); i++)
336  {
337  auto cond = bv_utils.equal(
338  op_bv,
340  bv_utilst::build_constant(i, op_bv.size() - 1),
341  {const_literal(true)}));
343  cond,
345  numbered_pointer_bv);
346  }
347 
348  auto null_object_bv = object_offset_encoding(
353  {const_literal(false)}));
354 
355  return bv_utils.select(top_bit, numbered_pointer_bv, null_object_bv);
356  }
357  }
358  else if(expr.id() == ID_if)
359  {
360  return SUB::convert_if(to_if_expr(expr));
361  }
362  else if(expr.id() == ID_index)
363  {
364  return SUB::convert_index(to_index_expr(expr));
365  }
366  else if(expr.id() == ID_member)
367  {
368  return SUB::convert_member(to_member_expr(expr));
369  }
370  else if(expr.id() == ID_address_of)
371  {
372  const address_of_exprt &address_of_expr = to_address_of_expr(expr);
373 
374  auto bv_opt = convert_address_of_rec(address_of_expr.op());
375  if(!bv_opt.has_value())
376  return conversion_failed(address_of_expr);
377 
378  CHECK_RETURN(bv_opt->size() == bits);
379  return *bv_opt;
380  }
381  else if(expr.id() == ID_object_address)
382  {
383  const auto &object_address_expr = to_object_address_expr(expr);
384  return add_addr(object_address_expr.object_expr());
385  }
386  else if(expr.is_constant())
387  {
388  const constant_exprt &c = to_constant_expr(expr);
389 
390  if(c.is_null_pointer())
391  return encode(pointer_logic.get_null_object(), type);
392  else
393  {
394  mp_integer i = bvrep2integer(c.get_value(), bits, false);
395  return bv_utils.build_constant(i, bits);
396  }
397  }
398  else if(expr.id() == ID_plus)
399  {
400  // this has to be pointer plus integer
401 
402  const plus_exprt &plus_expr = to_plus_expr(expr);
403 
404  bvt bv;
405 
406  mp_integer size = 0;
407  std::size_t count = 0;
408 
409  for(const auto &op : plus_expr.operands())
410  {
411  if(op.type().id() == ID_pointer)
412  {
413  count++;
414  bv = convert_bv(op);
415  CHECK_RETURN(bv.size() == bits);
416 
417  typet pointer_base_type = to_pointer_type(op.type()).base_type();
419  pointer_base_type.id() != ID_empty,
420  "no pointer arithmetic over void pointers");
421  auto size_opt = pointer_offset_size(pointer_base_type, ns);
422  CHECK_RETURN(size_opt.has_value() && *size_opt >= 0);
423  size = *size_opt;
424  }
425  }
426 
427  INVARIANT(
428  count == 1,
429  "there should be exactly one pointer-type operand in a pointer-type sum");
430 
431  const std::size_t offset_bits = get_offset_width(type);
432  bvt sum = bv_utils.build_constant(0, offset_bits);
433 
434  for(const auto &op : plus_expr.operands())
435  {
436  if(op.type().id() == ID_pointer)
437  continue;
438 
439  if(op.type().id() != ID_unsignedbv && op.type().id() != ID_signedbv)
440  {
441  return conversion_failed(plus_expr);
442  }
443 
444  bv_utilst::representationt rep = op.type().id() == ID_signedbv
447 
448  bvt op_bv = convert_bv(op);
449  CHECK_RETURN(!op_bv.empty());
450 
451  op_bv = bv_utils.extension(op_bv, offset_bits, rep);
452 
453  sum = bv_utils.add(sum, op_bv);
454  }
455 
456  return offset_arithmetic(type, bv, size, sum);
457  }
458  else if(expr.id() == ID_minus)
459  {
460  // this is pointer-integer
461 
462  const minus_exprt &minus_expr = to_minus_expr(expr);
463 
464  INVARIANT(
465  minus_expr.lhs().type().id() == ID_pointer,
466  "first operand should be of pointer type");
467 
468  if(
469  minus_expr.rhs().type().id() != ID_unsignedbv &&
470  minus_expr.rhs().type().id() != ID_signedbv)
471  {
472  return conversion_failed(minus_expr);
473  }
474 
475  const unary_minus_exprt neg_op1(minus_expr.rhs());
476 
477  const bvt &bv = convert_bv(minus_expr.lhs());
478 
479  typet pointer_base_type =
480  to_pointer_type(minus_expr.lhs().type()).base_type();
482  pointer_base_type.id() != ID_empty,
483  "no pointer arithmetic over void pointers");
484  auto element_size_opt = pointer_offset_size(pointer_base_type, ns);
485  CHECK_RETURN(element_size_opt.has_value() && *element_size_opt > 0);
486  return offset_arithmetic(type, bv, *element_size_opt, neg_op1);
487  }
488  else if(
489  expr.id() == ID_byte_extract_little_endian ||
490  expr.id() == ID_byte_extract_big_endian)
491  {
493  }
494  else if(
495  expr.id() == ID_byte_update_little_endian ||
496  expr.id() == ID_byte_update_big_endian)
497  {
499  }
500  else if(expr.id() == ID_field_address)
501  {
502  const auto &field_address_expr = to_field_address_expr(expr);
503 
504  // recursive call
505  auto bv = convert_bitvector(field_address_expr.base());
506 
507  if(field_address_expr.compound_type().id() == ID_struct_tag)
508  {
509  auto offset = member_offset(
510  ns.follow_tag(to_struct_tag_type(field_address_expr.compound_type())),
511  field_address_expr.component_name(),
512  ns);
513  CHECK_RETURN(offset.has_value());
514 
515  // add offset
516  bv = offset_arithmetic(field_address_expr.type(), bv, *offset);
517  }
518  else if(field_address_expr.compound_type().id() == ID_union_tag)
519  {
520  // nothing to do, all fields have offset 0
521  }
522  else
523  {
524  INVARIANT(false, "field address expressions operate on struct or union");
525  }
526 
527  return bv;
528  }
529  else if(expr.id() == ID_element_address)
530  {
531  const auto &element_address_expr = to_element_address_expr(expr);
532 
533  // recursive call
534  auto bv = convert_bitvector(element_address_expr.base());
535 
536  // get element size
537  auto size = pointer_offset_size(element_address_expr.element_type(), ns);
538  CHECK_RETURN(size.has_value() && *size >= 0);
539 
540  // add offset
541  bv = offset_arithmetic(
542  element_address_expr.type(), bv, *size, element_address_expr.index());
543 
544  return bv;
545  }
546 
547  return conversion_failed(expr);
548 }
549 
550 static bool is_pointer_subtraction(const exprt &expr)
551 {
552  if(expr.id() != ID_minus)
553  return false;
554 
555  const auto &minus_expr = to_minus_expr(expr);
556 
557  return minus_expr.lhs().type().id() == ID_pointer &&
558  minus_expr.rhs().type().id() == ID_pointer;
559 }
560 
562 {
563  if(expr.type().id() == ID_pointer)
564  return convert_pointer_type(expr);
565 
566  if(is_pointer_subtraction(expr))
567  {
568  std::size_t width = boolbv_width(expr.type());
569 
570  if(width == 0)
571  return conversion_failed(expr);
572 
573  // pointer minus pointer is subtraction over the offset divided by element
574  // size, iff the pointers point to the same object
575  const auto &minus_expr = to_minus_expr(expr);
576 
577  // do the same-object-test via an expression as this may permit re-using
578  // already cached encodings of the equality test
579  const exprt same_object = ::same_object(minus_expr.lhs(), minus_expr.rhs());
580  const literalt same_object_lit = convert(same_object);
581 
582  // compute the object size (again, possibly using cached results)
583  const exprt object_size = ::object_size(minus_expr.lhs());
584  const bvt object_size_bv =
586 
587  bvt bv = prop.new_variables(width);
588 
589  if(!same_object_lit.is_false())
590  {
591  const pointer_typet &lhs_pt = to_pointer_type(minus_expr.lhs().type());
592  const bvt &lhs = convert_bv(minus_expr.lhs());
593  const bvt lhs_offset =
594  bv_utils.sign_extension(offset_literals(lhs, lhs_pt), width);
595 
596  const literalt lhs_in_bounds = prop.land(
597  !bv_utils.sign_bit(lhs_offset),
598  bv_utils.rel(
599  lhs_offset,
600  ID_le,
601  object_size_bv,
603 
604  const pointer_typet &rhs_pt = to_pointer_type(minus_expr.rhs().type());
605  const bvt &rhs = convert_bv(minus_expr.rhs());
606  const bvt rhs_offset =
607  bv_utils.sign_extension(offset_literals(rhs, rhs_pt), width);
608 
609  const literalt rhs_in_bounds = prop.land(
610  !bv_utils.sign_bit(rhs_offset),
611  bv_utils.rel(
612  rhs_offset,
613  ID_le,
614  object_size_bv,
616 
617  bvt difference = bv_utils.sub(lhs_offset, rhs_offset);
618 
620  lhs_pt.base_type().id() != ID_empty,
621  "no pointer arithmetic over void pointers");
622  auto element_size_opt = pointer_offset_size(lhs_pt.base_type(), ns);
623  CHECK_RETURN(element_size_opt.has_value() && *element_size_opt > 0);
624 
625  if(*element_size_opt != 1)
626  {
627  bvt element_size_bv = bv_utils.build_constant(*element_size_opt, width);
628  difference = bv_utils.divider(
629  difference, element_size_bv, bv_utilst::representationt::SIGNED);
630  }
631 
633  prop.land(same_object_lit, prop.land(lhs_in_bounds, rhs_in_bounds)),
634  bv_utils.equal(difference, bv)));
635  }
636 
637  return bv;
638  }
639  else if(
640  expr.id() == ID_pointer_offset &&
641  to_pointer_offset_expr(expr).pointer().type().id() == ID_pointer)
642  {
643  std::size_t width = boolbv_width(expr.type());
644 
645  if(width == 0)
646  return conversion_failed(expr);
647 
648  const exprt &pointer = to_pointer_offset_expr(expr).pointer();
649  const bvt &pointer_bv = convert_bv(pointer);
650 
651  bvt offset_bv =
652  offset_literals(pointer_bv, to_pointer_type(pointer.type()));
653 
654  // we do a sign extension to permit negative offsets
655  return bv_utils.sign_extension(offset_bv, width);
656  }
657  else if(
658  const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
659  {
660  // we postpone until we know the objects
661  std::size_t width = boolbv_width(object_size->type());
662 
663  postponed_list.emplace_back(
664  prop.new_variables(width),
665  convert_bv(object_size->pointer()),
666  *object_size);
667 
668  return postponed_list.back().bv;
669  }
670  else if(
671  expr.id() == ID_pointer_object &&
672  to_pointer_object_expr(expr).pointer().type().id() == ID_pointer)
673  {
674  std::size_t width = boolbv_width(expr.type());
675 
676  if(width == 0)
677  return conversion_failed(expr);
678 
679  const exprt &pointer = to_pointer_object_expr(expr).pointer();
680  const bvt &pointer_bv = convert_bv(pointer);
681 
682  bvt object_bv =
683  object_literals(pointer_bv, to_pointer_type(pointer.type()));
684 
685  return bv_utils.zero_extension(object_bv, width);
686  }
687  else if(
688  expr.id() == ID_typecast &&
689  to_typecast_expr(expr).op().type().id() == ID_pointer)
690  {
691  // Pointer to int.
692  // We special-case NULL, which should always yield 0.
693  // Otherwise, we 'number' these, which are indicated by setting
694  // the top bit.
695  const auto &pointer_expr = to_typecast_expr(expr).op();
696  const bvt pointer_bv = convert_pointer_type(pointer_expr);
697  const auto is_null = bv_utils.is_zero(pointer_bv);
698  const auto target_width = boolbv_width(expr.type());
699 
700  if(target_width == 0)
701  return conversion_failed(expr);
702 
703  if(numbered_pointers.empty())
704  numbered_pointers.emplace_back(bvt{});
705 
706  const auto number = numbered_pointers.size();
707 
708  numbered_pointers.push_back(pointer_bv);
709 
710  return bv_utils.select(
711  is_null,
712  bv_utils.zeros(target_width),
714  bv_utils.build_constant(number, target_width - 1),
715  {const_literal(true)}));
716  }
717 
718  return SUB::convert_bitvector(expr);
719 }
720 
721 static std::string bits_to_string(const propt &prop, const bvt &bv)
722 {
723  std::string result;
724 
725  for(const auto &literal : bv)
726  {
727  char ch = 0;
728 
729  // clang-format off
730  switch(prop.l_get(literal).get_value())
731  {
732  case tvt::tv_enumt::TV_FALSE: ch = '0'; break;
733  case tvt::tv_enumt::TV_TRUE: ch = '1'; break;
734  case tvt::tv_enumt::TV_UNKNOWN: ch = '0'; break;
735  }
736  // clang-format on
737 
738  result = ch + result;
739  }
740 
741  return result;
742 }
743 
745  const exprt &expr,
746  const bvt &bv,
747  std::size_t offset) const
748 {
749  const auto &type = expr.type();
750 
751  if(type.id() != ID_pointer)
752  return SUB::bv_get_rec(expr, bv, offset);
753 
754  const pointer_typet &pt = to_pointer_type(type);
755  const std::size_t bits = boolbv_width(pt);
756  bvt value_bv(bv.begin() + offset, bv.begin() + offset + bits);
757 
758  std::string value = bits_to_string(prop, value_bv);
759  std::string value_addr = bits_to_string(prop, object_literals(value_bv, pt));
760  std::string value_offset =
761  bits_to_string(prop, offset_literals(value_bv, pt));
762 
763  // we treat these like bit-vector constants, but with
764  // some additional annotation
765 
766  const irep_idt bvrep = make_bvrep(bits, [&value](std::size_t i) {
767  return value[value.size() - 1 - i] == '1';
768  });
769 
770  constant_exprt result(bvrep, type);
771 
772  pointer_logict::pointert pointer{
773  numeric_cast_v<std::size_t>(binary2integer(value_addr, false)),
774  binary2integer(value_offset, false)};
775 
777  bvrep, pointer_logic.pointer_expr(pointer, pt)};
778 }
779 
781  const
782 {
783  const std::size_t offset_bits = get_offset_width(type);
784  const std::size_t object_bits = get_object_width(type);
785 
786  bvt zero_offset(offset_bits, const_literal(false));
787  bvt object = bv_utils.build_constant(addr, object_bits);
788 
789  return object_offset_encoding(object, zero_offset);
790 }
791 
793  const pointer_typet &type,
794  const bvt &bv,
795  const mp_integer &x)
796 {
797  const std::size_t offset_bits = get_offset_width(type);
798 
799  return offset_arithmetic(
800  type, bv, 1, bv_utils.build_constant(x, offset_bits));
801 }
802 
804  const pointer_typet &type,
805  const bvt &bv,
806  const mp_integer &factor,
807  const exprt &index)
808 {
809  bvt bv_index = convert_bv(index);
810 
811  bv_utilst::representationt rep = index.type().id() == ID_signedbv
814 
815  const std::size_t offset_bits = get_offset_width(type);
816  bv_index = bv_utils.extension(bv_index, offset_bits, rep);
817 
818  return offset_arithmetic(type, bv, factor, bv_index);
819 }
820 
822  const pointer_typet &type,
823  const bvt &bv,
824  const mp_integer &factor,
825  const bvt &index)
826 {
827  bvt bv_index;
828 
829  if(factor == 1)
830  bv_index = index;
831  else
832  {
833  bvt bv_factor = bv_utils.build_constant(factor, index.size());
834  bv_index = bv_utils.signed_multiplier(index, bv_factor);
835  }
836 
837  const std::size_t offset_bits = get_offset_width(type);
838  bv_index = bv_utils.sign_extension(bv_index, offset_bits);
839 
840  bvt offset_bv = offset_literals(bv, type);
841 
842  bvt bv_tmp = bv_utils.add(offset_bv, bv_index);
843 
844  return object_offset_encoding(object_literals(bv, type), bv_tmp);
845 }
846 
848 {
849  const auto a = pointer_logic.add_object(expr);
850 
851  const pointer_typet type = pointer_type(expr.type());
852  const std::size_t object_bits = get_object_width(type);
853  const std::size_t max_objects = std::size_t(1) << object_bits;
854 
855  if(a == max_objects)
856  throw analysis_exceptiont(
857  "too many addressed objects: maximum number of objects is set to 2^n=" +
858  std::to_string(max_objects) + " (with n=" + std::to_string(object_bits) +
859  "); " +
860  "use the `--object-bits n` option to increase the maximum number");
861 
862  return encode(a, type);
863 }
864 
866 {
867  if(postponed.expr.id() == ID_is_dynamic_object)
868  {
869  const auto &type =
870  to_pointer_type(to_unary_expr(postponed.expr).op().type());
871  const auto &objects = pointer_logic.objects;
872  std::size_t number = 0;
873 
874  for(auto it = objects.cbegin(); it != objects.cend(); ++it, ++number)
875  {
876  const exprt &expr = *it;
877 
879 
880  // only compare object part
881  pointer_typet pt = pointer_type(expr.type());
882  bvt bv = object_literals(encode(number, pt), type);
883 
884  bvt saved_bv = object_literals(postponed.op, type);
885 
886  POSTCONDITION(bv.size() == saved_bv.size());
887  PRECONDITION(postponed.bv.size() == 1);
888 
889  literalt l1 = bv_utils.equal(bv, saved_bv);
890  literalt l2 = postponed.bv.front();
891 
892  if(!is_dynamic)
893  l2 = !l2;
894 
895  prop.l_set_to_true(prop.limplies(l1, l2));
896  }
897  }
898  else if(
899  const auto postponed_object_size =
900  expr_try_dynamic_cast<object_size_exprt>(postponed.expr))
901  {
902  const auto &type = to_pointer_type(postponed_object_size->pointer().type());
903  const auto &objects = pointer_logic.objects;
904  std::size_t number = 0;
905 
906  for(auto it = objects.cbegin(); it != objects.cend(); ++it, ++number)
907  {
908  const exprt &expr = *it;
909 
910  if(expr.id() != ID_symbol && expr.id() != ID_string_constant)
911  continue;
912 
913  const auto size_expr = size_of_expr(expr.type(), ns);
914 
915  if(!size_expr.has_value())
916  continue;
917 
919  size_expr.value(), postponed_object_size->type());
920 
921  // only compare object part
922  pointer_typet pt = pointer_type(expr.type());
923  bvt bv = object_literals(encode(number, pt), type);
924 
925  bvt saved_bv = object_literals(postponed.op, type);
926 
927  bvt size_bv = convert_bv(object_size);
928 
929  POSTCONDITION(bv.size() == saved_bv.size());
930  PRECONDITION(postponed.bv.size() >= 1);
931  PRECONDITION(size_bv.size() == postponed.bv.size());
932 
933  literalt l1 = bv_utils.equal(bv, saved_bv);
934  literalt l2 = bv_utils.equal(postponed.bv, size_bv);
935 
936  prop.l_set_to_true(prop.limplies(l1, l2));
937  }
938  }
939  else
940  UNREACHABLE;
941 }
942 
944 {
945  // post-processing arrays may yield further objects, do this first
947 
948  for(postponed_listt::const_iterator it = postponed_list.begin();
949  it != postponed_list.end();
950  it++)
951  do_postponed(*it);
952 
953  // Clear the list to avoid re-doing in case of incremental usage.
954  postponed_list.clear();
955 }
mp_integer bvrep2integer(const irep_idt &src, std::size_t width, bool is_signed)
convert a bit-vector representation (possibly signed) to integer
irep_idt make_bvrep(const std::size_t width, const std::function< bool(std::size_t)> f)
construct a bit-vector representation from a functor
static std::string bits_to_string(const propt &prop, const bvt &bv)
static bool is_pointer_subtraction(const exprt &expr)
Expression classes for byte-level operators.
const byte_update_exprt & to_byte_update_expr(const exprt &expr)
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
pointer_typet pointer_type(const typet &subtype)
Definition: c_types.cpp:235
Operator to return the address of an object.
Definition: pointer_expr.h:540
Thrown when an unexpected error occurs during the analysis (e.g., when the SAT solver returns an erro...
Pointer-typed bitvector constant annotated with the pointer expression that the bitvector is the nume...
const namespacet & ns
Definition: arrays.h:56
exprt & lhs()
Definition: std_expr.h:668
exprt & rhs()
Definition: std_expr.h:678
std::size_t get_width() const
Definition: std_types.h:925
const bvt & get_literals(const irep_idt &identifier, const typet &type, std::size_t width)
Definition: boolbv_map.cpp:41
Definition: boolbv.h:46
virtual bvt convert_index(const exprt &array, const mp_integer &index)
index operator with constant index
virtual const bvt & convert_bv(const exprt &expr, const std::optional< std::size_t > expected_width={})
Convert expression to vector of literalts, using an internal cache to speed up conversion if availabl...
Definition: boolbv.cpp:39
virtual bvt convert_byte_extract(const byte_extract_exprt &expr)
virtual bvt convert_bitvector(const exprt &expr)
Converts an expression into its gate-level representation and returns a vector of literals correspond...
Definition: boolbv.cpp:108
virtual exprt bv_get_rec(const exprt &expr, const bvt &bv, std::size_t offset) const
Definition: boolbv_get.cpp:52
virtual bvt convert_member(const member_exprt &expr)
virtual bvt convert_if(const if_exprt &expr)
Definition: boolbv_if.cpp:12
virtual bvt convert_byte_update(const byte_update_exprt &expr)
void finish_eager_conversion() override
Definition: boolbv.h:80
bv_utilst bv_utils
Definition: boolbv.h:117
bvt conversion_failed(const exprt &expr)
Print that the expression of x has failed conversion, then return a vector of x's width.
Definition: boolbv.cpp:94
literalt convert_rest(const exprt &expr) override
Definition: boolbv.cpp:334
boolbv_mapt map
Definition: boolbv.h:123
bv_pointers_widet(const namespacet &, propt &, message_handlert &, bool get_array_constraints=false)
virtual bvt convert_pointer_type(const exprt &)
bvt object_literals(const bvt &bv, const pointer_typet &type) const
Given a pointer encoded in bv, extract the literals identifying the object that the pointer points to...
literalt convert_rest(const exprt &) override
bvt convert_bitvector(const exprt &) override
Converts an expression into its gate-level representation and returns a vector of literals correspond...
std::size_t get_object_width(const pointer_typet &) const
static bvt object_offset_encoding(const bvt &object, const bvt &offset)
Construct a pointer encoding from given encodings of object and offset.
bvt encode(const mp_integer &object, const pointer_typet &) const
std::vector< bvt > numbered_pointers
Table that maps a 'pointer number' to its full-width bit-vector.
pointer_logict pointer_logic
postponed_listt postponed_list
bvt offset_arithmetic(const pointer_typet &, const bvt &, const mp_integer &)
std::optional< bvt > convert_address_of_rec(const exprt &)
void do_postponed(const postponedt &postponed)
exprt bv_get_rec(const exprt &, const bvt &, std::size_t offset) const override
virtual bvt add_addr(const exprt &)
void finish_eager_conversion() override
std::size_t get_offset_width(const pointer_typet &) const
bvt offset_literals(const bvt &bv, const pointer_typet &type) const
Given a pointer encoded in bv, extract the literals representing the offset into an object that the p...
std::size_t boolbv_width(const typet &type) const override
static literalt sign_bit(const bvt &op)
Definition: bv_utils.h:138
bvt add(const bvt &op0, const bvt &op1)
Definition: bv_utils.h:66
static bvt zero_extension(const bvt &bv, std::size_t new_size)
Definition: bv_utils.h:187
bvt select(literalt s, const bvt &a, const bvt &b)
If s is true, selects a otherwise selects b.
Definition: bv_utils.cpp:95
static bvt build_constant(const mp_integer &i, std::size_t width)
Definition: bv_utils.cpp:14
literalt is_zero(const bvt &op)
Definition: bv_utils.h:143
literalt equal(const bvt &op0, const bvt &op1)
Bit-blasting ID_equal and use in other encodings.
Definition: bv_utils.cpp:1369
bvt signed_multiplier(const bvt &op0, const bvt &op1)
Definition: bv_utils.cpp:1003
void cond_implies_equal(literalt cond, const bvt &a, const bvt &b)
Definition: bv_utils.cpp:1595
static bvt concatenate(const bvt &a, const bvt &b)
Definition: bv_utils.cpp:79
representationt
Definition: bv_utils.h:28
bvt sub(const bvt &op0, const bvt &op1)
Definition: bv_utils.h:67
bvt divider(const bvt &op0, const bvt &op1, representationt rep)
Definition: bv_utils.h:89
static bvt extension(const bvt &bv, std::size_t new_size, representationt rep)
Definition: bv_utils.cpp:108
static bvt zeros(std::size_t new_size)
Definition: bv_utils.h:192
literalt rel(const bvt &bv0, irep_idt id, const bvt &bv1, representationt rep)
Definition: bv_utils.cpp:1562
static bvt sign_extension(const bvt &bv, std::size_t new_size)
Definition: bv_utils.h:182
A constant literal expression.
Definition: std_expr.h:3000
const irep_idt & get_value() const
Definition: std_expr.h:3008
bool is_null_pointer() const
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Definition: std_expr.cpp:25
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
typet & type()
Return the type of the expression.
Definition: expr.h:84
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
operandst & operands()
Definition: expr.h:94
The trinary if-then-else operator.
Definition: std_expr.h:2380
exprt & true_case()
Definition: std_expr.h:2407
exprt & false_case()
Definition: std_expr.h:2417
exprt & cond()
Definition: std_expr.h:2397
Array index operator.
Definition: std_expr.h:1470
exprt & array()
Definition: std_expr.h:1500
exprt & index()
Definition: std_expr.h:1510
const irep_idt & id() const
Definition: irep.h:388
bool is_false() const
Definition: literal.h:161
Extract member of struct or union.
Definition: std_expr.h:2854
const exprt & compound() const
Definition: std_expr.h:2903
irep_idt get_component_name() const
Definition: std_expr.h:2876
Binary minus.
Definition: std_expr.h:1061
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
const mp_integer & get_invalid_object() const
Definition: pointer_logic.h:58
numberingt< exprt, irep_hash > objects
Definition: pointer_logic.h:26
exprt pointer_expr(const pointert &pointer, const pointer_typet &type) const
Convert an (object,offset) pair to an expression.
mp_integer add_object(const exprt &expr)
const mp_integer & get_null_object() const
Definition: pointer_logic.h:52
bool is_dynamic_object(const exprt &expr) const
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
literalt convert(const exprt &expr) override
Convert a Boolean expression and return the corresponding literal.
TO_BE_DOCUMENTED.
Definition: prop.h:25
void l_set_to_true(literalt a)
Definition: prop.h:52
virtual literalt land(literalt a, literalt b)=0
virtual literalt limplies(literalt a, literalt b)=0
virtual bvt new_variables(std::size_t width)
generates a bitvector of given width with new variables
Definition: prop.cpp:30
virtual literalt new_variable()=0
virtual literalt lequal(literalt a, literalt b)=0
virtual tvt l_get(literalt a) const =0
const irep_idt & get_identifier() const
Definition: std_expr.h:160
tv_enumt get_value() const
Definition: threeval.h:40
Semantic type conversion.
Definition: std_expr.h:2073
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2081
The type of an expression, extends irept.
Definition: type.h:29
const exprt & op() const
Definition: std_expr.h:391
The unary minus expression.
Definition: std_expr.h:484
Deprecated expression utility functions.
std::vector< literalt > bvt
Definition: literal.h:201
literalt const_literal(bool value)
Definition: literal.h:188
const mp_integer binary2integer(const std::string &n, bool is_signed)
convert binary string representation to mp_integer
Definition: mp_arith.cpp:117
static bool is_dynamic(const exprt &object)
This function returns true for heap allocated objects or false for stack allocated objects.
API to expression classes for Pointers.
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
const field_address_exprt & to_field_address_expr(const exprt &expr)
Cast an exprt to an field_address_exprt.
Definition: pointer_expr.h:727
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
const object_address_exprt & to_object_address_expr(const exprt &expr)
Cast an exprt to an object_address_exprt.
Definition: pointer_expr.h:643
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
const element_address_exprt & to_element_address_expr(const exprt &expr)
Cast an exprt to an element_address_exprt.
Definition: pointer_expr.h:814
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
std::optional< mp_integer > member_offset(const struct_typet &type, const irep_idt &member, 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 object_size(const exprt &pointer)
exprt same_object(const exprt &p1, const exprt &p2)
Various predicates over pointers in programs.
BigInt mp_integer
Definition: smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
#define POSTCONDITION(CONDITION)
Definition: invariant.h:479
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2460
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3055
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2107
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition: std_expr.h:1086
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:2946
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition: std_expr.h:426
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1538
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:518
bool can_cast_type< bitvector_typet >(const typet &type)
Check whether a reference to a typet is a bitvector_typet.
Definition: std_types.h:952
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
static exprt is_null(const array_string_exprt &string, array_poolt &array_pool)
Expression which is true when the string is equal to the literal "null".