Skip to content

Commit 5ff4248

Browse files
committed
SPLIT
1 parent e625f46 commit 5ff4248

File tree

11 files changed

+195
-41
lines changed

11 files changed

+195
-41
lines changed

regression/cbmc/array-cell-sensitivity15/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ access.c
33
--program-only
44
^EXIT=0$
55
^SIGNAL=0$
6-
s!0@1#1\.\.n == \{ s!0@1#1\.\.n\[\[0\]\], s!0@1#1\.\.n\[\[1\]\], s!0@1#1\.\.n\[\[2\]\], s!0@1#1\.\.n\[\[3\]\] } WITH \[\(.*\)i!0@1#2:=k!0@1#1\]
6+
s!0@1#2\.\.n == \{ s!0@1#1\.\.n\[\[0\]\], s!0@1#1\.\.n\[\[1\]\], s!0@1#1\.\.n\[\[2\]\], s!0@1#1\.\.n\[\[3\]\] } WITH \[\(.*\)i!0@1#2:=k!0@1#1\]
77
--
88
byte_update
99
--

regression/cbmc/array-cell-sensitivity8/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ main::1::array!0@1#2\[\[6\]\] =
1010
main::1::array!0@1#2\[\[7\]\] =
1111
main::1::array!0@1#2\[\[8\]\] =
1212
main::1::array!0@1#2\[\[9\]\] =
13-
main::1::array!0@1#2 =.*byte_extract_little_endian
13+
main::1::array!0@1#3 =.*byte_extract_little_endian
1414
main::1::array!0@1#3\[\[0\]\] =
1515
main::1::array!0@1#3\[\[1\]\] =
1616
main::1::array!0@1#3\[\[2\]\] =

regression/cbmc/field-sensitivity9/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CORE
22
test.c
33
--show-vcc
4-
main::1::a1!0@1#1 =
5-
main::1::a2!0@1#1 =
4+
main::1::a1!0@1#2 =
5+
main::1::a2!0@1#2 =
66
main::1::a1!0@1#2\.\.x =
77
main::1::a1!0@1#2\.\.y =
88
main::1::a1!0@1#2\.\.z =

src/goto-symex/field_sensitivity.cpp

Lines changed: 117 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ Author: Michael Tautschnig
99
#include "field_sensitivity.h"
1010

1111
#include <util/arith_tools.h>
12+
#include <util/byte_operators.h>
13+
#include <util/c_types.h>
1214
#include <util/simplify_expr.h>
13-
#include <util/std_expr.h>
1415

1516
#include "goto_symex_state.h"
1617
#include "symex_target.h"
@@ -26,7 +27,7 @@ exprt field_sensitivityt::apply(
2627
if(!run_apply || write)
2728
return std::move(ssa_expr);
2829
else
29-
return get_fields(ns, state, ssa_expr);
30+
return get_fields(ns, state, ssa_expr, true);
3031
}
3132

3233
exprt field_sensitivityt::apply(
@@ -72,7 +73,9 @@ exprt field_sensitivityt::apply(
7273
if(
7374
is_ssa_expr(member.struct_op()) &&
7475
(member.struct_op().type().id() == ID_struct ||
75-
member.struct_op().type().id() == ID_struct_tag))
76+
member.struct_op().type().id() == ID_struct_tag ||
77+
member.struct_op().type().id() == ID_union ||
78+
member.struct_op().type().id() == ID_union_tag))
7679
{
7780
// place the entire member expression, not just the struct operand, in an
7881
// SSA expression
@@ -88,6 +91,35 @@ exprt field_sensitivityt::apply(
8891
return std::move(tmp);
8992
}
9093
}
94+
else if(
95+
!write && (expr.id() == ID_byte_extract_little_endian ||
96+
expr.id() == ID_byte_extract_big_endian))
97+
{
98+
const byte_extract_exprt &be = to_byte_extract_expr(expr);
99+
if(
100+
(be.op().type().id() == ID_union ||
101+
be.op().type().id() == ID_union_tag) &&
102+
is_ssa_expr(be.op()) && be.offset().is_zero())
103+
{
104+
const union_typet &type = to_union_type(ns.follow(be.op().type()));
105+
for(const auto &comp : type.components())
106+
{
107+
if(comp.type() == be.type())
108+
{
109+
ssa_exprt tmp = to_ssa_expr(be.op());
110+
bool was_l2 = !tmp.get_level_2().empty();
111+
tmp.remove_level_2();
112+
member_exprt member{tmp.get_original_expr(), comp};
113+
tmp.type() = be.type();
114+
tmp.set_expression(member);
115+
if(was_l2)
116+
return state.rename(std::move(tmp), ns).get();
117+
else
118+
return std::move(tmp);
119+
}
120+
}
121+
}
122+
}
91123
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
92124
else if(expr.id() == ID_index)
93125
{
@@ -144,7 +176,7 @@ exprt field_sensitivityt::apply(
144176
{
145177
// Expand the array and return `{array[0]; array[1]; ...}[index]`
146178
exprt expanded_array =
147-
get_fields(ns, state, to_ssa_expr(index.array()));
179+
get_fields(ns, state, to_ssa_expr(index.array()), true);
148180
return index_exprt{std::move(expanded_array), index.index()};
149181
}
150182
}
@@ -157,33 +189,48 @@ exprt field_sensitivityt::apply(
157189
exprt field_sensitivityt::get_fields(
158190
const namespacet &ns,
159191
goto_symex_statet &state,
160-
const ssa_exprt &ssa_expr) const
192+
const ssa_exprt &ssa_expr,
193+
bool disjoined_fields_only) const
161194
{
162-
if(ssa_expr.type().id() == ID_struct || ssa_expr.type().id() == ID_struct_tag)
195+
if(
196+
ssa_expr.type().id() == ID_struct ||
197+
ssa_expr.type().id() == ID_struct_tag ||
198+
(!disjoined_fields_only && (ssa_expr.type().id() == ID_union ||
199+
ssa_expr.type().id() == ID_union_tag)))
163200
{
164-
const struct_typet &type = to_struct_type(ns.follow(ssa_expr.type()));
201+
const struct_union_typet &type =
202+
to_struct_union_type(ns.follow(ssa_expr.type()));
165203
const struct_union_typet::componentst &components = type.components();
166204

167-
struct_exprt::operandst fields;
205+
exprt::operandst fields;
168206
fields.reserve(components.size());
169207

170-
const exprt &struct_op = ssa_expr.get_original_expr();
208+
const exprt &compound_op = ssa_expr.get_original_expr();
171209

172210
for(const auto &comp : components)
173211
{
174212
ssa_exprt tmp = ssa_expr;
175213
bool was_l2 = !tmp.get_level_2().empty();
176214
tmp.remove_level_2();
177-
tmp.set_expression(member_exprt{struct_op, comp.get_name(), comp.type()});
215+
tmp.set_expression(
216+
member_exprt{compound_op, comp.get_name(), comp.type()});
217+
exprt field = get_fields(ns, state, tmp, disjoined_fields_only);
178218
if(was_l2)
179219
{
180-
fields.push_back(state.rename(get_fields(ns, state, tmp), ns).get());
220+
fields.emplace_back(state.rename(std::move(field), ns).get());
181221
}
182222
else
183-
fields.push_back(get_fields(ns, state, tmp));
223+
fields.emplace_back(std::move(field));
184224
}
185225

186-
return struct_exprt(std::move(fields), ssa_expr.type());
226+
if(
227+
disjoined_fields_only && (ssa_expr.type().id() == ID_struct ||
228+
ssa_expr.type().id() == ID_struct_tag))
229+
{
230+
return struct_exprt{std::move(fields), ssa_expr.type()};
231+
}
232+
else
233+
return field_sensitive_ssa_exprt{ssa_expr, std::move(fields)};
187234
}
188235
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
189236
else if(
@@ -210,15 +257,19 @@ exprt field_sensitivityt::get_fields(
210257
bool was_l2 = !tmp.get_level_2().empty();
211258
tmp.remove_level_2();
212259
tmp.set_expression(index);
260+
exprt element = get_fields(ns, state, tmp, disjoined_fields_only);
213261
if(was_l2)
214262
{
215-
elements.push_back(state.rename(get_fields(ns, state, tmp), ns).get());
263+
elements.emplace_back(state.rename(std::move(element), ns).get());
216264
}
217265
else
218-
elements.push_back(get_fields(ns, state, tmp));
266+
elements.emplace_back(std::move(element));
219267
}
220268

221-
return array_exprt(std::move(elements), type);
269+
if(disjoined_fields_only)
270+
return array_exprt(std::move(elements), type);
271+
else
272+
return field_sensitive_ssa_exprt{ssa_expr, std::move(elements)};
222273
}
223274
#endif // ENABLE_ARRAY_FIELD_SENSITIVITY
224275
else
@@ -233,15 +284,15 @@ void field_sensitivityt::field_assignments(
233284
symex_targett &target,
234285
bool allow_pointer_unsoundness)
235286
{
236-
const exprt lhs_fs = apply(ns, state, lhs, false);
287+
PRECONDITION(run_apply);
288+
const exprt lhs_fs = get_fields(ns, state, lhs, false);
237289

238290
if(lhs != lhs_fs)
239291
{
240-
bool run_apply_bak = run_apply;
241292
run_apply = false;
242293
field_assignments_rec(
243294
ns, state, lhs_fs, rhs, target, allow_pointer_unsoundness);
244-
run_apply = run_apply_bak;
295+
run_apply = true;
245296
}
246297
}
247298

@@ -302,6 +353,43 @@ void field_sensitivityt::field_assignments_rec(
302353
simplify_opt(member_exprt{ssa_rhs, comp.get_name(), comp.type()}, ns);
303354
const exprt &member_lhs = *fs_it;
304355

356+
field_assignments_rec(
357+
ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
358+
++fs_it;
359+
}
360+
}
361+
else if(
362+
ssa_rhs.type().id() == ID_union || ssa_rhs.type().id() == ID_union_tag)
363+
{
364+
const union_typet &type = to_union_type(ns.follow(ssa_rhs.type()));
365+
const struct_union_typet::componentst &components = type.components();
366+
367+
PRECONDITION(
368+
components.empty() ||
369+
(lhs_fs.has_operands() && lhs_fs.operands().size() == components.size()));
370+
371+
exprt::operandst::const_iterator fs_it = lhs_fs.operands().begin();
372+
for(const auto &comp : components)
373+
{
374+
const exprt member_rhs = simplify_opt(
375+
make_byte_extract(
376+
ssa_rhs, from_integer(0, c_index_type()), comp.type()),
377+
ns);
378+
const exprt &member_lhs = *fs_it;
379+
380+
if(
381+
auto fs_ssa =
382+
expr_try_dynamic_cast<field_sensitive_ssa_exprt>(member_lhs))
383+
{
384+
field_assignments_rec(
385+
ns,
386+
state,
387+
fs_ssa->get_object_ssa(),
388+
member_rhs,
389+
target,
390+
allow_pointer_unsoundness);
391+
}
392+
305393
field_assignments_rec(
306394
ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
307395
++fs_it;
@@ -350,7 +438,9 @@ void field_sensitivityt::field_assignments_rec(
350438
}
351439
}
352440

353-
bool field_sensitivityt::is_divisible(const ssa_exprt &expr) const
441+
bool field_sensitivityt::is_divisible(
442+
const ssa_exprt &expr,
443+
bool disjoined_fields_only) const
354444
{
355445
if(expr.type().id() == ID_struct || expr.type().id() == ID_struct_tag)
356446
return true;
@@ -366,6 +456,13 @@ bool field_sensitivityt::is_divisible(const ssa_exprt &expr) const
366456
}
367457
#endif
368458

459+
if(
460+
!disjoined_fields_only &&
461+
(expr.type().id() == ID_union || expr.type().id() == ID_union_tag))
462+
{
463+
return true;
464+
}
465+
369466
return false;
370467
}
371468

src/goto-symex/field_sensitivity.h

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,51 @@ Author: Michael Tautschnig
99
#ifndef CPROVER_GOTO_SYMEX_FIELD_SENSITIVITY_H
1010
#define CPROVER_GOTO_SYMEX_FIELD_SENSITIVITY_H
1111

12-
#include <cstddef>
13-
1412
#include <util/nodiscard.h>
13+
#include <util/ssa_expr.h>
1514

16-
class exprt;
17-
class ssa_exprt;
1815
class namespacet;
1916
class goto_symex_statet;
2017
class symex_targett;
2118

19+
class field_sensitive_ssa_exprt : public exprt
20+
{
21+
public:
22+
field_sensitive_ssa_exprt(const ssa_exprt &ssa, exprt::operandst &&fields)
23+
: exprt(ID_field_sensitive_ssa, ssa.type(), std::move(fields))
24+
{
25+
add(ID_expression, ssa);
26+
}
27+
28+
const ssa_exprt &get_object_ssa() const
29+
{
30+
return static_cast<const ssa_exprt &>(find(ID_expression));
31+
}
32+
};
33+
34+
template <>
35+
inline bool can_cast_expr<field_sensitive_ssa_exprt>(const exprt &base)
36+
{
37+
return base.id() == ID_field_sensitive_ssa;
38+
}
39+
40+
inline const field_sensitive_ssa_exprt &
41+
to_field_sensitive_ssa_expr(const exprt &expr)
42+
{
43+
PRECONDITION(expr.id() == ID_field_sensitive_ssa);
44+
const field_sensitive_ssa_exprt &ret =
45+
static_cast<const field_sensitive_ssa_exprt &>(expr);
46+
return ret;
47+
}
48+
49+
inline field_sensitive_ssa_exprt &to_field_sensitive_ssa_expr(exprt &expr)
50+
{
51+
PRECONDITION(expr.id() == ID_field_sensitive_ssa);
52+
field_sensitive_ssa_exprt &ret =
53+
static_cast<field_sensitive_ssa_exprt &>(expr);
54+
return ret;
55+
}
56+
2257
/// Control granularity of object accesses
2358
///
2459
/// [Field sensitivity](\ref field_sensitivityt) is a transformation of the
@@ -128,33 +163,40 @@ class field_sensitivityt
128163
apply(const namespacet &ns, goto_symex_statet &state, exprt expr, bool write)
129164
const;
130165
/// \copydoc apply(const namespacet&,goto_symex_statet&,exprt,bool) const
166+
NODISCARD
131167
exprt apply(
132168
const namespacet &ns,
133169
goto_symex_statet &state,
134170
ssa_exprt expr,
135171
bool write) const;
136172

137173
/// Compute an expression representing the individual components of a
138-
/// field-sensitive SSA representation of \p ssa_expr.
174+
/// field-sensitive SSA representation of \p ssa_expr. When
175+
/// \p disjoined_fields_only is false, the resulting expression must be
176+
/// handled with care as it will have multiple operands but empty `id()`.
139177
/// \param ns: a namespace to resolve type symbols/tag types
140178
/// \param [in,out] state: symbolic execution state
141179
/// \param ssa_expr: the expression to evaluate
180+
/// \param disjoined_fields_only: whether to expand unions (`false`) or not (`true`)
142181
/// \return Expanded expression; for example, for a \p ssa_expr of some struct
143182
/// type, a `struct_exprt` with each component now being an SSA expression
144183
/// is built.
184+
NODISCARD
145185
exprt get_fields(
146186
const namespacet &ns,
147187
goto_symex_statet &state,
148-
const ssa_exprt &ssa_expr) const;
188+
const ssa_exprt &ssa_expr,
189+
bool disjoined_fields_only) const;
149190

150191
/// Determine whether \p expr would translate to an atomic SSA expression
151192
/// (returns false) or a composite object made of several SSA expressions as
152193
/// components (such as a struct with each member becoming an individual SSA
153194
/// expression, return true in this case).
154195
/// \param expr: the expression to evaluate
196+
/// \param disjoined_fields_only: whether to expand unions (`false`) or not (`true`)
155197
/// \return False, if and only if, \p expr would be a single field-sensitive
156198
/// SSA expression.
157-
bool is_divisible(const ssa_exprt &expr) const;
199+
bool is_divisible(const ssa_exprt &expr, bool disjoined_fields_only) const;
158200

159201
private:
160202
/// whether or not to invoke \ref field_sensitivityt::apply

0 commit comments

Comments
 (0)