@@ -11,12 +11,14 @@ Author: Daniel Kroening, kroening@kroening.com
11
11
12
12
#include " symex_assign.h"
13
13
14
- #include " expr_skeleton.h"
15
- #include " goto_symex_state.h"
14
+ #include < util/arith_tools.h>
16
15
#include < util/byte_operators.h>
17
16
#include < util/expr_util.h>
17
+ #include < util/pointer_offset_size.h>
18
18
#include < util/range.h>
19
19
20
+ #include " expr_skeleton.h"
21
+ #include " goto_symex_state.h"
20
22
#include " symex_config.h"
21
23
22
24
// We can either use with_exprt or update_exprt when building expressions that
@@ -253,11 +255,100 @@ void symex_assignt::assign_array(
253
255
{
254
256
const exprt &lhs_array=lhs.array ();
255
257
const exprt &lhs_index=lhs.index ();
256
- const typet &lhs_index_type = lhs_array.type ();
258
+ const array_typet &lhs_array_type = to_array_type (lhs_array.type ());
259
+
260
+ const bool may_be_out_of_bounds =
261
+ symex_config.updates_across_member_bounds &&
262
+ [&lhs_index, &lhs_array_type]() {
263
+ if (
264
+ lhs_index.id () != ID_constant ||
265
+ lhs_array_type.size ().id () != ID_constant)
266
+ {
267
+ return true ;
268
+ }
269
+
270
+ const auto lhs_index_int =
271
+ numeric_cast_v<mp_integer>(to_constant_expr (lhs_index));
272
+
273
+ return lhs_index_int < 0 ||
274
+ lhs_index_int >= numeric_cast_v<mp_integer>(
275
+ to_constant_expr (lhs_array_type.size ()));
276
+ }();
277
+
278
+ if (
279
+ may_be_out_of_bounds &&
280
+ (lhs_array.id () == ID_member || lhs_array.id () == ID_index))
281
+ {
282
+ const auto subtype_bytes_opt = size_of_expr (lhs_array.type ().subtype (), ns);
283
+ CHECK_RETURN (subtype_bytes_opt.has_value ());
257
284
258
- PRECONDITION (lhs_index_type.id () == ID_array);
285
+ exprt new_offset = mult_exprt{
286
+ lhs_index,
287
+ typecast_exprt::conditional_cast (*subtype_bytes_opt, lhs_index.type ())};
259
288
260
- if (use_update)
289
+ exprt parent;
290
+ if (lhs_array.id () == ID_member)
291
+ {
292
+ const member_exprt &member = to_member_expr (lhs_array);
293
+ const auto member_offset = member_offset_expr (member, ns);
294
+ CHECK_RETURN (member_offset.has_value ());
295
+
296
+ parent = member.compound ();
297
+ new_offset = plus_exprt{
298
+ typecast_exprt::conditional_cast (*member_offset, new_offset.type ()),
299
+ new_offset};
300
+ }
301
+ else
302
+ {
303
+ const index_exprt &index = to_index_expr (lhs_array);
304
+
305
+ const auto element_size_opt =
306
+ size_of_expr (to_array_type (index.array ().type ()).subtype (), ns);
307
+ CHECK_RETURN (element_size_opt.has_value ());
308
+
309
+ parent = index.array ();
310
+ new_offset =
311
+ plus_exprt{mult_exprt{typecast_exprt::conditional_cast (
312
+ *element_size_opt, new_offset.type ()),
313
+ typecast_exprt::conditional_cast (
314
+ index.index (), new_offset.type ())},
315
+ new_offset};
316
+ }
317
+
318
+ if (symex_config.simplify_opt )
319
+ simplify (new_offset, ns);
320
+
321
+ const byte_update_exprt new_rhs = make_byte_update (parent, new_offset, rhs);
322
+ const expr_skeletont new_skeleton =
323
+ full_lhs.compose (expr_skeletont::remove_op0 (lhs_array));
324
+ assign_rec (parent, new_skeleton, new_rhs, guard);
325
+ }
326
+ else if (
327
+ may_be_out_of_bounds && (lhs_array.id () == ID_byte_extract_big_endian ||
328
+ lhs_array.id () == ID_byte_extract_little_endian))
329
+ {
330
+ const byte_extract_exprt &byte_extract = to_byte_extract_expr (lhs_array);
331
+
332
+ const auto subtype_bytes_opt = size_of_expr (lhs_array.type ().subtype (), ns);
333
+ CHECK_RETURN (subtype_bytes_opt.has_value ());
334
+
335
+ exprt new_offset =
336
+ plus_exprt{mult_exprt{lhs_index,
337
+ typecast_exprt::conditional_cast (
338
+ *subtype_bytes_opt, lhs_index.type ())},
339
+ typecast_exprt::conditional_cast (
340
+ byte_extract.offset (), lhs_index.type ())};
341
+
342
+ if (symex_config.simplify_opt )
343
+ simplify (new_offset, ns);
344
+
345
+ byte_extract_exprt new_lhs = byte_extract;
346
+ new_lhs.offset () = new_offset;
347
+ new_lhs.type () = rhs.type ();
348
+
349
+ assign_rec (new_lhs, full_lhs, rhs, guard);
350
+ }
351
+ else if (use_update)
261
352
{
262
353
// turn
263
354
// a[i]=e
@@ -378,8 +469,70 @@ void symex_assignt::assign_byte_extract(
378
469
else
379
470
UNREACHABLE;
380
471
381
- const byte_update_exprt new_rhs{byte_update_id, lhs.op (), lhs.offset (), rhs};
382
- const expr_skeletont new_skeleton =
383
- full_lhs.compose (expr_skeletont::remove_op0 (lhs));
384
- assign_rec (lhs.op (), new_skeleton, new_rhs, guard);
472
+ const bool may_be_out_of_bounds =
473
+ symex_config.updates_across_member_bounds && [&lhs, this ]() {
474
+ if (lhs.offset ().id () != ID_constant)
475
+ return true ;
476
+ const auto extract_size_opt = pointer_offset_size (lhs.type (), ns);
477
+ if (!extract_size_opt.has_value ())
478
+ return true ;
479
+ const auto object_size_opt = pointer_offset_size (lhs.op ().type (), ns);
480
+ if (!object_size_opt.has_value ())
481
+ return true ;
482
+ const auto lhs_offset_int =
483
+ numeric_cast_v<mp_integer>(to_constant_expr (lhs.offset ()));
484
+ return lhs_offset_int < 0 ||
485
+ lhs_offset_int + *extract_size_opt > *object_size_opt;
486
+ }();
487
+
488
+ if (
489
+ may_be_out_of_bounds &&
490
+ (lhs.op ().id () == ID_member || lhs.op ().id () == ID_index))
491
+ {
492
+ exprt new_offset = lhs.offset ();
493
+ exprt parent;
494
+ if (lhs.op ().id () == ID_member)
495
+ {
496
+ const member_exprt &member = to_member_expr (lhs.op ());
497
+ const auto member_offset = member_offset_expr (member, ns);
498
+ CHECK_RETURN (member_offset.has_value ());
499
+
500
+ parent = member.compound ();
501
+ new_offset = plus_exprt{
502
+ typecast_exprt::conditional_cast (*member_offset, new_offset.type ()),
503
+ new_offset};
504
+ }
505
+ else
506
+ {
507
+ const index_exprt &index = to_index_expr (lhs.op ());
508
+
509
+ const auto element_size_opt =
510
+ size_of_expr (to_array_type (index.array ().type ()).subtype (), ns);
511
+ CHECK_RETURN (element_size_opt.has_value ());
512
+
513
+ parent = index.array ();
514
+ new_offset =
515
+ plus_exprt{mult_exprt{typecast_exprt::conditional_cast (
516
+ *element_size_opt, new_offset.type ()),
517
+ typecast_exprt::conditional_cast (
518
+ index.index (), new_offset.type ())},
519
+ new_offset};
520
+ }
521
+
522
+ if (symex_config.simplify_opt )
523
+ simplify (new_offset, ns);
524
+
525
+ const byte_update_exprt new_rhs{byte_update_id, parent, new_offset, rhs};
526
+ const expr_skeletont new_skeleton =
527
+ full_lhs.compose (expr_skeletont::remove_op0 (lhs.op ()));
528
+ assign_rec (parent, new_skeleton, new_rhs, guard);
529
+ }
530
+ else
531
+ {
532
+ const byte_update_exprt new_rhs{
533
+ byte_update_id, lhs.op (), lhs.offset (), rhs};
534
+ const expr_skeletont new_skeleton =
535
+ full_lhs.compose (expr_skeletont::remove_op0 (lhs));
536
+ assign_rec (lhs.op (), new_skeleton, new_rhs, guard);
537
+ }
385
538
}
0 commit comments