Skip to content

Commit 40bca65

Browse files
committed
Field sensitivity: account for array size in all index expressions
When code outside the core field-sensitivity implementation produces index expressions we must not blindly turn such expressions into ssa_exprt.
1 parent c66ffbe commit 40bca65

File tree

3 files changed

+72
-17
lines changed

3 files changed

+72
-17
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
union U
2+
{
3+
unsigned char buf[2];
4+
} s;
5+
6+
int main()
7+
{
8+
__CPROVER_assert(s.buf[0] == 0, "");
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--max-field-sensitivity-array-size 1
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
9+
The test is a minimized version of code generated using Kani. It should pass
10+
irrespective of whether field sensitivity is applied to the array or not. (The
11+
original example was unexpectedly failing with an array size of 65, but passed
12+
with an array size of 64 or less.)

src/goto-symex/field_sensitivity.cpp

+51-17
Original file line numberDiff line numberDiff line change
@@ -111,34 +111,68 @@ exprt field_sensitivityt::apply(
111111
const member_exprt member{tmp.get_original_expr(), comp};
112112
auto recursive_member =
113113
get_subexpression_at_offset(member, be.offset(), be.type(), ns);
114-
if(
115-
recursive_member.has_value() &&
116-
(recursive_member->id() == ID_member ||
117-
recursive_member->id() == ID_index))
114+
if(!recursive_member.has_value())
115+
continue;
116+
117+
// We need to inspect the access path as the resulting expression may
118+
// involve index expressions. When array field sensitivity is disabled
119+
// or the size of the array that is indexed into is larger than
120+
// max_field_sensitivity_array_size then only the expression up to (but
121+
// excluding) said index expression can be turned into an ssa_exprt.
122+
exprt full_exprt = *recursive_member;
123+
exprt *for_ssa = &full_exprt;
124+
exprt *parent = for_ssa;
125+
while(parent->id() == ID_typecast)
126+
parent = &to_typecast_expr(*parent).op();
127+
while(parent->id() == ID_member || parent->id() == ID_index)
118128
{
119-
tmp.type() = be.type();
120-
tmp.set_expression(*recursive_member);
129+
if(parent->id() == ID_member)
130+
{
131+
parent = &to_member_expr(*parent).compound();
132+
}
133+
else
134+
{
135+
parent = &to_index_expr(*parent).array();
136+
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
137+
if(
138+
!to_array_type(parent->type()).size().is_constant() ||
139+
numeric_cast_v<mp_integer>(
140+
to_constant_expr(to_array_type(parent->type()).size())) >
141+
max_field_sensitivity_array_size)
142+
{
143+
for_ssa = parent;
144+
}
145+
#else
146+
for_ssa = parent;
147+
#endif // ENABLE_ARRAY_FIELD_SENSITIVITY
148+
}
149+
}
150+
151+
if(for_ssa->id() == ID_index || for_ssa->id() == ID_member)
152+
{
153+
tmp.type() = for_ssa->type();
154+
tmp.set_expression(*for_ssa);
121155
if(was_l2)
122156
{
123-
return apply(
124-
ns, state, state.rename(std::move(tmp), ns).get(), write);
157+
*for_ssa =
158+
apply(ns, state, state.rename(std::move(tmp), ns).get(), write);
125159
}
126160
else
127-
return apply(ns, state, std::move(tmp), write);
161+
*for_ssa = apply(ns, state, std::move(tmp), write);
162+
163+
return full_exprt;
128164
}
129-
else if(
130-
recursive_member.has_value() && recursive_member->id() == ID_typecast)
165+
else if(for_ssa->id() == ID_typecast)
131166
{
132167
if(was_l2)
133168
{
134-
return apply(
135-
ns,
136-
state,
137-
state.rename(std::move(*recursive_member), ns).get(),
138-
write);
169+
*for_ssa =
170+
apply(ns, state, state.rename(*for_ssa, ns).get(), write);
139171
}
140172
else
141-
return apply(ns, state, std::move(*recursive_member), write);
173+
*for_ssa = apply(ns, state, std::move(*for_ssa), write);
174+
175+
return full_exprt;
142176
}
143177
}
144178
}

0 commit comments

Comments
 (0)