Skip to content

Commit 53e7bf4

Browse files
authored
Merge pull request #7398 from tautschnig/bugfixes/pointer-subtraction
Fix pointer subtraction over integer constants
2 parents 6672791 + 087dabd commit 53e7bf4

File tree

4 files changed

+72
-23
lines changed

4 files changed

+72
-23
lines changed

regression/cbmc/Pointer_difference1/main.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,11 @@ int main()
88
unsigned int diff2 = &arrayOfInt [1] - arrayOfInt;
99
__CPROVER_assert(diff2==1, "pointer diff2");
1010

11+
int zero = (char **)8 - (char **)8;
12+
__CPROVER_assert(zero == 0, "should be zero");
13+
14+
int ten = (char *)20 - (char *)10;
15+
__CPROVER_assert(ten == 10, "should be ten");
16+
1117
return 0;
1218
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--no-simplify
4+
VERIFICATION SUCCESSFUL
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
^CONVERSION ERROR$

src/solvers/flattening/bv_pointers.cpp

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -625,11 +625,6 @@ bvt bv_pointerst::convert_bitvector(const exprt &expr)
625625
const exprt same_object = ::same_object(minus_expr.lhs(), minus_expr.rhs());
626626
const literalt same_object_lit = convert(same_object);
627627

628-
// compute the object size (again, possibly using cached results)
629-
const exprt object_size = ::object_size(minus_expr.lhs());
630-
const bvt object_size_bv =
631-
bv_utils.zero_extension(convert_bv(object_size), width);
632-
633628
bvt bv = prop.new_variables(width);
634629

635630
if(!same_object_lit.is_false())
@@ -639,27 +634,11 @@ bvt bv_pointerst::convert_bitvector(const exprt &expr)
639634
const bvt lhs_offset =
640635
bv_utils.sign_extension(offset_literals(lhs, lhs_pt), width);
641636

642-
const literalt lhs_in_bounds = prop.land(
643-
!bv_utils.sign_bit(lhs_offset),
644-
bv_utils.rel(
645-
lhs_offset,
646-
ID_le,
647-
object_size_bv,
648-
bv_utilst::representationt::UNSIGNED));
649-
650637
const pointer_typet &rhs_pt = to_pointer_type(minus_expr.rhs().type());
651638
const bvt &rhs = convert_bv(minus_expr.rhs());
652639
const bvt rhs_offset =
653640
bv_utils.sign_extension(offset_literals(rhs, rhs_pt), width);
654641

655-
const literalt rhs_in_bounds = prop.land(
656-
!bv_utils.sign_bit(rhs_offset),
657-
bv_utils.rel(
658-
rhs_offset,
659-
ID_le,
660-
object_size_bv,
661-
bv_utilst::representationt::UNSIGNED));
662-
663642
bvt difference = bv_utils.sub(lhs_offset, rhs_offset);
664643

665644
// Support for void* is a gcc extension, with the size treated as 1 byte
@@ -679,9 +658,39 @@ bvt bv_pointerst::convert_bitvector(const exprt &expr)
679658
}
680659
}
681660

661+
// test for null object (integer constants)
662+
const exprt null_object = ::null_object(minus_expr.lhs());
663+
literalt in_bounds = convert(null_object);
664+
665+
if(!in_bounds.is_true())
666+
{
667+
// compute the object size (again, possibly using cached results)
668+
const exprt object_size = ::object_size(minus_expr.lhs());
669+
const bvt object_size_bv =
670+
bv_utils.zero_extension(convert_bv(object_size), width);
671+
672+
const literalt lhs_in_bounds = prop.land(
673+
!bv_utils.sign_bit(lhs_offset),
674+
bv_utils.rel(
675+
lhs_offset,
676+
ID_le,
677+
object_size_bv,
678+
bv_utilst::representationt::UNSIGNED));
679+
680+
const literalt rhs_in_bounds = prop.land(
681+
!bv_utils.sign_bit(rhs_offset),
682+
bv_utils.rel(
683+
rhs_offset,
684+
ID_le,
685+
object_size_bv,
686+
bv_utilst::representationt::UNSIGNED));
687+
688+
in_bounds =
689+
prop.lor(in_bounds, prop.land(lhs_in_bounds, rhs_in_bounds));
690+
}
691+
682692
prop.l_set_to_true(prop.limplies(
683-
prop.land(same_object_lit, prop.land(lhs_in_bounds, rhs_in_bounds)),
684-
bv_utils.equal(difference, bv)));
693+
prop.land(same_object_lit, in_bounds), bv_utils.equal(difference, bv)));
685694
}
686695

687696
return bv;

src/util/simplify_expr_int.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ simplify_exprt::simplify_minus(const minus_exprt &expr)
616616
if(
617617
offset_op0.is_constant() && offset_op1.is_constant() &&
618618
object_size.has_value() && element_size.has_value() &&
619+
element_size->is_constant() && !element_size->is_zero() &&
619620
numeric_cast_v<mp_integer>(to_constant_expr(offset_op0)) <=
620621
*object_size &&
621622
numeric_cast_v<mp_integer>(to_constant_expr(offset_op1)) <=
@@ -626,6 +627,30 @@ simplify_exprt::simplify_minus(const minus_exprt &expr)
626627
typecast_exprt{*element_size, minus_expr.type()}}));
627628
}
628629
}
630+
631+
const exprt &ptr_op0_skipped_tc = skip_typecast(ptr_op0);
632+
const exprt &ptr_op1_skipped_tc = skip_typecast(ptr_op1);
633+
if(
634+
is_number(ptr_op0_skipped_tc.type()) &&
635+
is_number(ptr_op1_skipped_tc.type()))
636+
{
637+
exprt offset_op0 = simplify_pointer_offset(
638+
pointer_offset_exprt{operands[0], minus_expr.type()});
639+
exprt offset_op1 = simplify_pointer_offset(
640+
pointer_offset_exprt{operands[1], minus_expr.type()});
641+
642+
auto element_size =
643+
size_of_expr(to_pointer_type(operands[0].type()).base_type(), ns);
644+
645+
if(
646+
element_size.has_value() && element_size->is_constant() &&
647+
!element_size->is_zero())
648+
{
649+
return changed(simplify_rec(div_exprt{
650+
minus_exprt{offset_op0, offset_op1},
651+
typecast_exprt{*element_size, minus_expr.type()}}));
652+
}
653+
}
629654
}
630655

631656
return unchanged(expr);

0 commit comments

Comments
 (0)