|
15 | 15 | #include <util/exception_utils.h>
|
16 | 16 | #include <util/pointer_expr.h>
|
17 | 17 | #include <util/pointer_offset_size.h>
|
| 18 | +#include <util/pointer_predicates.h> |
18 | 19 |
|
19 | 20 | /// Map bytes according to the configured endianness. The key difference to
|
20 | 21 | /// 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)
|
555 | 556 |
|
556 | 557 | if(is_pointer_subtraction(expr))
|
557 | 558 | {
|
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 |
| - |
563 | 559 | std::size_t width=boolbv_width(expr.type());
|
564 | 560 |
|
565 | 561 | if(width==0)
|
566 | 562 | return conversion_failed(expr);
|
567 | 563 |
|
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); |
571 | 567 |
|
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); |
573 | 573 |
|
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); |
576 | 578 |
|
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()) |
578 | 586 | {
|
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). |
580 | 617 | // 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); |
589 | 622 |
|
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))); |
595 | 635 | }
|
596 | 636 |
|
597 | 637 | return bv;
|
@@ -794,11 +834,11 @@ bvt bv_pointerst::offset_arithmetic(
|
794 | 834 | else
|
795 | 835 | {
|
796 | 836 | 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); |
798 | 838 | }
|
799 | 839 |
|
800 | 840 | 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); |
802 | 842 |
|
803 | 843 | bvt offset_bv = offset_literals(bv, type);
|
804 | 844 |
|
|
0 commit comments