@@ -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 (!run_apply || 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 (
@@ -72,7 +74,9 @@ exprt field_sensitivityt::apply(
72
74
if (
73
75
is_ssa_expr (member.struct_op ()) &&
74
76
(member.struct_op ().type ().id () == ID_struct ||
75
- member.struct_op ().type ().id () == ID_struct_tag))
77
+ member.struct_op ().type ().id () == ID_struct_tag ||
78
+ member.struct_op ().type ().id () == ID_union ||
79
+ member.struct_op ().type ().id () == ID_union_tag))
76
80
{
77
81
// place the entire member expression, not just the struct operand, in an
78
82
// SSA expression
@@ -88,6 +92,58 @@ exprt field_sensitivityt::apply(
88
92
return std::move (tmp);
89
93
}
90
94
}
95
+ else if (
96
+ !write && (expr.id () == ID_byte_extract_little_endian ||
97
+ expr.id () == ID_byte_extract_big_endian))
98
+ {
99
+ const byte_extract_exprt &be = to_byte_extract_expr (expr);
100
+ if (
101
+ (be.op ().type ().id () == ID_union ||
102
+ be.op ().type ().id () == ID_union_tag) &&
103
+ is_ssa_expr (be.op ()) && be.offset ().is_constant ())
104
+ {
105
+ const union_typet &type = to_union_type (ns.follow (be.op ().type ()));
106
+ for (const auto &comp : type.components ())
107
+ {
108
+ if (be.offset ().is_zero () && comp.type () == be.type ())
109
+ {
110
+ ssa_exprt tmp = to_ssa_expr (be.op ());
111
+ bool was_l2 = !tmp.get_level_2 ().empty ();
112
+ tmp.remove_level_2 ();
113
+ member_exprt member{tmp.get_original_expr (), comp};
114
+ tmp.type () = be.type ();
115
+ tmp.set_expression (member);
116
+ if (was_l2)
117
+ return state.rename (std::move (tmp), ns).get ();
118
+ else
119
+ return std::move (tmp);
120
+ }
121
+ else if (
122
+ comp.type ().id () == ID_struct || comp.type ().id () == ID_struct_tag ||
123
+ comp.type ().id () == ID_array)
124
+ {
125
+ ssa_exprt tmp = to_ssa_expr (be.op ());
126
+ bool was_l2 = !tmp.get_level_2 ().empty ();
127
+ tmp.remove_level_2 ();
128
+ const member_exprt member{tmp.get_original_expr (), comp};
129
+ auto recursive_member =
130
+ get_subexpression_at_offset (member, be.offset (), be.type (), ns);
131
+ if (
132
+ recursive_member.has_value () &&
133
+ (recursive_member->id () == ID_member ||
134
+ recursive_member->id () == ID_index))
135
+ {
136
+ tmp.type () = be.type ();
137
+ tmp.set_expression (*recursive_member);
138
+ if (was_l2)
139
+ return state.rename (std::move (tmp), ns).get ();
140
+ else
141
+ return std::move (tmp);
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
91
147
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
92
148
else if (expr.id () == ID_index)
93
149
{
@@ -144,7 +200,7 @@ exprt field_sensitivityt::apply(
144
200
{
145
201
// Expand the array and return `{array[0]; array[1]; ...}[index]`
146
202
exprt expanded_array =
147
- get_fields (ns, state, to_ssa_expr (index .array ()));
203
+ get_fields (ns, state, to_ssa_expr (index .array ()), true );
148
204
return index_exprt{std::move (expanded_array), index .index ()};
149
205
}
150
206
}
@@ -157,33 +213,48 @@ exprt field_sensitivityt::apply(
157
213
exprt field_sensitivityt::get_fields (
158
214
const namespacet &ns,
159
215
goto_symex_statet &state,
160
- const ssa_exprt &ssa_expr) const
216
+ const ssa_exprt &ssa_expr,
217
+ bool disjoined_fields_only) const
161
218
{
162
- if (ssa_expr.type ().id () == ID_struct || ssa_expr.type ().id () == ID_struct_tag)
219
+ if (
220
+ ssa_expr.type ().id () == ID_struct ||
221
+ ssa_expr.type ().id () == ID_struct_tag ||
222
+ (!disjoined_fields_only && (ssa_expr.type ().id () == ID_union ||
223
+ ssa_expr.type ().id () == ID_union_tag)))
163
224
{
164
- const struct_typet &type = to_struct_type (ns.follow (ssa_expr.type ()));
225
+ const struct_union_typet &type =
226
+ to_struct_union_type (ns.follow (ssa_expr.type ()));
165
227
const struct_union_typet::componentst &components = type.components ();
166
228
167
- struct_exprt ::operandst fields;
229
+ exprt ::operandst fields;
168
230
fields.reserve (components.size ());
169
231
170
- const exprt &struct_op = ssa_expr.get_original_expr ();
232
+ const exprt &compound_op = ssa_expr.get_original_expr ();
171
233
172
234
for (const auto &comp : components)
173
235
{
174
236
ssa_exprt tmp = ssa_expr;
175
237
bool was_l2 = !tmp.get_level_2 ().empty ();
176
238
tmp.remove_level_2 ();
177
- tmp.set_expression (member_exprt{struct_op, comp.get_name (), comp.type ()});
239
+ tmp.set_expression (
240
+ member_exprt{compound_op, comp.get_name (), comp.type ()});
241
+ exprt field = get_fields (ns, state, tmp, disjoined_fields_only);
178
242
if (was_l2)
179
243
{
180
- fields.push_back (state.rename (get_fields (ns, state, tmp ), ns).get ());
244
+ fields.emplace_back (state.rename (std::move (field ), ns).get ());
181
245
}
182
246
else
183
- fields.push_back ( get_fields (ns, state, tmp ));
247
+ fields.emplace_back ( std::move (field ));
184
248
}
185
249
186
- return struct_exprt (std::move (fields), ssa_expr.type ());
250
+ if (
251
+ disjoined_fields_only && (ssa_expr.type ().id () == ID_struct ||
252
+ ssa_expr.type ().id () == ID_struct_tag))
253
+ {
254
+ return struct_exprt{std::move (fields), ssa_expr.type ()};
255
+ }
256
+ else
257
+ return field_sensitive_ssa_exprt{ssa_expr, std::move (fields)};
187
258
}
188
259
#ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
189
260
else if (
@@ -210,15 +281,19 @@ exprt field_sensitivityt::get_fields(
210
281
bool was_l2 = !tmp.get_level_2 ().empty ();
211
282
tmp.remove_level_2 ();
212
283
tmp.set_expression (index );
284
+ exprt element = get_fields (ns, state, tmp, disjoined_fields_only);
213
285
if (was_l2)
214
286
{
215
- elements.push_back (state.rename (get_fields (ns, state, tmp ), ns).get ());
287
+ elements.emplace_back (state.rename (std::move (element ), ns).get ());
216
288
}
217
289
else
218
- elements.push_back ( get_fields (ns, state, tmp ));
290
+ elements.emplace_back ( std::move (element ));
219
291
}
220
292
221
- return array_exprt (std::move (elements), type);
293
+ if (disjoined_fields_only)
294
+ return array_exprt (std::move (elements), type);
295
+ else
296
+ return field_sensitive_ssa_exprt{ssa_expr, std::move (elements)};
222
297
}
223
298
#endif // ENABLE_ARRAY_FIELD_SENSITIVITY
224
299
else
@@ -233,15 +308,15 @@ void field_sensitivityt::field_assignments(
233
308
symex_targett &target,
234
309
bool allow_pointer_unsoundness)
235
310
{
236
- const exprt lhs_fs = apply (ns, state, lhs, false );
311
+ PRECONDITION (run_apply);
312
+ const exprt lhs_fs = get_fields (ns, state, lhs, false );
237
313
238
314
if (lhs != lhs_fs)
239
315
{
240
- bool run_apply_bak = run_apply;
241
- run_apply = false ;
316
+ // run_apply = false; // not even clear we need this anymore
242
317
field_assignments_rec (
243
318
ns, state, lhs_fs, rhs, target, allow_pointer_unsoundness);
244
- run_apply = run_apply_bak ;
319
+ // run_apply = true ;
245
320
}
246
321
}
247
322
@@ -302,6 +377,60 @@ void field_sensitivityt::field_assignments_rec(
302
377
simplify_opt (member_exprt{ssa_rhs, comp.get_name (), comp.type ()}, ns);
303
378
const exprt &member_lhs = *fs_it;
304
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
+
393
+ field_assignments_rec (
394
+ ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
395
+ ++fs_it;
396
+ }
397
+ }
398
+ else if (
399
+ ssa_rhs.type ().id () == ID_union || ssa_rhs.type ().id () == ID_union_tag)
400
+ {
401
+ const union_typet &type = to_union_type (ns.follow (ssa_rhs.type ()));
402
+ const struct_union_typet::componentst &components = type.components ();
403
+
404
+ PRECONDITION (
405
+ components.empty () ||
406
+ (lhs_fs.has_operands () && lhs_fs.operands ().size () == components.size ()));
407
+
408
+ exprt::operandst::const_iterator fs_it = lhs_fs.operands ().begin ();
409
+ for (const auto &comp : components)
410
+ {
411
+ const exprt member_rhs = apply (
412
+ ns,
413
+ state,
414
+ simplify_opt (
415
+ make_byte_extract (
416
+ ssa_rhs, from_integer (0 , c_index_type ()), comp.type ()),
417
+ ns),
418
+ false );
419
+ const exprt &member_lhs = *fs_it;
420
+
421
+ if (
422
+ auto fs_ssa =
423
+ expr_try_dynamic_cast<field_sensitive_ssa_exprt>(member_lhs))
424
+ {
425
+ field_assignments_rec (
426
+ ns,
427
+ state,
428
+ fs_ssa->get_object_ssa (),
429
+ member_rhs,
430
+ target,
431
+ allow_pointer_unsoundness);
432
+ }
433
+
305
434
field_assignments_rec (
306
435
ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
307
436
++fs_it;
@@ -324,6 +453,19 @@ void field_sensitivityt::field_assignments_rec(
324
453
index_exprt{ssa_rhs, from_integer (i, type->index_type ())}, ns);
325
454
const exprt &index_lhs = *fs_it;
326
455
456
+ if (
457
+ auto fs_ssa =
458
+ expr_try_dynamic_cast<field_sensitive_ssa_exprt>(index_lhs))
459
+ {
460
+ field_assignments_rec (
461
+ ns,
462
+ state,
463
+ fs_ssa->get_object_ssa (),
464
+ index_rhs,
465
+ target,
466
+ allow_pointer_unsoundness);
467
+ }
468
+
327
469
field_assignments_rec (
328
470
ns, state, index_lhs, index_rhs, target, allow_pointer_unsoundness);
329
471
++fs_it;
@@ -339,6 +481,17 @@ void field_sensitivityt::field_assignments_rec(
339
481
exprt::operandst::const_iterator fs_it = lhs_fs.operands ().begin ();
340
482
for (const exprt &op : ssa_rhs.operands ())
341
483
{
484
+ if (auto fs_ssa = expr_try_dynamic_cast<field_sensitive_ssa_exprt>(*fs_it))
485
+ {
486
+ field_assignments_rec (
487
+ ns,
488
+ state,
489
+ fs_ssa->get_object_ssa (),
490
+ op,
491
+ target,
492
+ allow_pointer_unsoundness);
493
+ }
494
+
342
495
field_assignments_rec (
343
496
ns, state, *fs_it, op, target, allow_pointer_unsoundness);
344
497
++fs_it;
@@ -350,7 +503,9 @@ void field_sensitivityt::field_assignments_rec(
350
503
}
351
504
}
352
505
353
- bool field_sensitivityt::is_divisible (const ssa_exprt &expr) const
506
+ bool field_sensitivityt::is_divisible (
507
+ const ssa_exprt &expr,
508
+ bool disjoined_fields_only) const
354
509
{
355
510
if (expr.type ().id () == ID_struct || expr.type ().id () == ID_struct_tag)
356
511
return true ;
@@ -366,6 +521,13 @@ bool field_sensitivityt::is_divisible(const ssa_exprt &expr) const
366
521
}
367
522
#endif
368
523
524
+ if (
525
+ !disjoined_fields_only &&
526
+ (expr.type ().id () == ID_union || expr.type ().id () == ID_union_tag))
527
+ {
528
+ return true ;
529
+ }
530
+
369
531
return false ;
370
532
}
371
533
0 commit comments