Skip to content

Commit 87a1563

Browse files
committed
Value sets should permit any order of operands in pointer arithmetic
Previously, only <integer-constant> +/- pointer or pointer-as-first-operand worked correctly. In all other cases, value sets did not recurse on the correct operand.
1 parent b79bd51 commit 87a1563

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
@@ -633,30 +633,45 @@ void value_sett::get_value_set_rec(
633633
object_mapt pointer_expr_set;
634634
optionalt<mp_integer> i;
635635

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

657-
if(i.has_value())
672+
if(ptr_operand.has_value() && i.has_value())
658673
{
659-
typet pointer_sub_type=ptr_operand.type().subtype();
674+
typet pointer_sub_type = ptr_operand->type().subtype();
660675
if(pointer_sub_type.id()==ID_empty)
661676
pointer_sub_type=char_type();
662677

@@ -671,12 +686,20 @@ void value_sett::get_value_set_rec(
671686
*i *= *size;
672687

673688
if(expr.id()==ID_minus)
689+
{
690+
DATA_INVARIANT(
691+
to_minus_expr(expr).lhs() == *ptr_operand,
692+
"unexpected subtraction of pointer from integer");
674693
i->negate();
694+
}
675695
}
676696
}
697+
}
677698

699+
if(ptr_operand.has_value())
700+
{
678701
get_value_set_rec(
679-
ptr_operand, pointer_expr_set, "", ptr_operand.type(), ns);
702+
*ptr_operand, pointer_expr_set, "", ptr_operand->type(), ns);
680703
}
681704
else
682705
{

0 commit comments

Comments
 (0)