@@ -9,8 +9,10 @@ Author: Michael Tautschnig
9
9
#include " field_sensitivity.h"
10
10
11
11
#include < util/arith_tools.h>
12
+ #include < util/byte_operators.h>
13
+ #include < util/c_types.h>
14
+ #include < util/pointer_offset_size.h>
12
15
#include < util/simplify_expr.h>
13
- #include < util/std_expr.h>
14
16
15
17
#include " goto_symex_state.h"
16
18
#include " symex_target.h"
@@ -26,7 +28,7 @@ exprt field_sensitivityt::apply(
26
28
if (write )
27
29
return std::move (ssa_expr);
28
30
else
29
- return get_fields (ns, state, ssa_expr);
31
+ return get_fields (ns, state, ssa_expr, true );
30
32
}
31
33
32
34
exprt field_sensitivityt::apply (
@@ -43,7 +45,7 @@ exprt field_sensitivityt::apply(
43
45
44
46
if (!write && is_ssa_expr (expr))
45
47
{
46
- return get_fields (ns, state, to_ssa_expr (expr));
48
+ return get_fields (ns, state, to_ssa_expr (expr), true );
47
49
}
48
50
else if (
49
51
!write && expr.id () == ID_member &&
@@ -69,7 +71,9 @@ exprt field_sensitivityt::apply(
69
71
if (
70
72
is_ssa_expr (member.struct_op ()) &&
71
73
(member.struct_op ().type ().id () == ID_struct ||
72
- member.struct_op ().type ().id () == ID_struct_tag))
74
+ member.struct_op ().type ().id () == ID_struct_tag ||
75
+ member.struct_op ().type ().id () == ID_union ||
76
+ member.struct_op ().type ().id () == ID_union_tag))
73
77
{
74
78
// place the entire member expression, not just the struct operand, in an
75
79
// SSA expression
@@ -85,6 +89,40 @@ exprt field_sensitivityt::apply(
85
89
return std::move (tmp);
86
90
}
87
91
}
92
+ else if (
93
+ !write && (expr.id () == ID_byte_extract_little_endian ||
94
+ expr.id () == ID_byte_extract_big_endian))
95
+ {
96
+ const byte_extract_exprt &be = to_byte_extract_expr (expr);
97
+ if (
98
+ (be.op ().type ().id () == ID_union ||
99
+ be.op ().type ().id () == ID_union_tag) &&
100
+ is_ssa_expr (be.op ()) && be.offset ().is_constant ())
101
+ {
102
+ const union_typet &type = to_union_type (ns.follow (be.op ().type ()));
103
+ for (const auto &comp : type.components ())
104
+ {
105
+ ssa_exprt tmp = to_ssa_expr (be.op ());
106
+ bool was_l2 = !tmp.get_level_2 ().empty ();
107
+ tmp.remove_level_2 ();
108
+ const member_exprt member{tmp.get_original_expr (), comp};
109
+ auto recursive_member =
110
+ get_subexpression_at_offset (member, be.offset (), be.type (), ns);
111
+ if (
112
+ recursive_member.has_value () &&
113
+ (recursive_member->id () == ID_member ||
114
+ recursive_member->id () == ID_index))
115
+ {
116
+ tmp.type () = be.type ();
117
+ tmp.set_expression (*recursive_member);
118
+ if (was_l2)
119
+ return state.rename (std::move (tmp), ns).get ();
120
+ else
121
+ return std::move (tmp);
122
+ }
123
+ }
124
+ }
125
+ }
88
126
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
89
127
else if (expr.id () == ID_index)
90
128
{
@@ -141,7 +179,7 @@ exprt field_sensitivityt::apply(
141
179
{
142
180
// Expand the array and return `{array[0]; array[1]; ...}[index]`
143
181
exprt expanded_array =
144
- get_fields (ns, state, to_ssa_expr (index .array ()));
182
+ get_fields (ns, state, to_ssa_expr (index .array ()), true );
145
183
return index_exprt{std::move (expanded_array), index .index ()};
146
184
}
147
185
}
@@ -154,33 +192,48 @@ exprt field_sensitivityt::apply(
154
192
exprt field_sensitivityt::get_fields (
155
193
const namespacet &ns,
156
194
goto_symex_statet &state,
157
- const ssa_exprt &ssa_expr) const
195
+ const ssa_exprt &ssa_expr,
196
+ bool disjoined_fields_only) const
158
197
{
159
- if (ssa_expr.type ().id () == ID_struct || ssa_expr.type ().id () == ID_struct_tag)
198
+ if (
199
+ ssa_expr.type ().id () == ID_struct ||
200
+ ssa_expr.type ().id () == ID_struct_tag ||
201
+ (!disjoined_fields_only && (ssa_expr.type ().id () == ID_union ||
202
+ ssa_expr.type ().id () == ID_union_tag)))
160
203
{
161
- const struct_typet &type = to_struct_type (ns.follow (ssa_expr.type ()));
204
+ const struct_union_typet &type =
205
+ to_struct_union_type (ns.follow (ssa_expr.type ()));
162
206
const struct_union_typet::componentst &components = type.components ();
163
207
164
- struct_exprt ::operandst fields;
208
+ exprt ::operandst fields;
165
209
fields.reserve (components.size ());
166
210
167
- const exprt &struct_op = ssa_expr.get_original_expr ();
211
+ const exprt &compound_op = ssa_expr.get_original_expr ();
168
212
169
213
for (const auto &comp : components)
170
214
{
171
215
ssa_exprt tmp = ssa_expr;
172
216
bool was_l2 = !tmp.get_level_2 ().empty ();
173
217
tmp.remove_level_2 ();
174
- tmp.set_expression (member_exprt{struct_op, comp.get_name (), comp.type ()});
218
+ tmp.set_expression (
219
+ member_exprt{compound_op, comp.get_name (), comp.type ()});
220
+ exprt field = get_fields (ns, state, tmp, disjoined_fields_only);
175
221
if (was_l2)
176
222
{
177
- fields.push_back (state.rename (get_fields (ns, state, tmp ), ns).get ());
223
+ fields.emplace_back (state.rename (std::move (field ), ns).get ());
178
224
}
179
225
else
180
- fields.push_back ( get_fields (ns, state, tmp ));
226
+ fields.emplace_back ( std::move (field ));
181
227
}
182
228
183
- return struct_exprt (std::move (fields), ssa_expr.type ());
229
+ if (
230
+ disjoined_fields_only && (ssa_expr.type ().id () == ID_struct ||
231
+ ssa_expr.type ().id () == ID_struct_tag))
232
+ {
233
+ return struct_exprt{std::move (fields), ssa_expr.type ()};
234
+ }
235
+ else
236
+ return field_sensitive_ssa_exprt{ssa_expr, std::move (fields)};
184
237
}
185
238
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
186
239
else if (
@@ -207,15 +260,19 @@ exprt field_sensitivityt::get_fields(
207
260
bool was_l2 = !tmp.get_level_2 ().empty ();
208
261
tmp.remove_level_2 ();
209
262
tmp.set_expression (index );
263
+ exprt element = get_fields (ns, state, tmp, disjoined_fields_only);
210
264
if (was_l2)
211
265
{
212
- elements.push_back (state.rename (get_fields (ns, state, tmp ), ns).get ());
266
+ elements.emplace_back (state.rename (std::move (element ), ns).get ());
213
267
}
214
268
else
215
- elements.push_back ( get_fields (ns, state, tmp ));
269
+ elements.emplace_back ( std::move (element ));
216
270
}
217
271
218
- return array_exprt (std::move (elements), type);
272
+ if (disjoined_fields_only)
273
+ return array_exprt (std::move (elements), type);
274
+ else
275
+ return field_sensitive_ssa_exprt{ssa_expr, std::move (elements)};
219
276
}
220
277
#endif // ENABLE_ARRAY_FIELD_SENSITIVITY
221
278
else
@@ -230,7 +287,7 @@ void field_sensitivityt::field_assignments(
230
287
symex_targett &target,
231
288
bool allow_pointer_unsoundness) const
232
289
{
233
- const exprt lhs_fs = get_fields (ns, state, lhs);
290
+ const exprt lhs_fs = get_fields (ns, state, lhs, false );
234
291
235
292
if (lhs != lhs_fs)
236
293
{
@@ -292,10 +349,67 @@ void field_sensitivityt::field_assignments_rec(
292
349
exprt::operandst::const_iterator fs_it = lhs_fs.operands ().begin ();
293
350
for (const auto &comp : components)
294
351
{
295
- const exprt member_rhs =
296
- simplify_opt (member_exprt{ssa_rhs, comp.get_name (), comp.type ()}, ns);
352
+ const exprt member_rhs = apply (
353
+ ns,
354
+ state,
355
+ simplify_opt (member_exprt{ssa_rhs, comp.get_name (), comp.type ()}, ns),
356
+ false );
357
+ const exprt &member_lhs = *fs_it;
358
+
359
+ if (
360
+ auto fs_ssa =
361
+ expr_try_dynamic_cast<field_sensitive_ssa_exprt>(member_lhs))
362
+ {
363
+ field_assignments_rec (
364
+ ns,
365
+ state,
366
+ fs_ssa->get_object_ssa (),
367
+ member_rhs,
368
+ target,
369
+ allow_pointer_unsoundness);
370
+ }
371
+
372
+ field_assignments_rec (
373
+ ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
374
+ ++fs_it;
375
+ }
376
+ }
377
+ else if (
378
+ ssa_rhs.type ().id () == ID_union || ssa_rhs.type ().id () == ID_union_tag)
379
+ {
380
+ const union_typet &type = to_union_type (ns.follow (ssa_rhs.type ()));
381
+ const struct_union_typet::componentst &components = type.components ();
382
+
383
+ PRECONDITION (
384
+ components.empty () ||
385
+ (lhs_fs.has_operands () && lhs_fs.operands ().size () == components.size ()));
386
+
387
+ exprt::operandst::const_iterator fs_it = lhs_fs.operands ().begin ();
388
+ for (const auto &comp : components)
389
+ {
390
+ const exprt member_rhs = apply (
391
+ ns,
392
+ state,
393
+ simplify_opt (
394
+ make_byte_extract (
395
+ ssa_rhs, from_integer (0 , c_index_type ()), comp.type ()),
396
+ ns),
397
+ false );
297
398
const exprt &member_lhs = *fs_it;
298
399
400
+ if (
401
+ auto fs_ssa =
402
+ expr_try_dynamic_cast<field_sensitive_ssa_exprt>(member_lhs))
403
+ {
404
+ field_assignments_rec (
405
+ ns,
406
+ state,
407
+ fs_ssa->get_object_ssa (),
408
+ member_rhs,
409
+ target,
410
+ allow_pointer_unsoundness);
411
+ }
412
+
299
413
field_assignments_rec (
300
414
ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
301
415
++fs_it;
@@ -314,10 +428,27 @@ void field_sensitivityt::field_assignments_rec(
314
428
exprt::operandst::const_iterator fs_it = lhs_fs.operands ().begin ();
315
429
for (std::size_t i = 0 ; i < array_size; ++i)
316
430
{
317
- const exprt index_rhs = simplify_opt (
318
- index_exprt{ssa_rhs, from_integer (i, type->index_type ())}, ns);
431
+ const exprt index_rhs = apply (
432
+ ns,
433
+ state,
434
+ simplify_opt (
435
+ index_exprt{ssa_rhs, from_integer (i, type->index_type ())}, ns),
436
+ false );
319
437
const exprt &index_lhs = *fs_it;
320
438
439
+ if (
440
+ auto fs_ssa =
441
+ expr_try_dynamic_cast<field_sensitive_ssa_exprt>(index_lhs))
442
+ {
443
+ field_assignments_rec (
444
+ ns,
445
+ state,
446
+ fs_ssa->get_object_ssa (),
447
+ index_rhs,
448
+ target,
449
+ allow_pointer_unsoundness);
450
+ }
451
+
321
452
field_assignments_rec (
322
453
ns, state, index_lhs, index_rhs, target, allow_pointer_unsoundness);
323
454
++fs_it;
@@ -333,6 +464,17 @@ void field_sensitivityt::field_assignments_rec(
333
464
exprt::operandst::const_iterator fs_it = lhs_fs.operands ().begin ();
334
465
for (const exprt &op : ssa_rhs.operands ())
335
466
{
467
+ if (auto fs_ssa = expr_try_dynamic_cast<field_sensitive_ssa_exprt>(*fs_it))
468
+ {
469
+ field_assignments_rec (
470
+ ns,
471
+ state,
472
+ fs_ssa->get_object_ssa (),
473
+ op,
474
+ target,
475
+ allow_pointer_unsoundness);
476
+ }
477
+
336
478
field_assignments_rec (
337
479
ns, state, *fs_it, op, target, allow_pointer_unsoundness);
338
480
++fs_it;
@@ -344,7 +486,9 @@ void field_sensitivityt::field_assignments_rec(
344
486
}
345
487
}
346
488
347
- bool field_sensitivityt::is_divisible (const ssa_exprt &expr) const
489
+ bool field_sensitivityt::is_divisible (
490
+ const ssa_exprt &expr,
491
+ bool disjoined_fields_only) const
348
492
{
349
493
if (expr.type ().id () == ID_struct || expr.type ().id () == ID_struct_tag)
350
494
return true ;
@@ -360,6 +504,13 @@ bool field_sensitivityt::is_divisible(const ssa_exprt &expr) const
360
504
}
361
505
#endif
362
506
507
+ if (
508
+ !disjoined_fields_only &&
509
+ (expr.type ().id () == ID_union || expr.type ().id () == ID_union_tag))
510
+ {
511
+ return true ;
512
+ }
513
+
363
514
return false ;
364
515
}
365
516
0 commit comments