|
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