CBMC
shadow_memory.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Symex Shadow Memory Instrumentation
4 
5 Author: Peter Schrammel
6 
7 \*******************************************************************/
8 
11 
12 #include "shadow_memory.h"
13 
14 #include <util/bitvector_types.h>
15 #include <util/expr_initializer.h>
16 #include <util/format_expr.h>
17 #include <util/format_type.h>
18 #include <util/fresh_symbol.h>
19 #include <util/pointer_expr.h>
20 #include <util/string_constant.h>
21 
22 #include <langapi/language_util.h>
24 
25 #include "goto_symex_state.h"
26 #include "shadow_memory_util.h"
27 
29  goto_symex_statet &state,
30  exprt expr,
32 {
33  typet type = ns.follow(expr.type());
34  clean_pointer_expr(expr, type);
35  for(const auto &field_pair : fields)
36  {
37  const symbol_exprt &shadow = add_field(state, expr, field_pair.first, type);
38 
39  if(
40  field_pair.second.id() == ID_typecast &&
41  to_typecast_expr(field_pair.second).op().is_zero())
42  {
43  const auto zero_value =
44  zero_initializer(type, expr.source_location(), ns);
45  CHECK_RETURN(zero_value.has_value());
46 
47  symex_assign(state, shadow, *zero_value);
48  }
49  else
50  {
51  exprt init_expr = field_pair.second;
52  const auto init_value =
53  expr_initializer(type, expr.source_location(), ns, init_expr);
54  CHECK_RETURN(init_value.has_value());
55 
56  symex_assign(state, shadow, *init_value);
57  }
58 
59  log.debug() << "Shadow memory: initialize field "
60  << id2string(shadow.get_identifier()) << " for " << format(expr)
61  << " with initial value " << format(field_pair.second)
62  << messaget::eom;
63  }
64 }
65 
67  goto_symex_statet &state,
68  const exprt &expr,
69  const irep_idt &field_name,
70  const typet &field_type)
71 {
72  const auto &function_symbol = ns.lookup(state.source.function_id);
73  const symbolt &new_symbol = get_fresh_aux_symbol(
74  field_type,
76  SHADOW_MEMORY_PREFIX + from_expr(expr) + "__" + id2string(field_name),
77  state.source.pc->source_location(),
78  function_symbol.mode,
79  state.symbol_table);
80 
81  auto &addresses = state.shadow_memory.address_fields[field_name];
82  addresses.push_back(
84 
85  return addresses.back().shadow;
86 }
87 
89  goto_symex_statet &state,
90  const exprt::operandst &arguments)
91 {
92  // parse set_field call
93  INVARIANT(
94  arguments.size() == 3, CPROVER_PREFIX "set_field requires 3 arguments");
95  irep_idt field_name = extract_field_name(arguments[1]);
96 
97  exprt expr = arguments[0];
98  typet expr_type = expr.type();
100  expr_type.id() == ID_pointer,
101  "shadow memory requires a pointer expression",
102  irep_pretty_diagnosticst{expr_type});
103 
104  exprt value = arguments[2];
105  shadow_memory_log_set_field(ns, log, field_name, expr, value);
106  INVARIANT(
107  state.shadow_memory.address_fields.count(field_name) == 1,
108  id2string(field_name) + " should exist");
109  const auto &addresses = state.shadow_memory.address_fields.at(field_name);
110 
111  // get value set
113 
114  shadow_memory_log_set_field(ns, log, field_name, expr, value);
115 
116  std::vector<exprt> value_set = state.value_set.get_value_set(expr, ns);
117  shadow_memory_log_value_set(ns, log, value_set);
118  if(check_value_set_contains_only_null_ptr(ns, log, value_set, expr))
119  {
120  log.warning() << "Shadow memory: cannot set shadow memory of NULL"
121  << messaget::eom;
122  return;
123  }
124 
125  // build lhs
126  const exprt &rhs = value;
127  size_t mux_size = 0;
128  std::optional<exprt> maybe_lhs =
129  get_shadow_memory(expr, value_set, addresses, ns, log, mux_size);
130 
131  // add to equation
132  if(maybe_lhs.has_value())
133  {
134  if(mux_size >= 10)
135  {
136  log.warning() << "Shadow memory: mux size set_field: " << mux_size
137  << messaget::eom;
138  }
139  else
140  {
141  log.debug() << "Shadow memory: mux size set_field: " << mux_size
142  << messaget::eom;
143  }
144  const exprt lhs = deref_expr(*maybe_lhs);
145 
146  shadow_memory_log_text_and_expr(ns, log, "LHS", lhs);
147 
148  if(lhs.type().id() == ID_empty)
149  {
150  std::stringstream s;
151  s << "Shadow memory: cannot set shadow memory via type void* for "
152  << format(expr)
153  << ". Insert a cast to the type that you want to access.";
154  throw invalid_input_exceptiont(s.str());
155  }
156 
157  // Get the type of the shadow memory for this field
158  const typet &sm_field_type = get_field_init_type(field_name, state);
159  // Add a conditional cast to the shadow memory field type if `rhs` is not of
160  // the expected type
161  const exprt casted_rhs =
162  typecast_exprt::conditional_cast(rhs, sm_field_type);
163  // We replicate the rhs value on each byte of the value that we set.
164  // This allows the get_field or/max semantics to operate correctly
165  // on unions.
166  const auto per_byte_rhs =
167  expr_initializer(lhs.type(), expr.source_location(), ns, casted_rhs);
168  CHECK_RETURN(per_byte_rhs.has_value());
169 
170  shadow_memory_log_text_and_expr(ns, log, "RHS", per_byte_rhs.value());
171  symex_assign(
172  state,
173  lhs,
174  typecast_exprt::conditional_cast(per_byte_rhs.value(), lhs.type()));
175  }
176  else
177  {
178  log.warning() << "Shadow memory: cannot set_field for " << format(expr)
179  << messaget::eom;
180  }
181 }
182 
183 // Function synopsis
184 // value_set = get_value_set(expr)
185 // foreach object in value_set:
186 // if(object invalid) continue;
187 // get_field(&exact_match)
188 // if(exact_match)
189 // return;
190 // return;
192  goto_symex_statet &state,
193  const exprt &lhs,
194  const exprt::operandst &arguments)
195 {
196  INVARIANT(
197  arguments.size() == 2, CPROVER_PREFIX "get_field requires 2 arguments");
198  irep_idt field_name = extract_field_name(arguments[1]);
199 
200  exprt expr = arguments[0];
201  typet expr_type = expr.type();
203  expr_type.id() == ID_pointer,
204  "shadow memory requires a pointer expression");
205  shadow_memory_log_get_field(ns, log, field_name, expr);
206 
207  INVARIANT(
208  state.shadow_memory.address_fields.count(field_name) == 1,
209  id2string(field_name) + " should exist");
210  const auto &addresses = state.shadow_memory.address_fields.at(field_name);
211 
212  // Return null (invalid object) instead of auto-object or invalid-object.
213  // This will "polish" expr from invalid and auto-obj
215 
216  std::vector<exprt> value_set = state.value_set.get_value_set(expr, ns);
217  shadow_memory_log_value_set(ns, log, value_set);
218 
219  std::vector<std::pair<exprt, exprt>> rhs_conds_values;
220  const null_pointer_exprt null_pointer(to_pointer_type(expr.type()));
221  // Used to give a default value for invalid pointers and other usages
222  const exprt &field_init_expr = get_field_init_expr(field_name, state);
223 
224  if(contains_null_or_invalid(value_set, null_pointer))
225  {
226  shadow_memory_log_value_set_match(ns, log, null_pointer, expr);
227  // If we have an invalid pointer, then return the default value of the
228  // shadow memory as dereferencing it would fail
229  rhs_conds_values.emplace_back(
230  true_exprt(),
231  typecast_exprt::conditional_cast(field_init_expr, lhs.type()));
232  }
233 
234  for(const auto &matched_object : value_set)
235  {
236  // Ignore "unknown"
237  if(matched_object.id() != ID_object_descriptor)
238  {
239  log.warning() << "Shadow memory: value set contains unknown for "
240  << format(expr) << messaget::eom;
241  continue;
242  }
243  // Ignore "integer_address"
244  if(
245  to_object_descriptor_expr(matched_object).root_object().id() ==
246  ID_integer_address)
247  {
248  log.warning() << "Shadow memory: value set contains integer_address for "
249  << format(expr) << messaget::eom;
250  continue;
251  }
252  // Ignore "ID_C_is_failed_symbol" (another incarnation of invalid pointer)
253  // TODO: check if this is obsolete (or removed by
254  // replace_invalid_object_by_null) or add default value
255  if(matched_object.type().get_bool(ID_C_is_failed_symbol))
256  {
257  log.warning() << "Shadow memory: value set contains failed symbol for "
258  << format(expr) << messaget::eom;
259  continue;
260  }
261 
262  bool exact_match = false;
263 
264  // List of condition ==> value (read condition implies values)
265  auto per_matched_object_conds_values = get_shadow_dereference_candidates(
266  ns,
267  log,
268  matched_object,
269  addresses,
270  field_init_expr.type(),
271  expr,
272  lhs.type(),
273  exact_match);
274 
275  // If we have an exact match we discard all the previous conditions and
276  // create an assignment. Then we'll break
277  if(exact_match)
278  {
279  rhs_conds_values.clear();
280  }
281  // Process this match (exact will contain only one set of conditions).
282  rhs_conds_values.insert(
283  rhs_conds_values.end(),
284  per_matched_object_conds_values.begin(),
285  per_matched_object_conds_values.end());
286  if(exact_match)
287  {
288  break;
289  }
290  }
291 
292  // If we have at least a condition ==> value
293  if(!rhs_conds_values.empty())
294  {
295  // Build the rhs expression from the shadow memory (big switch for all
296  // condition ==> value)
298  build_if_else_expr(rhs_conds_values), lhs.type());
299  const size_t mux_size = rhs_conds_values.size() - 1;
300  // Don't debug if the switch is too big
301  if(mux_size >= 10)
302  {
303  log.warning() << "Shadow memory: mux size get_field: " << mux_size
304  << messaget::eom;
305  }
306  else
307  {
308  log.debug() << "Shadow memory: mux size get_field: " << mux_size
309  << messaget::eom;
310  }
311 
312  shadow_memory_log_text_and_expr(ns, log, "RHS", rhs);
313 
314  // create the assignment of __CPROVER_shadow_memory_get_field
315  symex_assign(state, lhs, typecast_exprt::conditional_cast(rhs, lhs.type()));
316  }
317  else
318  {
319  // We don't have any condition ==> value for the pointer, so we fall-back to
320  // the initialization value of the shadow-memory.
321  log.warning() << "Shadow memory: cannot get_field for " << format(expr)
322  << messaget::eom;
323  symex_assign(
324  state,
325  lhs,
326  typecast_exprt::conditional_cast(field_init_expr, lhs.type()));
327  }
328 }
329 
330 // TODO: the following 4 functions (`symex_field_static_init`,
331 // `symex_field_static_init_string_constant`,
332 // `symex_field_local_init`,
333 // `symex_field_dynamic_init`) do filtering on
334 // the input symbol name and then call `initialize_shadow_memory` accordingly.
335 // We want to refactor and improve the way the filtering is done, but given
336 // that we don't have an easy mechanism to validate that we haven't changed the
337 // behaviour, we want to postpone changing this until the full shadow memory
338 // functionalities are integrated and we have good regression/unit testing.
339 
341  goto_symex_statet &state,
342  const ssa_exprt &lhs)
343 {
344  if(lhs.get_original_expr().id() != ID_symbol)
345  return;
346 
347  const irep_idt &identifier =
349 
351  return;
352 
353  if(
354  identifier.starts_with(CPROVER_PREFIX) &&
355  !identifier.starts_with(CPROVER_PREFIX "errno"))
356  {
357  return;
358  }
359 
360  const symbolt &symbol = ns.lookup(identifier);
361 
362  if(
363  (id2string(symbol.name).find("::return_value") == std::string::npos &&
364  symbol.is_auxiliary) ||
365  !symbol.is_static_lifetime)
366  return;
367  if(id2string(symbol.name).find("__cs_") != std::string::npos)
368  return;
369 
370  const typet &type = symbol.type;
371  log.debug() << "Shadow memory: global memory " << id2string(identifier)
372  << " of type " << from_type(ns, "", type) << messaget::eom;
373 
375  state, lhs, state.shadow_memory.fields.global_fields);
376 }
377 
379  goto_symex_statet &state,
380  const ssa_exprt &expr,
381  const exprt &rhs)
382 {
383  if(
384  expr.get_original_expr().id() == ID_symbol &&
386  .get_identifier()
388  {
389  return;
390  }
391  const index_exprt &index_expr =
392  to_index_expr(to_address_of_expr(rhs).object());
393 
394  const typet &type = index_expr.array().type();
395  log.debug() << "Shadow memory: global memory "
396  << id2string(to_string_constant(index_expr.array()).value())
397  << " of type " << from_type(ns, "", type) << messaget::eom;
398 
400  state, index_expr.array(), state.shadow_memory.fields.global_fields);
401 }
402 
404  goto_symex_statet &state,
405  const ssa_exprt &expr)
406 {
407  const symbolt &symbol =
409 
410  const std::string symbol_name = id2string(symbol.name);
411  if(
412  symbol.is_auxiliary &&
413  symbol_name.find("::return_value") == std::string::npos)
414  return;
415  if(
416  symbol_name.find("malloc::") != std::string::npos &&
417  (symbol_name.find("malloc_size") != std::string::npos ||
418  symbol_name.find("malloc_res") != std::string::npos ||
419  symbol_name.find("record_malloc") != std::string::npos ||
420  symbol_name.find("record_may_leak") != std::string::npos))
421  {
422  return;
423  }
424  if(
425  symbol_name.find("__builtin_alloca::") != std::string::npos &&
426  (symbol_name.find("alloca_size") != std::string::npos ||
427  symbol_name.find("record_malloc") != std::string::npos ||
428  symbol_name.find("record_alloca") != std::string::npos ||
429  symbol_name.find("res") != std::string::npos))
430  {
431  return;
432  }
433  if(symbol_name.find("__cs_") != std::string::npos)
434  return;
435 
436  const typet &type = expr.type();
437  ssa_exprt expr_l1 = remove_level_2(expr);
438  log.debug() << "Shadow memory: local memory "
439  << id2string(expr_l1.get_identifier()) << " of type "
440  << from_type(ns, "", type) << messaget::eom;
441 
443  state, expr_l1, state.shadow_memory.fields.local_fields);
444 }
445 
447  goto_symex_statet &state,
448  const exprt &expr,
449  const side_effect_exprt &code)
450 {
451  log.debug() << "Shadow memory: dynamic memory of type "
452  << from_type(ns, "", expr.type()) << messaget::eom;
453 
455  state, expr, state.shadow_memory.fields.global_fields);
456 }
457 
459  const abstract_goto_modelt &goto_model,
460  message_handlert &message_handler)
461 {
462  shadow_memory_field_definitionst field_definitions;
463 
464  // Gather shadow memory declarations from goto model
465  for(const auto &goto_function : goto_model.get_goto_functions().function_map)
466  {
467  const auto &goto_program = goto_function.second.body;
468  forall_goto_program_instructions(target, goto_program)
469  {
470  if(!target->is_function_call())
471  continue;
472 
473  const auto &code_function_call = to_code_function_call(target->code());
474  const exprt &function = code_function_call.function();
475 
476  if(function.id() != ID_symbol)
477  continue;
478 
479  const irep_idt &identifier = to_symbol_expr(function).get_identifier();
480 
481  if(
482  identifier ==
484  {
486  code_function_call,
487  field_definitions.global_fields,
488  true,
489  message_handler);
490  }
491  else if(
492  identifier ==
494  {
496  code_function_call,
497  field_definitions.local_fields,
498  false,
499  message_handler);
500  }
501  }
502  }
503  return field_definitions;
504 }
505 
507  const code_function_callt &code_function_call,
509  bool is_global,
510  message_handlert &message_handler)
511 {
512  INVARIANT(
513  code_function_call.arguments().size() == 2,
516  " requires 2 arguments");
517  irep_idt field_name = extract_field_name(code_function_call.arguments()[0]);
518 
519  exprt expr = code_function_call.arguments()[1];
520 
521  messaget log(message_handler);
522  log.debug() << "Shadow memory: declare " << (is_global ? "global " : "local ")
523  << "field " << id2string(field_name) << " of type "
524  << format(expr.type()) << messaget::eom;
526  {
528  "A shadow memory field must be of a bitvector type.");
529  }
530  if(to_bitvector_type(expr.type()).get_width() > 8)
531  {
533  "A shadow memory field must not be larger than 8 bits.");
534  }
535 
536  // record the field's initial value (and type)
537  fields[field_name] = expr;
538 }
Pre-defined bitvector types.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
Abstract interface to eager or lazy GOTO models.
virtual const goto_functionst & get_goto_functions() const =0
Accessor to get a raw goto_functionst.
std::size_t get_width() const
Definition: std_types.h:920
goto_instruction_codet representation of a function call statement.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool starts_with(const char *s) const
equivalent of as_string().starts_with(s)
Definition: dstring.h:95
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
const source_locationt & source_location() const
Definition: expr.h:231
bool is_zero() const
Return whether the expression is a constant representing 0.
Definition: expr.cpp:47
typet & type()
Return the type of the expression.
Definition: expr.h:84
function_mapt function_map
value_sett value_set
Uses level 1 names, and is used to do dereferencing.
Definition: goto_state.h:51
Central data structure: state.
shadow_memory_statet shadow_memory
symbol_tablet symbol_table
contains symbols that are minted during symbolic execution, such as dynamically created objects etc.
symex_targett::sourcet source
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
Thrown when user-provided input cannot be processed.
const irep_idt & id() const
Definition: irep.h:384
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
mstreamt & warning() const
Definition: message.h:404
mstreamt & debug() const
Definition: message.h:429
static eomt eom
Definition: message.h:297
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
The null pointer constant.
Definition: pointer_expr.h:909
The shadow memory field definitions.
field_definitiont global_fields
Field definitions for global-scope fields.
field_definitiont local_fields
Field definitions for local-scope fields.
std::map< irep_idt, exprt > field_definitiont
A field definition mapping a field name to its initial value.
shadow_memory_field_definitionst fields
The available shadow memory field definitions.
std::map< irep_idt, std::vector< shadowed_addresst > > address_fields
const symbol_exprt & add_field(goto_symex_statet &state, const exprt &expr, const irep_idt &field_name, const typet &field_type)
Registers a shadow memory field for the given original memory.
void symex_get_field(goto_symex_statet &state, const exprt &lhs, const exprt::operandst &arguments)
Symbolically executes a __CPROVER_get_field call.
static void convert_field_declaration(const code_function_callt &code_function_call, shadow_memory_field_definitionst::field_definitiont &fields, bool is_global, message_handlert &message_handler)
Converts a field declaration.
void symex_field_dynamic_init(goto_symex_statet &state, const exprt &expr, const side_effect_exprt &code)
Initialize global-scope shadow memory for dynamically allocated memory.
void symex_field_static_init(goto_symex_statet &state, const ssa_exprt &lhs)
Initialize global-scope shadow memory for global/static variables.
const std::function< void(goto_symex_statet &, const exprt &, const exprt)> symex_assign
void symex_field_static_init_string_constant(goto_symex_statet &state, const ssa_exprt &expr, const exprt &rhs)
Initialize global-scope shadow memory for string constants.
const namespacet & ns
static shadow_memory_field_definitionst gather_field_declarations(const abstract_goto_modelt &goto_model, message_handlert &message_handler)
Gathers the available shadow memory field definitions (__CPROVER_field_decl calls) from the goto mode...
void symex_field_local_init(goto_symex_statet &state, const ssa_exprt &expr)
Initialize local-scope shadow memory for local variables and parameters.
void initialize_shadow_memory(goto_symex_statet &state, exprt expr, const shadow_memory_field_definitionst::field_definitiont &fields)
Allocates and initializes a shadow memory field for the given original memory.
void symex_set_field(goto_symex_statet &state, const exprt::operandst &arguments)
Symbolically executes a __CPROVER_set_field call.
An expression containing a side effect.
Definition: std_code.h:1450
Expression providing an SSA-renamed symbol of expressions.
Definition: ssa_expr.h:17
const exprt & get_original_expr() const
Definition: ssa_expr.h:33
void value(const irep_idt &)
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
Symbol table entry.
Definition: symbol.h:28
bool is_auxiliary
Definition: symbol.h:77
bool is_static_lifetime
Definition: symbol.h:70
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
typet type
Type of symbol.
Definition: symbol.h:31
irep_idt name
The unique identifier.
Definition: symbol.h:40
The Boolean constant true.
Definition: std_expr.h:3055
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2076
The type of an expression, extends irept.
Definition: type.h:29
const exprt & op() const
Definition: std_expr.h:391
Thrown when we encounter an instruction, parameters to an instruction etc.
std::vector< exprt > get_value_set(exprt expr, const namespacet &ns) const
Gets values pointed to by expr, including following dereference operators (i.e.
Definition: value_set.cpp:391
#define CPROVER_PREFIX
std::optional< exprt > zero_initializer(const typet &type, const source_locationt &source_location, const namespacet &ns)
Create the equivalent of zero for type type.
std::optional< exprt > expr_initializer(const typet &type, const source_locationt &source_location, const namespacet &ns, const exprt &init_byte_expr)
Create a value for type type, with all subtype bytes initialized to the given value.
Expression Initialization.
static format_containert< T > format(const T &o)
Definition: format.h:37
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 ...
Fresh auxiliary symbol creation.
const code_function_callt & to_code_function_call(const goto_instruction_codet &code)
#define forall_goto_program_instructions(it, program)
Symbolic Execution.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
std::string from_type(const namespacet &ns, const irep_idt &identifier, const typet &type)
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const object_descriptor_exprt & to_object_descriptor_expr(const exprt &expr)
Cast an exprt to an object_descriptor_exprt.
Definition: pointer_expr.h:252
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
Symex Shadow Memory Instrumentation.
#define SHADOW_MEMORY_GLOBAL_SCOPE
Definition: shadow_memory.h:22
#define SHADOW_MEMORY_LOCAL_SCOPE
Definition: shadow_memory.h:23
#define SHADOW_MEMORY_PREFIX
Definition: shadow_memory.h:20
#define SHADOW_MEMORY_FIELD_DECL
Definition: shadow_memory.h:21
exprt build_if_else_expr(const std::vector< std::pair< exprt, exprt >> &conds_values)
Build an if-then-else chain from a vector containing pairs of expressions.
void replace_invalid_object_by_null(exprt &expr)
Replace an invalid object by a null pointer.
void shadow_memory_log_value_set_match(const namespacet &ns, const messaget &log, const exprt &address, const exprt &expr)
Logs a successful match between an address and a value within the value set.
exprt deref_expr(const exprt &expr)
Wraps a given expression into a dereference_exprt unless it is an address_of_exprt in which case it j...
bool contains_null_or_invalid(const std::vector< exprt > &value_set, const exprt &address)
Given a pointer expression check to see if it can be a null pointer or an invalid object within value...
bool check_value_set_contains_only_null_ptr(const namespacet &ns, const messaget &log, const std::vector< exprt > &value_set, const exprt &expr)
Checks if value_set contains only a NULL pointer expression of the same type of expr.
void shadow_memory_log_set_field(const namespacet &ns, const messaget &log, const irep_idt &field_name, const exprt &expr, const exprt &value)
Logs setting a value to a given shadow field.
const typet & get_field_init_type(const irep_idt &field_name, const goto_symex_statet &state)
Retrieves the type of the shadow memory by returning the type of the shadow memory initializer value.
const exprt & get_field_init_expr(const irep_idt &field_name, const goto_symex_statet &state)
Retrieve the expression that a field was initialised with within a given symex state.
std::vector< std::pair< exprt, exprt > > get_shadow_dereference_candidates(const namespacet &ns, const messaget &log, const exprt &matched_object, const std::vector< shadow_memory_statet::shadowed_addresst > &addresses, const typet &field_type, const exprt &expr, const typet &lhs_type, bool &exact_match)
Get a list of (condition, value) pairs for a certain pointer from the shadow memory,...
void shadow_memory_log_get_field(const namespacet &ns, const messaget &log, const irep_idt &field_name, const exprt &expr)
Logs getting a value corresponding to a shadow memory field.
irep_idt extract_field_name(const exprt &string_expr)
Extracts the field name identifier from a string expression, e.g.
void shadow_memory_log_value_set(const namespacet &ns, const messaget &log, const std::vector< exprt > &value_set)
Logs the retrieval of the value associated with a given shadow memory field.
void clean_pointer_expr(exprt &expr, const typet &type)
Clean the given pointer expression so that it has the right shape for being used for identifying shad...
void shadow_memory_log_text_and_expr(const namespacet &ns, const messaget &log, const char *text, const exprt &expr)
Generic logging function that will log depending on the configured verbosity.
std::optional< exprt > get_shadow_memory(const exprt &expr, const std::vector< exprt > &value_set, const std::vector< shadow_memory_statet::shadowed_addresst > &addresses, const namespacet &ns, const messaget &log, size_t &mux_size)
Get shadow memory values for a given expression within a specified value set.
Symex Shadow Memory Instrumentation Utilities.
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define DATA_INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
Definition: invariant.h:535
ssa_exprt remove_level_2(ssa_exprt ssa)
#define INITIALIZE_FUNCTION
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
bool can_cast_type< bitvector_typet >(const typet &type)
Check whether a reference to a typet is a bitvector_typet.
Definition: std_types.h:943
const string_constantt & to_string_constant(const exprt &expr)
goto_programt::const_targett pc
Definition: symex_target.h:42