|
16 | 16 | #include <util/byte_operators.h>
|
17 | 17 | #include <util/c_types.h>
|
18 | 18 | #include <util/exception_utils.h>
|
| 19 | +#include <util/expr_util.h> |
19 | 20 | #include <util/invariant.h>
|
20 | 21 | #include <util/pointer_offset_size.h>
|
21 | 22 |
|
@@ -363,4 +364,30 @@ void goto_symext::dereference(exprt &expr, statet &state)
|
363 | 364 | // dereferencing may introduce new symbol_exprt
|
364 | 365 | // (like __CPROVER_memory)
|
365 | 366 | expr = state.rename<goto_symex_statet::L1>(std::move(l1_expr), ns);
|
| 367 | + |
| 368 | + // Dereferencing is likely to introduce new member-of-if constructs -- |
| 369 | + // for example, "x->field" may have become "(x == &o1 ? o1 : o2).field." |
| 370 | + // Run expression simplification, which converts that to |
| 371 | + // (x == &o1 ? o1.field : o2.field)) |
| 372 | + // before applying field sensitivity. Field sensitivity can then turn such |
| 373 | + // field-of-symbol expressions into atomic SSA expressions instead of having |
| 374 | + // to rewrite all of 'o1' otherwise. |
| 375 | + // Even without field sensitivity this can be beneficial: for example, |
| 376 | + // "(b ? s1 : s2).member := X" results in |
| 377 | + // (b ? s1 : s2) := (b ? s1 : s2) with (member := X) |
| 378 | + // and then |
| 379 | + // s1 := b ? ((b ? s1 : s2) with (member := X)) : s1 |
| 380 | + // when all we need is |
| 381 | + // s1 := s1 with (member := X) [and guard b] |
| 382 | + // s2 := s2 with (member := X) [and guard !b] |
| 383 | + do_simplify(expr); |
| 384 | + |
| 385 | + if(symex_config.run_validation_checks) |
| 386 | + { |
| 387 | + // make sure simplify has not re-introduced any dereferencing that |
| 388 | + // had previously been cleaned away |
| 389 | + INVARIANT( |
| 390 | + !has_subexpr(expr, ID_dereference), |
| 391 | + "simplify re-introduced dereferencing"); |
| 392 | + } |
366 | 393 | }
|
0 commit comments