CBMC
utils.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Utility functions for code contracts.
4 
5 Author: Saswat Padhi, saspadhi@amazon.com
6 
7 Date: September 2021
8 
9 \*******************************************************************/
10 
11 #include "utils.h"
12 
13 #include <goto-programs/cfg.h>
14 
15 #include <util/fresh_symbol.h>
16 #include <util/graph.h>
17 #include <util/message.h>
18 #include <util/pointer_expr.h>
20 #include <util/simplify_expr.h>
21 
22 #include <langapi/language_util.h>
23 
25  const source_locationt location,
26  const namespacet &ns,
27  const exprt &expr,
28  goto_programt &dest,
29  const std::function<void()> &havoc_code_impl)
30 {
31  goto_programt skip_program;
32  const auto skip_target = skip_program.add(goto_programt::make_skip(location));
33 
34  // skip havocing only if all pointer derefs in the expression are valid
35  // (to avoid spurious pointer deref errors)
37  skip_target, not_exprt{all_dereferences_are_valid(expr, ns)}, location));
38 
39  havoc_code_impl();
40 
41  // add the final skip target
42  dest.destructive_append(skip_program);
43 }
44 
46  const source_locationt location,
47  const exprt &expr,
48  goto_programt &dest) const
49 {
50  append_safe_havoc_code_for_expr(location, ns, expr, dest, [&]() {
52  });
53 }
54 
56  const source_locationt location,
57  const exprt &expr,
58  goto_programt &dest) const
59 {
60  append_safe_havoc_code_for_expr(location, ns, expr, dest, [&]() {
62  });
63 }
64 
66  const source_locationt location,
67  const exprt &expr,
68  goto_programt &dest) const
69 {
70  if(expr.id() == ID_pointer_object)
71  {
73  location, to_pointer_object_expr(expr).pointer(), dest);
74  return;
75  }
76 
77  havoc_utilst::append_havoc_code_for_expr(location, expr, dest);
78 }
79 
81 {
82  exprt::operandst validity_checks;
83 
84  if(expr.id() == ID_dereference)
85  validity_checks.push_back(
86  good_pointer_def(to_dereference_expr(expr).pointer(), ns));
87 
88  for(const auto &op : expr.operands())
89  validity_checks.push_back(all_dereferences_are_valid(op, ns));
90 
91  return conjunction(validity_checks);
92 }
93 
95  const std::vector<symbol_exprt> &lhs,
96  const std::vector<symbol_exprt> &rhs)
97 {
98  PRECONDITION(lhs.size() == rhs.size());
99 
100  if(lhs.empty())
101  {
102  return false_exprt();
103  }
104 
105  // Store conjunctions of equalities.
106  // For example, suppose that the two input vectors are <s1, s2, s3> and <l1,
107  // l2, l3>.
108  // Then this vector stores <s1 == l1, s1 == l1 && s2 == l2,
109  // s1 == l1 && s2 == l2 && s3 == l3>.
110  // In fact, the last element is unnecessary, so we do not create it.
111  exprt::operandst equality_conjunctions(lhs.size());
112  equality_conjunctions[0] = binary_relation_exprt(lhs[0], ID_equal, rhs[0]);
113  for(size_t i = 1; i < equality_conjunctions.size() - 1; i++)
114  {
115  binary_relation_exprt component_i_equality{lhs[i], ID_equal, rhs[i]};
116  equality_conjunctions[i] =
117  and_exprt(equality_conjunctions[i - 1], component_i_equality);
118  }
119 
120  // Store inequalities between the i-th components of the input vectors
121  // (i.e. lhs and rhs).
122  // For example, suppose that the two input vectors are <s1, s2, s3> and <l1,
123  // l2, l3>.
124  // Then this vector stores <s1 < l1, s1 == l1 && s2 < l2, s1 == l1 &&
125  // s2 == l2 && s3 < l3>.
126  exprt::operandst lexicographic_individual_comparisons(lhs.size());
127  lexicographic_individual_comparisons[0] =
128  binary_relation_exprt(lhs[0], ID_lt, rhs[0]);
129  for(size_t i = 1; i < lexicographic_individual_comparisons.size(); i++)
130  {
131  binary_relation_exprt component_i_less_than{lhs[i], ID_lt, rhs[i]};
132  lexicographic_individual_comparisons[i] =
133  and_exprt(equality_conjunctions[i - 1], component_i_less_than);
134  }
135  return disjunction(lexicographic_individual_comparisons);
136 }
137 
139  goto_programt &destination,
140  goto_programt::targett &target,
141  goto_programt &payload)
142 {
143  const auto offset = payload.instructions.size();
144  destination.insert_before_swap(target, payload);
145  std::advance(target, offset);
146 }
147 
149  const typet &type,
150  const source_locationt &location,
151  const irep_idt &mode,
152  symbol_table_baset &symtab,
153  std::string suffix,
154  bool is_auxiliary)
155 {
156  symbolt &new_symbol = get_fresh_aux_symbol(
157  type, id2string(location.get_function()), suffix, location, mode, symtab);
158  new_symbol.is_auxiliary = is_auxiliary;
159  return new_symbol;
160 }
161 
162 void simplify_gotos(goto_programt &goto_program, namespacet &ns)
163 {
164  for(auto &instruction : goto_program.instructions)
165  {
166  if(
167  instruction.is_goto() &&
168  simplify_expr(instruction.condition(), ns).is_false())
169  instruction.turn_into_skip();
170  }
171 }
172 
174  const goto_programt &goto_program,
175  namespacet &ns,
176  messaget &log)
177 {
178  // create cfg from instruction list
180  cfg(goto_program);
181 
182  // check that all nodes are there
183  INVARIANT(
184  goto_program.instructions.size() == cfg.size(),
185  "Instruction list vs CFG size mismatch.");
186 
187  // compute SCCs
189  std::vector<idxt> node_to_scc(cfg.size(), -1);
190  auto nof_sccs = cfg.SCCs(node_to_scc);
191 
192  // compute size of each SCC
193  std::vector<int> scc_size(nof_sccs, 0);
194  for(auto scc : node_to_scc)
195  {
196  INVARIANT(
197  0 <= scc && scc < nof_sccs, "Could not determine SCC for instruction");
198  scc_size[scc]++;
199  }
200 
201  // check they are all of size 1
202  for(size_t scc_id = 0; scc_id < nof_sccs; scc_id++)
203  {
204  auto size = scc_size[scc_id];
205  if(size > 1)
206  {
207  log.conditional_output(
208  log.error(),
209  [&cfg, &node_to_scc, &scc_id, &size](messaget::mstreamt &mstream) {
210  mstream << "Found CFG SCC with size " << size << messaget::eom;
211  for(const auto &node_id : node_to_scc)
212  {
213  if(node_to_scc[node_id] == scc_id)
214  {
215  const auto &pc = cfg[node_id].PC;
216  pc->output(mstream);
217  mstream << messaget::eom;
218  }
219  }
220  });
221  return false;
222  }
223  }
224  return true;
225 }
226 
229  " (assigned by the contract of ";
230 
232  const exprt &target,
233  const irep_idt &function_id,
234  const namespacet &ns)
235 {
236  return from_expr(ns, target.id(), target) +
237  ASSIGNS_CLAUSE_REPLACEMENT_TRACKING + id2string(function_id) + ")";
238 }
239 
241 {
243  std::string::npos;
244 }
messaget
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
all_dereferences_are_valid
exprt all_dereferences_are_valid(const exprt &expr, const namespacet &ns)
Generate a validity check over all dereferences in an expression.
Definition: utils.cpp:80
source_locationt::get_function
const irep_idt & get_function() const
Definition: source_location.h:55
cfg.h
grapht::size
std::size_t size() const
Definition: graph.h:212
insert_before_swap_and_advance
void insert_before_swap_and_advance(goto_programt &destination, goto_programt::targett &target, goto_programt &payload)
Insert a goto program before a target instruction iterator and advance the iterator.
Definition: utils.cpp:138
conjunction
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:62
good_pointer_def
exprt good_pointer_def(const exprt &pointer, const namespacet &ns)
Definition: pointer_predicates.cpp:64
to_dereference_expr
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:716
typet
The type of an expression, extends irept.
Definition: type.h:28
generate_lexicographic_less_than_check
exprt generate_lexicographic_less_than_check(const std::vector< symbol_exprt > &lhs, const std::vector< symbol_exprt > &rhs)
Generate a lexicographic less-than comparison over ordered tuples.
Definition: utils.cpp:94
fresh_symbol.h
make_assigns_clause_replacement_tracking_comment
irep_idt make_assigns_clause_replacement_tracking_comment(const exprt &target, const irep_idt &function_id, const namespacet &ns)
Returns an irep_idt that essentially says that target was assigned by the contract of function_id.
Definition: utils.cpp:231
pointer_predicates.h
and_exprt
Boolean AND.
Definition: std_expr.h:2070
havoc_utilst::append_scalar_havoc_code_for_expr
virtual void append_scalar_havoc_code_for_expr(const source_locationt location, const exprt &expr, goto_programt &dest) const
Append goto instructions to havoc the value of expr
Definition: havoc_utils.cpp:57
goto_programt::add
targett add(instructiont &&instruction)
Adds a given instruction at the end.
Definition: goto_program.h:709
exprt
Base class for all expressions.
Definition: expr.h:55
havoc_utilst::append_havoc_code_for_expr
virtual void append_havoc_code_for_expr(const source_locationt location, const exprt &expr, goto_programt &dest) const
Append goto instructions to havoc a single expression expr
Definition: havoc_utils.cpp:29
is_assigns_clause_replacement_tracking_comment
bool is_assigns_clause_replacement_tracking_comment(const irep_idt &comment)
Returns true if the given comment matches the type of comments created by make_assigns_clause_replace...
Definition: utils.cpp:240
goto_programt::make_goto
static instructiont make_goto(targett _target, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:1030
exprt::is_false
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:43
append_safe_havoc_code_for_expr
static void append_safe_havoc_code_for_expr(const source_locationt location, const namespacet &ns, const exprt &expr, goto_programt &dest, const std::function< void()> &havoc_code_impl)
Definition: utils.cpp:24
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
to_pointer_object_expr
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
Definition: pointer_expr.h:986
disjunction
exprt disjunction(const exprt::operandst &op)
1) generates a disjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:50
utils.h
messaget::error
mstreamt & error() const
Definition: message.h:399
simplify_gotos
void simplify_gotos(goto_programt &goto_program, namespacet &ns)
Turns goto instructions IF cond GOTO label where the condition statically simplifies to false into SK...
Definition: utils.cpp:162
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
havoc_if_validt::append_object_havoc_code_for_expr
void append_object_havoc_code_for_expr(const source_locationt location, const exprt &expr, goto_programt &dest) const override
Append goto instructions to havoc the underlying object of expr
Definition: utils.cpp:45
goto_programt::make_skip
static instructiont make_skip(const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:882
language_util.h
havoc_if_validt::ns
const namespacet & ns
Definition: utils.h:52
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
symbol_table_baset
The symbol table base class interface.
Definition: symbol_table_base.h:21
havoc_utilst::append_object_havoc_code_for_expr
virtual void append_object_havoc_code_for_expr(const source_locationt location, const exprt &expr, goto_programt &dest) const
Append goto instructions to havoc the underlying object of expr
Definition: havoc_utils.cpp:46
pointer_expr.h
simplify_expr
exprt simplify_expr(exprt src, const namespacet &ns)
Definition: simplify_expr.cpp:2931
irept::id
const irep_idt & id() const
Definition: irep.h:396
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
havoc_if_validt::append_scalar_havoc_code_for_expr
void append_scalar_havoc_code_for_expr(const source_locationt location, const exprt &expr, goto_programt &dest) const override
Append goto instructions to havoc the value of expr
Definition: utils.cpp:55
goto_programt::destructive_append
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
Definition: goto_program.h:692
grapht::SCCs
std::size_t SCCs(std::vector< node_indext > &subgraph_nr) const
Computes strongly-connected components of a graph and yields a vector expressing a mapping from nodes...
Definition: graph.h:832
source_locationt
Definition: source_location.h:18
simplify_expr.h
cfg_baset< empty_cfg_nodet >
goto_programt::instructions
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:592
is_loop_free
bool is_loop_free(const goto_programt &goto_program, namespacet &ns, messaget &log)
Returns true iff the given program is loop-free, i.e.
Definition: utils.cpp:173
graph.h
symbolt
Symbol table entry.
Definition: symbol.h:27
binary_relation_exprt
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:706
messaget::conditional_output
void conditional_output(mstreamt &mstream, const std::function< void(mstreamt &)> &output_generator) const
Generate output to message_stream using output_generator if the configured verbosity is at least as h...
Definition: message.cpp:139
symbolt::is_auxiliary
bool is_auxiliary
Definition: symbol.h:67
goto_programt
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:72
havoc_assigns_targetst::append_havoc_code_for_expr
void append_havoc_code_for_expr(const source_locationt location, const exprt &expr, goto_programt &dest) const override
Append goto instructions to havoc a single expression expr
Definition: utils.cpp:65
messaget::mstreamt
Definition: message.h:223
new_tmp_symbol
const symbolt & new_tmp_symbol(const typet &type, const source_locationt &location, const irep_idt &mode, symbol_table_baset &symtab, std::string suffix, bool is_auxiliary)
Adds a fresh and uniquely named symbol to the symbol table.
Definition: utils.cpp:148
exprt::operands
operandst & operands()
Definition: expr.h:94
graph_nodet::node_indext
std::size_t node_indext
Definition: graph.h:37
INVARIANT
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
goto_programt::insert_before_swap
void insert_before_swap(targett target)
Insertion that preserves jumps to "target".
Definition: goto_program.h:613
ASSIGNS_CLAUSE_REPLACEMENT_TRACKING
static const char ASSIGNS_CLAUSE_REPLACEMENT_TRACKING[]
Prefix for comments added to track assigns clause replacement.
Definition: utils.cpp:228
message.h
comment
static std::string comment(const rw_set_baset::entryt &entry, bool write)
Definition: race_check.cpp:109
from_expr
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
Definition: language_util.cpp:38
get_fresh_aux_symbol
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Definition: fresh_symbol.cpp:32
goto_programt::targett
instructionst::iterator targett
Definition: goto_program.h:586
not_exprt
Boolean negation.
Definition: std_expr.h:2277