|
| 1 | +/*******************************************************************\ |
| 2 | +
|
| 3 | +Module: Dynamic frame condition checking |
| 4 | +
|
| 5 | +Author: Remi Delmas, [email protected] |
| 6 | +
|
| 7 | +\*******************************************************************/ |
| 8 | +#include "dfcc_infer_loop_assigns.h" |
| 9 | + |
| 10 | +#include <util/expr.h> |
| 11 | +#include <util/find_symbols.h> |
| 12 | +#include <util/message.h> |
| 13 | +#include <util/pointer_expr.h> |
| 14 | +#include <util/std_code.h> |
| 15 | + |
| 16 | +#include <goto-instrument/havoc_utils.h> |
| 17 | + |
| 18 | +/// Widens expressions in the given \p assigns set as follows: |
| 19 | +/// If an expression is an array index expression or an object dereference |
| 20 | +/// expression with a non-constant offset, e.g. a[i] or *(b+i) with a |
| 21 | +/// non-constant `i`, then replace it by the entire underlying object. |
| 22 | +/// Otherwise, e.g. for a[i] or *(b+i) when `i` is a known constant, |
| 23 | +/// keep the expression in the result. |
| 24 | +/// By `constant` for the index expression, we do not mean a literal constant |
| 25 | +/// expression. Rather, we mean a symbol or an expression the value of which is |
| 26 | +/// known not to change over loop iterations, i.e. an expression that is not |
| 27 | +/// itself part of \p assigns. |
| 28 | +static void dfcc_widen_non_const(const namespacet &ns, assignst &assigns) |
| 29 | +{ |
| 30 | + assignst result; |
| 31 | + const symbolt &object_whole_sym = ns.lookup(CPROVER_PREFIX "object_whole"); |
| 32 | + code_typet object_whole_code_type = to_code_type(object_whole_sym.type); |
| 33 | + havoc_utils_is_constantt is_constant(assigns, ns); |
| 34 | + |
| 35 | + for(const auto &e : assigns) |
| 36 | + { |
| 37 | + if(e.id() == ID_index || e.id() == ID_dereference) |
| 38 | + { |
| 39 | + address_of_exprt address_of_expr(e); |
| 40 | + |
| 41 | + // index or offset is non-constant. |
| 42 | + if(!is_constant(address_of_expr)) |
| 43 | + { |
| 44 | + exprt::operandst args; |
| 45 | + args.emplace_back(address_of_expr); |
| 46 | + result.emplace(side_effect_expr_function_callt( |
| 47 | + object_whole_sym.symbol_expr(), |
| 48 | + args, |
| 49 | + object_whole_code_type.return_type(), |
| 50 | + address_of_expr.source_location())); |
| 51 | + } |
| 52 | + else |
| 53 | + result.emplace(e); |
| 54 | + } |
| 55 | + else |
| 56 | + result.emplace(e); |
| 57 | + } |
| 58 | + assigns.swap(result); |
| 59 | +} |
| 60 | + |
| 61 | +std::set<exprt> dfcc_infer_loop_assigns( |
| 62 | + const local_may_aliast &local_may_alias, |
| 63 | + const loopt &loop_instructions, |
| 64 | + const source_locationt &loop_head_location, |
| 65 | + messaget &log, |
| 66 | + namespacet &ns) |
| 67 | +{ |
| 68 | + try |
| 69 | + { |
| 70 | + // infer |
| 71 | + assignst assigns; |
| 72 | + get_assigns(local_may_alias, loop_instructions, assigns); |
| 73 | + |
| 74 | + // compute locals |
| 75 | + std::set<irep_idt> loop_locals; |
| 76 | + for(const auto &target : loop_instructions) |
| 77 | + { |
| 78 | + if(target->is_decl()) |
| 79 | + { |
| 80 | + loop_locals.insert(target->decl_symbol().get_identifier()); |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + // remove all targets that depend on loop-local identifiers |
| 85 | + auto expr_it = assigns.begin(); |
| 86 | + while(expr_it != assigns.end()) |
| 87 | + { |
| 88 | + const std::unordered_set<irep_idt> symbols = |
| 89 | + find_symbol_identifiers(*expr_it); |
| 90 | + |
| 91 | + if(std::find_if(symbols.begin(), symbols.end(), [&](const irep_idt &id) { |
| 92 | + return loop_locals.find(id) != loop_locals.end(); |
| 93 | + }) != symbols.end()) |
| 94 | + { |
| 95 | + expr_it = assigns.erase(expr_it); |
| 96 | + } |
| 97 | + else |
| 98 | + { |
| 99 | + expr_it++; |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + // widen all targets that depend on non-constant expressions |
| 104 | + dfcc_widen_non_const(ns, assigns); |
| 105 | + return assigns; |
| 106 | + } |
| 107 | + catch(const analysis_exceptiont &exc) |
| 108 | + { |
| 109 | + log.error() << "Failed to infer memory locations assigned by the loop at " |
| 110 | + << loop_head_location |
| 111 | + << ".\nPlease specify an assigns clause.\nReason:" |
| 112 | + << messaget::eom; |
| 113 | + throw exc; |
| 114 | + } |
| 115 | +} |
0 commit comments