@@ -15,6 +15,7 @@ Author: Daniel Kroening, kroening@kroening.com
1515#include < util/exception_utils.h>
1616#include < util/pointer_expr.h>
1717#include < util/pointer_offset_size.h>
18+ #include < util/pointer_predicates.h>
1819
1920// / Map bytes according to the configured endianness. The key difference to
2021// / endianness_mapt is that bv_endianness_mapt is aware of the bit-level
@@ -555,43 +556,82 @@ bvt bv_pointerst::convert_bitvector(const exprt &expr)
555556
556557 if (is_pointer_subtraction (expr))
557558 {
558- // pointer minus pointer
559- const auto &minus_expr = to_minus_expr (expr);
560- bvt lhs = convert_bv (minus_expr.lhs ());
561- bvt rhs = convert_bv (minus_expr.rhs ());
562-
563559 std::size_t width=boolbv_width (expr.type ());
564560
565561 if (width==0 )
566562 return conversion_failed (expr);
567563
568- // we do a zero extension
569- lhs = bv_utils. zero_extension (lhs, width);
570- rhs = bv_utils. zero_extension (rhs, width );
564+ // pointer minus pointer is subtraction over the offset divided by element
565+ // size, iff the pointers point to the same object
566+ const auto &minus_expr = to_minus_expr (expr );
571567
572- bvt bv = bv_utils.sub (lhs, rhs);
568+ // do the same-object-test via an expression as this may permit re-using
569+ // already cached encodings of the equality test
570+ const exprt same_object = ::same_object (minus_expr.lhs (), minus_expr.rhs ());
571+ const bvt &same_object_bv = convert_bv (same_object);
572+ CHECK_RETURN (same_object_bv.size () == 1 );
573573
574- typet pointer_sub_type = minus_expr.lhs ().type ().subtype ();
575- mp_integer element_size;
574+ // compute the object size (again, possibly using cached results)
575+ const exprt object_size = ::object_size (minus_expr.lhs ());
576+ const bvt object_size_bv =
577+ bv_utils.zero_extension (convert_bv (object_size), width);
576578
577- if (pointer_sub_type.id ()==ID_empty)
579+ bvt bv;
580+ bv.reserve (width);
581+
582+ for (std::size_t i = 0 ; i < width; ++i)
583+ bv.push_back (prop.new_variable ());
584+
585+ if (!same_object_bv[0 ].is_false ())
578586 {
579- // This is a gcc extension.
587+ const pointer_typet &lhs_pt = to_pointer_type (minus_expr.lhs ().type ());
588+ const bvt &lhs = convert_bv (minus_expr.lhs ());
589+ const bvt lhs_offset =
590+ bv_utils.sign_extension (offset_literals (lhs, lhs_pt), width);
591+
592+ const literalt lhs_in_bounds = prop.land (
593+ !bv_utils.sign_bit (lhs_offset),
594+ bv_utils.rel (
595+ lhs_offset,
596+ ID_le,
597+ object_size_bv,
598+ bv_utilst::representationt::UNSIGNED));
599+
600+ const pointer_typet &rhs_pt = to_pointer_type (minus_expr.rhs ().type ());
601+ const bvt &rhs = convert_bv (minus_expr.rhs ());
602+ const bvt rhs_offset =
603+ bv_utils.sign_extension (offset_literals (rhs, rhs_pt), width);
604+
605+ const literalt rhs_in_bounds = prop.land (
606+ !bv_utils.sign_bit (rhs_offset),
607+ bv_utils.rel (
608+ rhs_offset,
609+ ID_le,
610+ object_size_bv,
611+ bv_utilst::representationt::UNSIGNED));
612+
613+ bvt difference = bv_utils.sub (lhs_offset, rhs_offset);
614+
615+ // Support for void* is a gcc extension, with the size treated as 1 byte
616+ // (no division required below).
580617 // https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Pointer-Arith.html
581- element_size = 1 ;
582- }
583- else
584- {
585- auto element_size_opt = pointer_offset_size (pointer_sub_type, ns);
586- CHECK_RETURN (element_size_opt.has_value () && *element_size_opt > 0 );
587- element_size = *element_size_opt;
588- }
618+ if (lhs_pt.subtype ().id () != ID_empty)
619+ {
620+ auto element_size_opt = pointer_offset_size (lhs_pt.subtype (), ns);
621+ CHECK_RETURN (element_size_opt.has_value () && *element_size_opt > 0 );
589622
590- if (element_size != 1 )
591- {
592- bvt element_size_bv = bv_utils.build_constant (element_size, bv.size ());
593- bv=bv_utils.divider (
594- bv, element_size_bv, bv_utilst::representationt::SIGNED);
623+ if (*element_size_opt != 1 )
624+ {
625+ bvt element_size_bv =
626+ bv_utils.build_constant (*element_size_opt, width);
627+ difference = bv_utils.divider (
628+ difference, element_size_bv, bv_utilst::representationt::SIGNED);
629+ }
630+ }
631+
632+ prop.l_set_to_true (prop.limplies (
633+ prop.land (same_object_bv[0 ], prop.land (lhs_in_bounds, rhs_in_bounds)),
634+ bv_utils.equal (difference, bv)));
595635 }
596636
597637 return bv;
@@ -794,11 +834,11 @@ bvt bv_pointerst::offset_arithmetic(
794834 else
795835 {
796836 bvt bv_factor=bv_utils.build_constant (factor, index.size ());
797- bv_index= bv_utils.unsigned_multiplier (index, bv_factor);
837+ bv_index = bv_utils.signed_multiplier (index, bv_factor);
798838 }
799839
800840 const std::size_t offset_bits = bv_pointers_width.get_offset_width (type);
801- bv_index = bv_utils.zero_extension (bv_index, offset_bits);
841+ bv_index = bv_utils.sign_extension (bv_index, offset_bits);
802842
803843 bvt offset_bv = offset_literals (bv, type);
804844
0 commit comments