Skip to content

Commit 1c3f275

Browse files
authored
Merge pull request #6560 from tautschnig/value-set-ptr-arithmetic
Value sets should permit any order of operands in pointer arithmetic
2 parents c391c08 + 87a1563 commit 1c3f275

File tree

4 files changed

+81
-18
lines changed

4 files changed

+81
-18
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
struct S
2+
{
3+
int *p;
4+
int s;
5+
};
6+
7+
union U {
8+
struct S st;
9+
int i;
10+
};
11+
12+
int main()
13+
{
14+
int x;
15+
int *ip = &x;
16+
17+
union U u;
18+
u.st.p = ip;
19+
u.st.s = 1;
20+
21+
int A[2] = {42, 43};
22+
// the following should behave the same as "int *p = A + u.st.s;"
23+
int *p = u.st.s + A;
24+
assert(*p == 43);
25+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
main.c
3+
--program-only
4+
ASSERT\(\{ 42, 43 \}\[POINTER_OFFSET\(p!0@1#2\) / \d+l*\] == 43\)$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
p\$object
9+
^warning: ignoring
10+
--
11+
Value sets should be sufficiently precise to infer that dereferencing p is an
12+
access into the array at some offset, and not an access into any other object
13+
(or perhaps the invalid object). If that were the case, the assert instruction
14+
would include "p$object," the absence of which we check for in the above.

regression/validate-trace-xml-schema/check.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
['show_properties1', 'test.desc'],
3131
# program-only instead of trace
3232
['vla1', 'program-only.desc'],
33+
['Pointer_Arithmetic19', 'test.desc'],
3334
['Quantifiers-simplify', 'simplify_not_forall.desc'],
3435
['array-cell-sensitivity15', 'test.desc'],
3536
# these test for invalid command line handling

src/pointer-analysis/value_set.cpp

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -634,30 +634,45 @@ void value_sett::get_value_set_rec(
634634
object_mapt pointer_expr_set;
635635
optionalt<mp_integer> i;
636636

637-
// special case for pointer+integer
638-
637+
// special case for plus/minus and exactly one pointer
638+
optionalt<exprt> ptr_operand;
639639
if(
640-
expr.operands().size() == 2 && expr_type.id() == ID_pointer &&
640+
expr_type.id() == ID_pointer &&
641641
(expr.id() == ID_plus || expr.id() == ID_minus))
642642
{
643-
exprt ptr_operand;
644-
645-
if(
646-
to_binary_expr(expr).op0().type().id() != ID_pointer &&
647-
to_binary_expr(expr).op0().is_constant())
648-
{
649-
i = numeric_cast<mp_integer>(to_binary_expr(expr).op0());
650-
ptr_operand = to_binary_expr(expr).op1();
651-
}
652-
else
643+
bool non_const_offset = false;
644+
for(const auto &op : expr.operands())
653645
{
654-
i = numeric_cast<mp_integer>(to_binary_expr(expr).op1());
655-
ptr_operand = to_binary_expr(expr).op0();
646+
if(op.type().id() == ID_pointer)
647+
{
648+
if(ptr_operand.has_value())
649+
{
650+
ptr_operand.reset();
651+
break;
652+
}
653+
654+
ptr_operand = op;
655+
}
656+
else if(!non_const_offset)
657+
{
658+
auto offset = numeric_cast<mp_integer>(op);
659+
if(!offset.has_value())
660+
{
661+
i.reset();
662+
non_const_offset = true;
663+
}
664+
else
665+
{
666+
if(!i.has_value())
667+
i = mp_integer{0};
668+
i = *i + *offset;
669+
}
670+
}
656671
}
657672

658-
if(i.has_value())
673+
if(ptr_operand.has_value() && i.has_value())
659674
{
660-
typet pointer_sub_type=ptr_operand.type().subtype();
675+
typet pointer_sub_type = ptr_operand->type().subtype();
661676
if(pointer_sub_type.id()==ID_empty)
662677
pointer_sub_type=char_type();
663678

@@ -672,12 +687,20 @@ void value_sett::get_value_set_rec(
672687
*i *= *size;
673688

674689
if(expr.id()==ID_minus)
690+
{
691+
DATA_INVARIANT(
692+
to_minus_expr(expr).lhs() == *ptr_operand,
693+
"unexpected subtraction of pointer from integer");
675694
i->negate();
695+
}
676696
}
677697
}
698+
}
678699

700+
if(ptr_operand.has_value())
701+
{
679702
get_value_set_rec(
680-
ptr_operand, pointer_expr_set, "", ptr_operand.type(), ns);
703+
*ptr_operand, pointer_expr_set, "", ptr_operand->type(), ns);
681704
}
682705
else
683706
{

0 commit comments

Comments
 (0)