|
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