Skip to content

Commit 87bcf4a

Browse files
committed
Add special case for deref-of-typecast-of-if
This results from expressions such as *(int*)*p, and is very nearly as easy to handle as the already-special-cased deref-of-if case. In essence we transform *(type*)(x ? y : z) into x ? *(type*)y : *(type*)z, which should yield a more compact expression due to not conflating the alias sets that can be derived from the two arms of the conditional.
1 parent 7552bad commit 87bcf4a

File tree

3 files changed

+24
-4
lines changed

3 files changed

+24
-4
lines changed

regression/cbmc/double_deref/README

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ operator, such as **p, *(int*)*p, p->field1->field2, etc. At present a directly
88
(p == &o1 ? (o1 == &o3 ? o3 : o4) : (o2 == &o5 ? o5 : o6))
99

1010
This deref operator push-in is performed (implicitly) by value_set_dereferencet::dereference, which special-cases
11-
the ternary conditional expression.
11+
the ternary conditional expression and typecasts of ternary conditionals.
1212
More complicated expressions are handled using a let-expression. Example:
1313

1414
p->field1->field2 ==>
@@ -21,7 +21,7 @@ result = (derefd_pointer == &o3 ? o3 : derefd_pointer == &o4 ? o4 : derefd_point
2121

2222
The tests in this directory check that auxiliary let-expressions like this are only used when appropriate by inspecting formula VCCs:
2323
double_deref.desc -- a directly nested double-dereference, should not use a let-expression
24-
double_deref_with_cast.desc -- a double-deref with an intervening cast (*(int*)*p for example), should use a let-expression
24+
double_deref_with_cast.desc -- a double-deref with an intervening cast (*(int*)*p for example), should not use a let-expression
2525
double_deref_with_member.desc -- a double-deref with an intervening member expression (p->field1->field2), should use a let-expression
2626
double_deref_with_pointer_arithmetic.desc -- a double-deref with intervening pointer arithmetic (p[idx1][idx2]), should use a let-expression
2727
*_single_alias.desc -- variants of the above where the first dereference points to a single possible object, so no let-expression is necessary
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
CORE
22
double_deref_with_cast.c
33
--show-vcc
4-
^\{-[0-9]+\} derefd_pointer::derefd_pointer!0#1 =
5-
^\{1\} \(derefd_pointer::derefd_pointer!0#1 = address_of\(symex_dynamic::dynamic_object[1-9]+\) \? main::argc!0@1#1 = [12] : main::argc!0@1#1 = [12]
4+
\{1\} \(cast\(main::1::pptr!0@1#2, signedbv\[32\]\*\*\) = address_of\(main::1::ptr2!0@1\) \? main::argc!0@1#1 = 2 \: main::argc!0@1#1 = 1\)
65
^EXIT=0$
76
^SIGNAL=0$
87
--
8+
derefd_pointer::derefd_pointer
99
--
1010
See README for details about these tests

src/pointer-analysis/value_set_dereference.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,26 @@ exprt value_set_dereferencet::dereference(const exprt &pointer)
7272
exprt false_case = dereference(if_expr.false_case());
7373
return if_exprt(if_expr.cond(), true_case, false_case);
7474
}
75+
else if(pointer.id() == ID_typecast)
76+
{
77+
const exprt *underlying = &pointer;
78+
// Note this isn't quite the same as skip_typecast, which would also skip
79+
// things such as int-to-ptr typecasts which we shouldn't ignore
80+
while(underlying->id() == ID_typecast &&
81+
underlying->type().id() == ID_pointer)
82+
{
83+
underlying = &to_typecast_expr(*underlying).op();
84+
}
85+
86+
if(underlying->id() == ID_if && underlying->type().id() == ID_pointer)
87+
{
88+
const auto &if_expr = to_if_expr(*underlying);
89+
return if_exprt(
90+
if_expr.cond(),
91+
dereference(typecast_exprt(if_expr.true_case(), pointer.type())),
92+
dereference(typecast_exprt(if_expr.false_case(), pointer.type())));
93+
}
94+
}
7595

7696
// type of the object
7797
const typet &type=pointer.type().subtype();

0 commit comments

Comments
 (0)