CBMC
abstract_environment.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3  Module: analyses variable-sensitivity
4 
5  Author: Thomas Kiley, thomas.kiley@diffblue.com
6 
7 \*******************************************************************/
8 
9 #include <util/expr_util.h>
10 #include <util/namespace.h>
11 #include <util/simplify_expr.h>
12 #include <util/simplify_utils.h>
13 #include <util/symbol_table.h>
14 
17 
18 #include <algorithm>
19 #include <map>
20 #include <ostream>
21 #include <stack>
22 
23 #ifdef DEBUG
24 # include <iostream>
25 #endif
26 
30 
31 typedef exprt (
33 
34 static exprt
35 assume_not(abstract_environmentt &env, const exprt &expr, const namespacet &ns);
36 static exprt
37 assume_or(abstract_environmentt &env, const exprt &expr, const namespacet &ns);
38 static exprt
39 assume_and(abstract_environmentt &env, const exprt &expr, const namespacet &ns);
40 static exprt
41 assume_eq(abstract_environmentt &env, const exprt &expr, const namespacet &ns);
42 static exprt assume_noteq(
44  const exprt &expr,
45  const namespacet &ns);
46 static exprt assume_less_than(
48  const exprt &expr,
49  const namespacet &ns);
52  const exprt &expr,
53  const namespacet &ns);
54 
56 static bool is_value(const abstract_object_pointert &obj);
57 
58 std::vector<abstract_object_pointert> eval_operands(
59  const exprt &expr,
60  const abstract_environmentt &env,
61  const namespacet &ns);
62 
63 bool is_ptr_diff(const exprt &expr)
64 {
65  return (expr.id() == ID_minus) &&
66  (expr.operands()[0].type().id() == ID_pointer) &&
67  (expr.operands()[1].type().id() == ID_pointer);
68 }
69 
70 bool is_ptr_comparison(const exprt &expr)
71 {
72  auto const &id = expr.id();
73  bool is_comparison = id == ID_equal || id == ID_notequal || id == ID_lt ||
74  id == ID_le || id == ID_gt || id == ID_ge;
75 
76  return is_comparison && (expr.operands()[0].type().id() == ID_pointer) &&
77  (expr.operands()[1].type().id() == ID_pointer);
78 }
79 
80 static bool is_access_expr(const irep_idt &id)
81 {
82  return id == ID_member || id == ID_index || id == ID_dereference;
83 }
84 
85 static bool is_object_creation(const irep_idt &id)
86 {
87  return id == ID_array || id == ID_struct || id == ID_constant ||
88  id == ID_address_of;
89 }
90 
91 static bool is_dynamic_allocation(const exprt &expr)
92 {
93  return expr.id() == ID_side_effect && expr.get(ID_statement) == ID_allocate;
94 }
95 
97 abstract_environmentt::eval(const exprt &expr, const namespacet &ns) const
98 {
99  if(bottom)
100  return abstract_object_factory(expr.type(), ns, false, true);
101 
102  // first try to canonicalise, including constant folding
103  const exprt &simplified_expr = simplify_expr(expr, ns);
104 
105  const irep_idt simplified_id = simplified_expr.id();
106  if(simplified_id == ID_symbol)
107  return resolve_symbol(simplified_expr, ns);
108 
109  if(
110  is_access_expr(simplified_id) || is_ptr_diff(simplified_expr) ||
111  is_ptr_comparison(simplified_expr))
112  {
113  auto const operands = eval_operands(simplified_expr, *this, ns);
114  auto const &target = operands.front();
115 
116  return target->expression_transform(simplified_expr, operands, *this, ns);
117  }
118 
119  if(is_object_creation(simplified_id))
120  return abstract_object_factory(simplified_expr.type(), simplified_expr, ns);
121 
122  if(is_dynamic_allocation(simplified_expr))
124  typet(ID_dynamic_object),
125  exprt(ID_dynamic_object, simplified_expr.type()),
126  ns);
127 
128  // No special handling required by the abstract environment
129  // delegate to the abstract object
130  if(!simplified_expr.operands().empty())
131  return eval_expression(simplified_expr, ns);
132 
133  // It is important that this is top as the abstract object may not know
134  // how to handle the expression
135  return abstract_object_factory(simplified_expr.type(), ns, true, false);
136 }
137 
139  const exprt &expr,
140  const namespacet &ns) const
141 {
142  const symbol_exprt &symbol(to_symbol_expr(expr));
143  const auto symbol_entry = map.find(symbol.get_identifier());
144 
145  if(symbol_entry.has_value())
146  return symbol_entry.value();
147  return abstract_object_factory(expr.type(), ns, true, false);
148 }
149 
151  const exprt &expr,
152  const abstract_object_pointert &value,
153  const namespacet &ns)
154 {
155  PRECONDITION(value);
156 
157  if(value->is_bottom())
158  {
159  bool bottom_at_start = this->is_bottom();
160  this->make_bottom();
161  return !bottom_at_start;
162  }
163 
164  abstract_object_pointert lhs_value = nullptr;
165  // Build a stack of index, member and dereference accesses which
166  // we will work through the relevant abstract objects
167  exprt s = expr;
168  std::stack<exprt> stactions; // I'm not a continuation, honest guv'
169  while(s.id() != ID_symbol)
170  {
171  if(s.id() == ID_index || s.id() == ID_member || s.id() == ID_dereference)
172  {
173  stactions.push(s);
174  s = s.operands()[0];
175  }
176  else
177  {
178  lhs_value = eval(s, ns);
179  break;
180  }
181  }
182 
183  if(!lhs_value)
184  {
185  INVARIANT(s.id() == ID_symbol, "Have a symbol or a stack");
186  lhs_value = resolve_symbol(s, ns);
187  }
188 
189  abstract_object_pointert final_value;
190 
191  // This is the root abstract object that is in the map of abstract objects
192  // It might not have the same type as value if the above stack isn't empty
193 
194  if(!stactions.empty())
195  {
196  // The symbol is not in the map - it is therefore top
197  final_value = write(lhs_value, value, stactions, ns, false);
198  }
199  else
200  {
201  // If we don't have a symbol on the LHS, then we must have some expression
202  // that we can write to (i.e. a pointer, an array, a struct) This appears
203  // to be none of that.
204  if(s.id() != ID_symbol)
205  {
206  throw std::runtime_error("invalid l-value");
207  }
208  // We can assign the AO directly to the symbol
209  final_value = value;
210  }
211 
212  // Write the value for the root symbol back into the map
213  INVARIANT(
214  lhs_value->type() == final_value->type(),
215  "Assignment types must match"
216  "\n"
217  "lhs_type :" +
218  lhs_value->type().pretty() +
219  "\n"
220  "rhs_type :" +
221  final_value->type().pretty());
222 
223  // If LHS was directly the symbol
224  if(s.id() == ID_symbol)
225  {
226  symbol_exprt symbol_expr = to_symbol_expr(s);
227 
228  if(final_value != lhs_value)
229  {
230  CHECK_RETURN(!symbol_expr.get_identifier().empty());
231  map.insert_or_replace(symbol_expr.get_identifier(), final_value);
232  }
233  }
234  return true;
235 }
236 
238  const abstract_object_pointert &lhs,
239  const abstract_object_pointert &rhs,
240  std::stack<exprt> remaining_stack,
241  const namespacet &ns,
242  bool merge_write)
243 {
244  PRECONDITION(!remaining_stack.empty());
245  const exprt &next_expr = remaining_stack.top();
246  remaining_stack.pop();
247 
248  const irep_idt &stack_head_id = next_expr.id();
249  INVARIANT(
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");
253 
254  return lhs->write(*this, ns, remaining_stack, next_expr, rhs, merge_write);
255 }
256 
257 bool abstract_environmentt::assume(const exprt &expr, const namespacet &ns)
258 {
259  // We should only attempt to assume Boolean things
260  // This should be enforced by the well-structured-ness of the
261  // goto-program and the way assume is used.
262  PRECONDITION(expr.is_boolean());
263 
264  auto simplified = simplify_expr(expr, ns);
265  auto assumption = do_assume(simplified, ns);
266 
267  if(assumption.id() != ID_nil) // I.E. actually a value
268  {
269  // Should be of the right type
270  INVARIANT(assumption.is_boolean(), "simplification preserves type");
271 
272  if(assumption.is_false())
273  {
274  bool currently_bottom = is_bottom();
275  make_bottom();
276  return !currently_bottom;
277  }
278  }
279 
280  return false;
281 }
282 
283 static auto assume_functions =
284  std::map<irep_idt, assume_function>{{ID_not, assume_not},
285  {ID_and, assume_and},
286  {ID_or, assume_or},
287  {ID_equal, assume_eq},
288  {ID_notequal, assume_noteq},
289  {ID_le, assume_less_than},
290  {ID_lt, assume_less_than},
291  {ID_ge, assume_greater_than},
292  {ID_gt, assume_greater_than}};
293 
294 // do_assume attempts to reduce the expression
295 // returns
296 // true_exprt when the assumption does not hold
297 // false_exprt if the assumption does not hold & the domain should go bottom
298 // nil_exprt if the assumption can't be evaluated & we should give up
300 {
301  auto expr_id = expr.id();
302 
303  auto fn = assume_functions[expr_id];
304 
305  if(fn)
306  return fn(*this, expr, ns);
307 
308  return eval(expr, ns)->to_constant();
309 }
310 
312  const typet &type,
313  const namespacet &ns,
314  bool top,
315  bool bttm) const
316 {
317  exprt empty_constant_expr = nil_exprt();
319  type, top, bttm, empty_constant_expr, *this, ns);
320 }
321 
323  const typet &type,
324  const exprt &e,
325  const namespacet &ns) const
326 {
327  return abstract_object_factory(type, false, false, e, *this, ns);
328 }
329 
331  const typet &type,
332  bool top,
333  bool bttm,
334  const exprt &e,
335  const abstract_environmentt &environment,
336  const namespacet &ns) const
337 {
338  return object_factory->get_abstract_object(
339  type, top, bttm, e, environment, ns);
340 }
341 
343 {
344  return object_factory->config();
345 }
346 
348  const abstract_environmentt &env,
349  const goto_programt::const_targett &merge_location,
350  widen_modet widen_mode)
351 {
352  // for each entry in the incoming environment we need to either add it
353  // if it is new, or merge with the existing key if it is not present
354  if(bottom)
355  {
356  *this = env;
357  return !env.bottom;
358  }
359 
360  if(env.bottom)
361  return false;
362 
363  // For each element in the intersection of map and env.map merge
364  // If the result of the merge is top, remove from the map
365  bool modified = false;
366  for(const auto &entry : env.map.get_delta_view(map))
367  {
368  auto merge_result = abstract_objectt::merge(
369  entry.get_other_map_value(), entry.m, merge_location, widen_mode);
370 
371  modified |= merge_result.modified;
372  map.replace(entry.k, merge_result.object);
373  }
374 
375  return modified;
376 }
377 
378 void abstract_environmentt::havoc(const std::string &havoc_string)
379 {
380  // TODO(tkiley): error reporting
381  make_top();
382 }
383 
385 {
386  // since we assume anything is not in the map is top this is sufficient
387  map.clear();
388  bottom = false;
389 }
390 
392 {
393  map.clear();
394  bottom = true;
395 }
396 
398 {
399  return map.empty() && bottom;
400 }
401 
403 {
404  return map.empty() && !bottom;
405 }
406 
408  std::ostream &out,
409  const ai_baset &ai,
410  const namespacet &ns) const
411 {
412  out << "{\n";
413 
414  for(const auto &entry : map.get_view())
415  {
416  out << entry.first << " () -> ";
417  entry.second->output(out, ai, ns);
418  out << "\n";
419  }
420 
421  out << "}\n";
422 }
423 
425 {
426  if(is_bottom())
427  return false_exprt();
428  if(is_top())
429  return true_exprt();
430 
431  exprt::operandst predicates;
432  for(const auto &entry : map.get_view())
433  {
434  auto sym = entry.first;
435  auto val = entry.second;
436  auto pred = val->to_predicate(symbol_exprt(sym, val->type()));
437 
438  predicates.push_back(pred);
439  }
440 
441  if(predicates.size() == 1)
442  return predicates.front();
443 
444  sort_operands(predicates);
445  return and_exprt(predicates);
446 }
447 
449 {
450  for(const auto &entry : map.get_view())
451  {
452  if(entry.second == nullptr)
453  {
454  return false;
455  }
456  }
457  return true;
458 }
459 
461  const exprt &e,
462  const namespacet &ns) const
463 {
464  // We create a temporary top abstract object (according to the
465  // type of the expression), and call expression transform on it.
466  // The value of the temporary abstract object is ignored, its
467  // purpose is just to dispatch the expression transform call to
468  // a concrete subtype of abstract_objectt.
469  auto eval_obj = abstract_object_factory(e.type(), ns, true, false);
470  auto operands = eval_operands(e, *this, ns);
471 
472  return eval_obj->expression_transform(e, operands, *this, ns);
473 }
474 
476 {
477  map.erase_if_exists(expr.get_identifier());
478 }
479 
480 std::vector<abstract_environmentt::map_keyt>
482  const abstract_environmentt &first,
483  const abstract_environmentt &second)
484 {
485  // Find all symbols who have different write locations in each map
486  std::vector<abstract_environmentt::map_keyt> symbols_diff;
487  for(const auto &entry : first.map.get_view())
488  {
489  const auto &second_entry = second.map.find(entry.first);
490  if(second_entry.has_value())
491  {
492  if(second_entry.value().get()->has_been_modified(entry.second))
493  {
494  CHECK_RETURN(!entry.first.empty());
495  symbols_diff.push_back(entry.first);
496  }
497  }
498  }
499 
500  // Add any symbols that are only in the second map
501  for(const auto &entry : second.map.get_view())
502  {
503  const auto &second_entry = first.map.find(entry.first);
504  if(!second_entry.has_value())
505  {
506  CHECK_RETURN(!entry.first.empty());
507  symbols_diff.push_back(entry.first);
508  }
509  }
510  return symbols_diff;
511 }
512 
513 static std::size_t count_globals(const namespacet &ns)
514 {
515  auto const &symtab = ns.get_symbol_table();
516  auto val = std::count_if(
517  symtab.begin(),
518  symtab.end(),
519  [](const symbol_tablet::const_iteratort::value_type &sym) {
520  return sym.second.is_lvalue && sym.second.is_static_lifetime;
521  });
522  return val;
523 }
524 
527 {
528  abstract_object_statisticst statistics = {};
529  statistics.number_of_globals = count_globals(ns);
530  abstract_object_visitedt visited;
531  for(auto const &object : map.get_view())
532  {
533  if(visited.find(object.second) == visited.end())
534  {
535  object.second->get_statistics(statistics, visited, *this, ns);
536  }
537  }
538  return statistics;
539 }
540 
541 std::vector<abstract_object_pointert> eval_operands(
542  const exprt &expr,
543  const abstract_environmentt &env,
544  const namespacet &ns)
545 {
546  std::vector<abstract_object_pointert> operands;
547 
548  for(const auto &op : expr.operands())
549  operands.push_back(env.eval(op, ns));
550 
551  return operands;
552 }
553 
556 {
557  return std::dynamic_pointer_cast<const abstract_value_objectt>(
558  obj->unwrap_context());
559 }
560 
562 {
563  return as_value(obj) != nullptr;
564 }
565 
566 static auto inverse_operations =
567  std::map<irep_idt, irep_idt>{{ID_equal, ID_notequal},
568  {ID_notequal, ID_equal},
569  {ID_le, ID_gt},
570  {ID_lt, ID_ge},
571  {ID_ge, ID_lt},
572  {ID_gt, ID_le}};
573 
574 static exprt invert_result(const exprt &result)
575 {
576  if(!result.is_boolean())
577  return result;
578 
579  if(result.is_true())
580  return false_exprt();
581  return true_exprt();
582 }
583 
584 static exprt invert_expr(const exprt &expr)
585 {
586  auto expr_id = expr.id();
587 
588  auto inverse_operation = inverse_operations.find(expr_id);
589  if(inverse_operation == inverse_operations.end())
590  return nil_exprt();
591 
592  auto relation_expr = to_binary_relation_expr(expr);
593  auto inverse_op = inverse_operation->second;
594  return binary_relation_exprt(
595  relation_expr.lhs(), inverse_op, relation_expr.rhs());
596 }
597 
600  const abstract_object_pointert &previous,
601  const exprt &destination,
603  const namespacet &ns)
604 {
605  auto context =
606  std::dynamic_pointer_cast<const context_abstract_objectt>(previous);
607  if(context != nullptr)
608  obj = context->envelop(obj);
609  env.assign(destination, obj, ns);
610 }
611 
614  const exprt &expr,
615  const namespacet &ns)
616 {
617  auto const &not_expr = to_not_expr(expr);
618 
619  auto inverse_expression = invert_expr(not_expr.op());
620  if(inverse_expression.is_not_nil())
621  return env.do_assume(inverse_expression, ns);
622 
623  auto result = env.do_assume(not_expr.op(), ns);
624  return invert_result(result);
625 }
626 
629  const exprt &expr,
630  const namespacet &ns)
631 {
632  auto and_expr = to_and_expr(expr);
633  bool nil = false;
634  for(auto const &operand : and_expr.operands())
635  {
636  auto result = env.do_assume(operand, ns);
637  if(result.is_false())
638  return result;
639  nil |= result.is_nil();
640  }
641  if(nil)
642  return nil_exprt();
643  return true_exprt();
644 }
645 
648  const exprt &expr,
649  const namespacet &ns)
650 {
651  auto or_expr = to_or_expr(expr);
652 
653  auto negated_operands = exprt::operandst{};
654  for(auto const &operand : or_expr.operands())
655  negated_operands.push_back(invert_expr(operand));
656 
657  auto result = assume_and(env, and_exprt(negated_operands), ns);
658  return invert_result(result);
659 }
660 
662 {
667 
669  {
670  return as_value(left)->to_interval();
671  }
673  {
674  return as_value(right)->to_interval();
675  }
676 
677  bool are_bad() const
678  {
679  return left == nullptr || right == nullptr ||
680  (left->is_top() && right->is_top()) || !is_value(left) ||
681  !is_value(right);
682  }
683 
684  bool has_top() const
685  {
686  return left->is_top() || right->is_top();
687  }
688 };
689 
692  const exprt &expr,
693  const namespacet &ns)
694 {
695  auto const &relationship_expr = to_binary_expr(expr);
696 
697  auto lhs = relationship_expr.lhs();
698  auto rhs = relationship_expr.rhs();
699  auto left = env.eval(lhs, ns);
700  auto right = env.eval(rhs, ns);
701 
702  if(left->is_top() && right->is_top())
703  return {};
704 
705  return {lhs, rhs, left, right};
706 }
707 
710  const left_and_right_valuest &operands,
711  const namespacet &ns)
712 {
713  if(operands.left->is_top() && is_assignable(operands.lhs))
714  {
715  // TOP == x
716  auto constrained = std::make_shared<interval_abstract_valuet>(
717  operands.right_interval(), env, ns);
718  prune_assign(env, operands.left, operands.lhs, constrained, ns);
719  }
720  if(operands.right->is_top() && is_assignable(operands.rhs))
721  {
722  // x == TOP
723  auto constrained = std::make_shared<interval_abstract_valuet>(
724  operands.left_interval(), env, ns);
725  prune_assign(env, operands.right, operands.rhs, constrained, ns);
726  }
727  return true_exprt();
728 }
729 
732  const exprt &expr,
733  const namespacet &ns)
734 {
735  auto operands = eval_operands_as_values(env, expr, ns);
736 
737  if(operands.are_bad())
738  return nil_exprt();
739 
740  if(operands.has_top())
741  return assume_eq_unbounded(env, operands, ns);
742 
743  auto meet = operands.left->meet(operands.right);
744 
745  if(meet->is_bottom())
746  return false_exprt();
747 
748  if(is_assignable(operands.lhs))
749  prune_assign(env, operands.left, operands.lhs, meet, ns);
750  if(is_assignable(operands.rhs))
751  prune_assign(env, operands.right, operands.rhs, meet, ns);
752  return true_exprt();
753 }
754 
757  const exprt &expr,
758  const namespacet &ns)
759 {
760  auto const &notequal_expr = to_binary_expr(expr);
761 
762  auto left = env.eval(notequal_expr.lhs(), ns);
763  auto right = env.eval(notequal_expr.rhs(), ns);
764 
765  if(left->is_top() || right->is_top())
766  return nil_exprt();
767  if(!is_value(left) || !is_value(right))
768  return nil_exprt();
769 
770  auto meet = left->meet(right);
771 
772  if(meet->is_bottom())
773  return true_exprt();
774 
775  return false_exprt();
776 }
777 
780  const left_and_right_valuest &operands,
781  const namespacet &ns)
782 {
783  if(operands.left->is_top() && is_assignable(operands.lhs))
784  {
785  // TOP < x, so prune range is min->right.upper
786  auto pruned_expr = constant_interval_exprt(
787  min_value_exprt(operands.left->type()),
788  operands.right_interval().get_upper(),
789  operands.left->type());
790  auto constrained =
791  std::make_shared<interval_abstract_valuet>(pruned_expr, env, ns);
792  prune_assign(env, operands.left, operands.lhs, constrained, ns);
793  }
794  if(operands.right->is_top() && is_assignable(operands.rhs))
795  {
796  // x < TOP, so prune range is left.lower->max
797  auto pruned_expr = constant_interval_exprt(
798  operands.left_interval().get_lower(),
799  max_value_exprt(operands.right->type()),
800  operands.right->type());
801  auto constrained =
802  std::make_shared<interval_abstract_valuet>(pruned_expr, env, ns);
803  prune_assign(env, operands.right, operands.rhs, constrained, ns);
804  }
805 
806  return true_exprt();
807 }
808 
811  const exprt &expr,
812  const namespacet &ns)
813 {
814  auto operands = eval_operands_as_values(env, expr, ns);
815  if(operands.are_bad())
816  return nil_exprt();
817 
818  if(operands.has_top())
819  return assume_less_than_unbounded(env, operands, ns);
820 
821  auto left_interval = operands.left_interval();
822  auto right_interval = operands.right_interval();
823 
824  const auto &left_lower = left_interval.get_lower();
825  const auto &right_upper = right_interval.get_upper();
826 
827  auto reduced_le_expr =
828  binary_relation_exprt(left_lower, expr.id(), right_upper);
829  auto result = env.eval(reduced_le_expr, ns)->to_constant();
830  if(result.is_true())
831  {
832  if(is_assignable(operands.lhs))
833  {
834  auto pruned_upper = constant_interval_exprt::get_min(
835  left_interval.get_upper(), right_upper);
836  auto constrained =
837  as_value(operands.left)->constrain(left_lower, pruned_upper);
838  prune_assign(env, operands.left, operands.lhs, constrained, ns);
839  }
840  if(is_assignable(operands.rhs))
841  {
842  auto pruned_lower = constant_interval_exprt::get_max(
843  left_lower, right_interval.get_lower());
844  auto constrained =
845  as_value(operands.right)->constrain(pruned_lower, right_upper);
846  prune_assign(env, operands.right, operands.rhs, constrained, ns);
847  }
848  }
849  return result;
850 }
851 
852 static auto symmetric_operations =
853  std::map<irep_idt, irep_idt>{{ID_ge, ID_le}, {ID_gt, ID_lt}};
854 
857  const exprt &expr,
858  const namespacet &ns)
859 {
860  auto const &gt_expr = to_binary_expr(expr);
861 
862  auto symmetric_op = symmetric_operations[gt_expr.id()];
863  auto symmetric_expr =
864  binary_relation_exprt(gt_expr.rhs(), symmetric_op, gt_expr.lhs());
865 
866  return assume_less_than(env, symmetric_expr, ns);
867 }
std::vector< abstract_object_pointert > eval_operands(const exprt &expr, const abstract_environmentt &env, const namespacet &ns)
static auto assume_functions
static bool is_value(const abstract_object_pointert &obj)
static exprt assume_not(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
static auto inverse_operations
static exprt invert_expr(const exprt &expr)
static abstract_value_pointert as_value(const abstract_object_pointert &obj)
static bool is_object_creation(const irep_idt &id)
static auto symmetric_operations
static bool is_access_expr(const irep_idt &id)
left_and_right_valuest eval_operands_as_values(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
static exprt assume_eq(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
static exprt assume_noteq(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
static std::size_t count_globals(const namespacet &ns)
static exprt assume_or(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
exprt(* assume_function)(abstract_environmentt &, const exprt &, const namespacet &)
static exprt assume_less_than(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
static exprt invert_result(const exprt &result)
exprt assume_less_than_unbounded(abstract_environmentt &env, const left_and_right_valuest &operands, const namespacet &ns)
static exprt assume_and(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
bool is_ptr_comparison(const exprt &expr)
void prune_assign(abstract_environmentt &env, const abstract_object_pointert &previous, const exprt &destination, abstract_object_pointert obj, const namespacet &ns)
static bool is_dynamic_allocation(const exprt &expr)
exprt assume_eq_unbounded(abstract_environmentt &env, const left_and_right_valuest &operands, const namespacet &ns)
static exprt assume_greater_than(abstract_environmentt &env, const exprt &expr, const namespacet &ns)
bool is_ptr_diff(const exprt &expr)
An abstract version of a program environment.
std::set< abstract_object_pointert > abstract_object_visitedt
sharing_ptrt< class abstract_objectt > abstract_object_pointert
Statistics gathering for the variable senstivity domain.
sharing_ptrt< const abstract_value_objectt > abstract_value_pointert
virtual bool assume(const exprt &expr, const namespacet &ns)
Reduces the domain based on a condition.
void output(std::ostream &out, const class ai_baset &ai, const namespacet &ns) const
Print out all the values in the abstract object map.
bool is_bottom() const
Gets whether the domain is bottom.
abstract_object_pointert resolve_symbol(const exprt &e, const namespacet &ns) const
exprt to_predicate() const
Gives a boolean condition that is true for all values represented by the environment.
void make_top()
Set the domain to top (i.e. everything)
virtual abstract_object_pointert eval(const exprt &expr, const namespacet &ns) const
These three are really the heart of the method.
void erase(const symbol_exprt &expr)
Delete a symbol from the map.
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...
bool verify() const
Check the structural invariants are maintained.
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...
exprt do_assume(const exprt &e, const namespacet &ns)
const vsd_configt & configuration() const
Exposes the environment configuration.
variable_sensitivity_object_factory_ptrt object_factory
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.
abstract_object_statisticst gather_statistics(const namespacet &ns) const
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".
void make_bottom()
Set the domain to top (i.e. no possible states / unreachable)
bool is_top() const
Gets whether the domain is top.
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.
virtual abstract_object_pointert eval_expression(const exprt &e, const namespacet &ns) const
virtual bool assign(const exprt &expr, const abstract_object_pointert &value, const namespacet &ns)
Assign a value to an expression.
sharing_mapt< map_keyt, abstract_object_pointert > map
static combine_result merge(const abstract_object_pointert &op1, const abstract_object_pointert &op2, const locationt &merge_location, const widen_modet &widen_mode)
This is the basic interface of the abstract interpreter with default implementations of the core func...
Definition: ai.h:117
Boolean AND.
Definition: std_expr.h:2125
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:762
Represents an interval of values.
Definition: interval.h:52
static exprt get_max(const exprt &a, const exprt &b)
Definition: interval.cpp:960
static exprt get_min(const exprt &a, const exprt &b)
Definition: interval.cpp:965
const exprt & get_lower() const
Definition: interval.cpp:27
const exprt & get_upper() const
Definition: interval.cpp:32
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:27
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition: expr.h:224
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
The Boolean constant false.
Definition: std_expr.h:3082
instructionst::const_iterator const_targett
Definition: goto_program.h:615
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
const irep_idt & id() const
Definition: irep.h:388
bool is_nil() const
Definition: irep.h:368
+∞ upper bound for intervals
Definition: interval.h:18
-∞ upper bound for intervals
Definition: interval.h:33
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
const symbol_table_baset & get_symbol_table() const
Return first symbol table registered with the namespace.
Definition: namespace.h:126
The NIL expression.
Definition: std_expr.h:3091
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
The Boolean constant true.
Definition: std_expr.h:3073
The type of an expression, extends irept.
Definition: type.h:29
General implementation of a an abstract_objectt which can track side information in the form of a 'co...
bool is_assignable(const exprt &expr)
Returns true iff the argument is one of the following:
Definition: expr_util.cpp:24
Deprecated expression utility functions.
An interval to represent a set of possible values.
exprt simplify_expr(exprt src, const namespacet &ns)
bool sort_operands(exprt::operandst &operands)
sort operands of an expression according to ordering defined by operator<
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
const or_exprt & to_or_expr(const exprt &expr)
Cast an exprt to a or_exprt.
Definition: std_expr.h:2280
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const and_exprt & to_and_expr(const exprt &expr)
Cast an exprt to a and_exprt.
Definition: std_expr.h:2172
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition: std_expr.h:2362
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition: std_expr.h:715
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition: std_expr.h:895
abstract_object_pointert right
constant_interval_exprt right_interval() const
constant_interval_exprt left_interval() const
abstract_object_pointert left
Author: Diffblue Ltd.
Tracks the user-supplied configuration for VSD and build the correct type of abstract object when nee...