Go to the documentation of this file.
62 return (expr.
id() == ID_minus) &&
63 (expr.
operands()[0].type().id() == ID_pointer) &&
64 (expr.
operands()[1].type().id() == ID_pointer);
69 auto const &
id = expr.
id();
70 bool is_comparison =
id == ID_equal ||
id == ID_notequal ||
id == ID_lt ||
71 id == ID_le ||
id == ID_gt ||
id == ID_ge;
73 return is_comparison && (expr.
operands()[0].type().id() == ID_pointer) &&
74 (expr.
operands()[1].type().id() == ID_pointer);
79 return id == ID_member ||
id == ID_index ||
id == ID_dereference;
84 return id == ID_array ||
id == ID_struct ||
id == ID_constant ||
90 return expr.
id() == ID_side_effect && expr.
get(ID_statement) == ID_allocate;
102 const irep_idt simplified_id = simplified_expr.
id();
103 if(simplified_id == ID_symbol)
110 auto const operands =
eval_operands(simplified_expr, *
this, ns);
111 auto const &target = operands.front();
113 return target->expression_transform(simplified_expr, operands, *
this, ns);
121 typet(ID_dynamic_object),
122 exprt(ID_dynamic_object, simplified_expr.
type()),
127 if(!simplified_expr.
operands().empty())
142 if(symbol_entry.has_value())
143 return symbol_entry.value();
154 if(value->is_bottom())
156 bool bottom_at_start = this->
is_bottom();
158 return !bottom_at_start;
165 std::stack<exprt> stactions;
166 while(s.
id() != ID_symbol)
168 if(s.
id() == ID_index || s.
id() == ID_member || s.
id() == ID_dereference)
175 lhs_value =
eval(s, ns);
182 INVARIANT(s.
id() == ID_symbol,
"Have a symbol or a stack");
191 if(!stactions.empty())
194 final_value =
write(lhs_value, value, stactions, ns,
false);
201 if(s.
id() != ID_symbol)
203 throw std::runtime_error(
"invalid l-value");
209 const typet &lhs_type = ns.
follow(lhs_value->type());
210 const typet &rhs_type = ns.
follow(final_value->type());
214 lhs_type == rhs_type,
215 "Assignment types must match"
224 if(s.
id() == ID_symbol)
228 if(final_value != lhs_value)
240 std::stack<exprt> remaining_stack,
245 const exprt &next_expr = remaining_stack.top();
246 remaining_stack.pop();
248 const irep_idt &stack_head_id = next_expr.
id();
250 stack_head_id == ID_index || stack_head_id == ID_member ||
251 stack_head_id == ID_dereference,
252 "Write stack expressions must be index, member, or dereference");
254 return lhs->write(*
this, ns, remaining_stack, next_expr, rhs, merge_write);
265 auto assumption =
do_assume(simplified, ns);
267 if(assumption.id() != ID_nil)
271 assumption.type().id() == ID_bool,
"simplification preserves type");
273 if(assumption.is_false())
277 return !currently_bottom;
285 std::map<irep_idt, assume_function>{{ID_not,
assume_not},
302 auto expr_id = expr.
id();
307 return fn(*
this, expr, ns);
309 return eval(expr, ns)->to_constant();
320 type, top, bttm, empty_constant_expr, *
this, ns);
340 type, top, bttm, e, environment, ns);
366 bool modified =
false;
367 for(
const auto &entry : env.
map.get_delta_view(
map))
370 entry.get_other_map_value(), entry.m, merge_location, widen_mode);
372 modified |= merge_result.modified;
373 map.replace(entry.k, merge_result.object);
415 for(
const auto &entry :
map.get_view())
417 out << entry.first <<
" () -> ";
418 entry.second->output(out, ai, ns);
433 for(
const auto &entry :
map.get_view())
435 auto sym = entry.first;
436 auto val = entry.second;
437 auto pred = val->to_predicate(
symbol_exprt(sym, val->type()));
439 predicates.push_back(pred);
442 if(predicates.size() == 1)
443 return predicates.front();
451 for(
const auto &entry :
map.get_view())
453 if(entry.second ==
nullptr)
473 return eval_obj->expression_transform(e, operands, *
this, ns);
481 std::vector<abstract_environmentt::map_keyt>
487 std::vector<abstract_environmentt::map_keyt> symbols_diff;
488 for(
const auto &entry : first.
map.get_view())
490 const auto &second_entry = second.
map.find(entry.first);
491 if(second_entry.has_value())
493 if(second_entry.value().get()->has_been_modified(entry.second))
496 symbols_diff.push_back(entry.first);
502 for(
const auto &entry : second.
map.get_view())
504 const auto &second_entry = first.
map.find(entry.first);
505 if(!second_entry.has_value())
508 symbols_diff.push_back(entry.first);
517 auto val = std::count_if(
520 [](
const symbol_tablet::const_iteratort::value_type &sym) {
521 return sym.second.is_lvalue && sym.second.is_static_lifetime;
532 for(
auto const &
object :
map.get_view())
534 if(visited.find(
object.second) == visited.end())
536 object.second->get_statistics(statistics, visited, *
this, ns);
547 std::vector<abstract_object_pointert> operands;
549 for(
const auto &op : expr.
operands())
550 operands.push_back(env.
eval(op, ns));
558 return std::dynamic_pointer_cast<const abstract_value_objectt>(
559 obj->unwrap_context());
568 std::map<irep_idt, irep_idt>{{ID_equal, ID_notequal},
569 {ID_notequal, ID_equal},
587 auto expr_id = expr.
id();
594 auto inverse_op = inverse_operation->second;
596 relation_expr.lhs(), inverse_op, relation_expr.rhs());
602 const exprt &destination,
607 std::dynamic_pointer_cast<const context_abstract_objectt>(previous);
608 if(context !=
nullptr)
609 obj = context->envelop(obj);
610 env.
assign(destination, obj, ns);
620 auto inverse_expression =
invert_expr(not_expr.op());
621 if(inverse_expression.is_not_nil())
622 return env.
do_assume(inverse_expression, ns);
624 auto result = env.
do_assume(not_expr.op(), ns);
635 for(
auto const &operand : and_expr.operands())
637 auto result = env.
do_assume(operand, ns);
638 if(result.is_false())
655 for(
auto const &operand : or_expr.operands())
680 return left ==
nullptr ||
right ==
nullptr ||
687 return left->is_top() ||
right->is_top();
698 auto lhs = relationship_expr.lhs();
699 auto rhs = relationship_expr.rhs();
700 auto left = env.
eval(lhs, ns);
701 auto right = env.
eval(rhs, ns);
703 if(left->is_top() && right->is_top())
706 return {lhs, rhs, left, right};
717 auto constrained = std::make_shared<interval_abstract_valuet>(
724 auto constrained = std::make_shared<interval_abstract_valuet>(
738 if(operands.are_bad())
741 if(operands.has_top())
744 auto meet = operands.left->meet(operands.right);
746 if(meet->is_bottom())
750 prune_assign(env, operands.left, operands.lhs, meet, ns);
752 prune_assign(env, operands.right, operands.rhs, meet, ns);
763 auto left = env.
eval(notequal_expr.lhs(), ns);
764 auto right = env.
eval(notequal_expr.rhs(), ns);
766 if(left->is_top() || right->is_top())
771 auto meet = left->meet(right);
773 if(meet->is_bottom())
790 operands.
left->type());
792 std::make_shared<interval_abstract_valuet>(pruned_expr, env, ns);
801 operands.
right->type());
803 std::make_shared<interval_abstract_valuet>(pruned_expr, env, ns);
816 if(operands.are_bad())
819 if(operands.has_top())
822 auto left_interval = operands.left_interval();
823 auto right_interval = operands.right_interval();
825 const auto &left_lower = left_interval.get_lower();
826 const auto &right_upper = right_interval.get_upper();
828 auto reduced_le_expr =
830 auto result = env.
eval(reduced_le_expr, ns)->to_constant();
836 left_interval.get_upper(), right_upper);
838 as_value(operands.left)->constrain(left_lower, pruned_upper);
839 prune_assign(env, operands.left, operands.lhs, constrained, ns);
844 left_lower, right_interval.get_lower());
846 as_value(operands.right)->constrain(pruned_lower, right_upper);
847 prune_assign(env, operands.right, operands.rhs, constrained, ns);
854 std::map<irep_idt, irep_idt>{{ID_ge, ID_le}, {ID_gt, ID_lt}};
864 auto symmetric_expr =
exprt assume_eq_unbounded(abstract_environmentt &env, const left_and_right_valuest &operands, const namespacet &ns)
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
std::size_t number_of_globals
void prune_assign(abstract_environmentt &env, const abstract_object_pointert &previous, const exprt &destination, abstract_object_pointert obj, const namespacet &ns)
bool is_assignable(const exprt &expr)
Returns true iff the argument is one of the following:
static bool is_dynamic_allocation(const exprt &expr)
sharing_ptrt< const abstract_value_objectt > abstract_value_pointert
sharing_ptrt< class abstract_objectt > abstract_object_pointert
exprt assume_less_than_unbounded(abstract_environmentt &env, const left_and_right_valuest &operands, const namespacet &ns)
exprt to_predicate() const
Gives a boolean condition that is true for all values represented by the environment.
virtual abstract_object_pointert write(const abstract_object_pointert &lhs, const abstract_object_pointert &rhs, std::stack< exprt > remaining_stack, const namespacet &ns, bool merge_write)
Used within assign to do the actual dispatch.
#define CHECK_RETURN(CONDITION)
The type of an expression, extends irept.
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
static exprt get_max(const exprt &a, const exprt &b)
abstract_object_pointert resolve_symbol(const exprt &e, const namespacet &ns) const
static bool is_access_expr(const irep_idt &id)
+∞ upper bound for intervals
virtual bool assign(const exprt &expr, const abstract_object_pointert &value, const namespacet &ns)
Assign a value to an expression.
bool verify() const
Check the structural invariants are maintained.
Base class for all expressions.
constant_interval_exprt left_interval() const
void output(std::ostream &out, const class ai_baset &ai, const namespacet &ns) const
Print out all the values in the abstract object map.
virtual void havoc(const std::string &havoc_string)
This should be used as a default case / everything else has failed The string is so that I can easily...
-∞ upper bound for intervals
bool is_true() const
Return whether the expression is a constant representing true.
Expression to hold a symbol (variable)
void make_top()
Set the domain to top (i.e. everything)
static auto inverse_operations
Represents an interval of values.
const irep_idt & get(const irep_idt &name) const
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
virtual abstract_object_pointert eval_expression(const exprt &e, const namespacet &ns) const
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
typet & type()
Return the type of the expression.
static auto assume_functions
variable_sensitivity_object_factory_ptrt object_factory
bool is_top() const
Gets whether the domain is top.
static combine_result merge(const abstract_object_pointert &op1, const abstract_object_pointert &op2, const locationt &merge_location, const widen_modet &widen_mode)
abstract_object_pointert left
static bool is_value(const abstract_object_pointert &obj)
virtual abstract_object_pointert abstract_object_factory(const typet &type, const namespacet &ns, bool top, bool bottom) const
Look at the configuration for the sensitivity and create an appropriate abstract_object.
#define PRECONDITION(CONDITION)
const irep_idt & get_identifier() const
void make_bottom()
Set the domain to top (i.e. no possible states / unreachable)
static exprt assume_or(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
static exprt assume_greater_than(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
virtual bool merge(const abstract_environmentt &env, const goto_programt::const_targett &merge_location, widen_modet widen_mode)
Computes the join between "this" and "b".
constant_interval_exprt right_interval() const
bool is_ptr_diff(const exprt &expr)
exprt simplify_expr(exprt src, const namespacet &ns)
sharing_mapt< map_keyt, abstract_object_pointert > map
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
virtual abstract_object_pointert eval(const exprt &expr, const namespacet &ns) const
These three are really the heart of the method.
const irep_idt & id() const
std::vector< exprt > operandst
The Boolean constant false.
std::set< abstract_object_pointert > abstract_object_visitedt
static exprt assume_eq(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
exprt do_assume(const exprt &e, const namespacet &ns)
static exprt invert_result(const exprt &result)
static auto symmetric_operations
static exprt assume_less_than(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
const or_exprt & to_or_expr(const exprt &expr)
Cast an exprt to a or_exprt.
Deprecated expression utility functions.
const symbol_table_baset & get_symbol_table() const
Return first symbol table registered with the namespace.
static bool is_object_creation(const irep_idt &id)
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
static exprt assume_not(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
static abstract_value_pointert as_value(const abstract_object_pointert &obj)
A base class for relations, i.e., binary predicates whose two operands have the same type.
This is the basic interface of the abstract interpreter with default implementations of the core func...
const exprt & get_lower() const
static std::vector< abstract_environmentt::map_keyt > modified_symbols(const abstract_environmentt &first, const abstract_environmentt &second)
For our implementation of variable sensitivity domains, we need to be able to efficiently find symbol...
instructionst::const_iterator const_targett
const exprt & get_upper() const
static exprt get_min(const exprt &a, const exprt &b)
static exprt assume_noteq(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
static std::size_t count_globals(const namespacet &ns)
const vsd_configt & configuration() const
Exposes the environment configuration.
exprt(* assume_function)(abstract_environmentt &, const exprt &, const namespacet &)
The Boolean constant true.
bool is_boolean() const
Return whether the expression represents a Boolean.
static exprt invert_expr(const exprt &expr)
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
std::vector< abstract_object_pointert > eval_operands(const exprt &expr, const abstract_environmentt &env, const namespacet &ns)
abstract_object_statisticst gather_statistics(const namespacet &ns) const
static exprt assume_and(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
bool is_bottom() const
Gets whether the domain is bottom.
abstract_object_pointert right
left_and_right_valuest eval_operands_as_values(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
void erase(const symbol_exprt &expr)
Delete a symbol from the map.
const and_exprt & to_and_expr(const exprt &expr)
Cast an exprt to a and_exprt.
bool sort_operands(exprt::operandst &operands)
sort operands of an expression according to ordering defined by operator<
virtual bool assume(const exprt &expr, const namespacet &ns)
Reduces the domain based on a condition.
bool is_ptr_comparison(const exprt &expr)