CBMC
nondet_volatile.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Volatile Variables
4 
5 Author: Daniel Kroening
6 
7 Date: September 2011
8 
9 \*******************************************************************/
10 
13 
14 #include "nondet_volatile.h"
15 
16 #include <util/c_types.h>
17 #include <util/cmdline.h>
18 #include <util/fresh_symbol.h>
19 #include <util/options.h>
20 #include <util/pointer_expr.h>
21 #include <util/std_code.h>
22 #include <util/std_expr.h>
23 #include <util/string_utils.h>
24 
26 
28 {
29 public:
32  {
33  typecheck_options(options);
34  }
35 
36  void operator()()
37  {
38  if(!all_nondet && nondet_variables.empty() && variable_models.empty())
39  {
40  return;
41  }
42 
44  {
45  nondet_volatile(goto_model.symbol_table, f.second.body);
46  }
47 
49  }
50 
51 private:
52  static bool is_volatile(const namespacet &ns, const typet &src);
53 
55  exprt &expr,
56  const namespacet &ns,
57  goto_programt &pre,
58  goto_programt &post);
59 
61  const symbol_table_baset &symbol_table,
62  exprt &expr,
63  goto_programt &pre,
64  goto_programt &post);
65 
67  const symbol_table_baset &symbol_table,
68  exprt &expr,
69  goto_programt &pre,
70  goto_programt &post);
71 
72  void nondet_volatile(
73  symbol_table_baset &symbol_table,
74  goto_programt &goto_program);
75 
76  const symbolt &typecheck_variable(const irep_idt &id, const namespacet &ns);
77 
78  void typecheck_model(
79  const irep_idt &id,
80  const symbolt &variable,
81  const namespacet &ns);
82 
83  void typecheck_options(const optionst &options);
84 
86 
87  // configuration obtained from command line options
88  bool all_nondet;
89  std::set<irep_idt> nondet_variables;
90  std::map<irep_idt, irep_idt> variable_models;
91 };
92 
93 bool nondet_volatilet::is_volatile(const namespacet &ns, const typet &src)
94 {
95  if(src.get_bool(ID_C_volatile))
96  return true;
97 
98  if(auto struct_tag = type_try_dynamic_cast<struct_tag_typet>(src))
99  return is_volatile(ns, ns.follow_tag(*struct_tag));
100  else if(auto union_tag = type_try_dynamic_cast<union_tag_typet>(src))
101  return is_volatile(ns, ns.follow_tag(*union_tag));
102  else if(auto enum_tag = type_try_dynamic_cast<c_enum_tag_typet>(src))
103  return is_volatile(ns, ns.follow_tag(*enum_tag));
104  else
105  return false;
106 }
107 
109  exprt &expr,
110  const namespacet &ns,
111  goto_programt &pre,
112  goto_programt &post)
113 {
114  // Check if we should replace the variable by a nondet expression
115  if(
116  all_nondet ||
117  (expr.id() == ID_symbol &&
118  nondet_variables.count(to_symbol_expr(expr).get_identifier()) != 0))
119  {
120  typet t = expr.type();
121  t.remove(ID_C_volatile);
122 
123  side_effect_expr_nondett nondet_expr(t, expr.source_location());
124  expr.swap(nondet_expr);
125 
126  return;
127  }
128 
129  // Now check if we should replace the variable by a model
130 
131  if(expr.id() != ID_symbol)
132  {
133  return;
134  }
135 
136  const irep_idt &id = to_symbol_expr(expr).get_identifier();
137  const auto &it = variable_models.find(id);
138 
139  if(it == variable_models.end())
140  {
141  return;
142  }
143 
144  const auto &model_symbol = ns.lookup(it->second);
145 
146  const auto &new_variable = get_fresh_aux_symbol(
147  to_code_type(model_symbol.type).return_type(),
148  "",
149  "modelled_volatile",
151  ID_C,
153  .symbol_expr();
154 
155  pre.instructions.push_back(goto_programt::make_decl(new_variable));
156 
157  code_function_callt call(new_variable, model_symbol.symbol_expr(), {});
158  pre.instructions.push_back(goto_programt::make_function_call(call));
159 
160  post.instructions.push_back(goto_programt::make_dead(new_variable));
161 
162  expr = new_variable;
163 }
164 
166  const symbol_table_baset &symbol_table,
167  exprt &expr,
168  goto_programt &pre,
169  goto_programt &post)
170 {
171  Forall_operands(it, expr)
172  nondet_volatile_rhs(symbol_table, *it, pre, post);
173 
174  if(expr.id()==ID_symbol ||
175  expr.id()==ID_dereference)
176  {
177  const namespacet ns(symbol_table);
178 
179  if(is_volatile(ns, expr.type()))
180  {
181  handle_volatile_expression(expr, ns, pre, post);
182  }
183  }
184 }
185 
187  const symbol_table_baset &symbol_table,
188  exprt &expr,
189  goto_programt &pre,
190  goto_programt &post)
191 {
192  if(expr.id()==ID_if)
193  {
194  nondet_volatile_rhs(symbol_table, to_if_expr(expr).cond(), pre, post);
195  nondet_volatile_lhs(symbol_table, to_if_expr(expr).true_case(), pre, post);
196  nondet_volatile_lhs(symbol_table, to_if_expr(expr).false_case(), pre, post);
197  }
198  else if(expr.id()==ID_index)
199  {
200  nondet_volatile_lhs(symbol_table, to_index_expr(expr).array(), pre, post);
201  nondet_volatile_rhs(symbol_table, to_index_expr(expr).index(), pre, post);
202  }
203  else if(expr.id()==ID_member)
204  {
206  symbol_table, to_member_expr(expr).struct_op(), pre, post);
207  }
208  else if(expr.id()==ID_dereference)
209  {
211  symbol_table, to_dereference_expr(expr).pointer(), pre, post);
212  }
213 }
214 
216  symbol_table_baset &symbol_table,
217  goto_programt &goto_program)
218 {
219  namespacet ns(symbol_table);
220 
221  for(auto i_it = goto_program.instructions.begin();
222  i_it != goto_program.instructions.end();
223  i_it++)
224  {
225  goto_programt pre;
226  goto_programt post;
227 
228  goto_programt::instructiont &instruction = *i_it;
229 
230  if(instruction.is_assign())
231  {
233  symbol_table, instruction.assign_rhs_nonconst(), pre, post);
235  symbol_table, instruction.assign_lhs_nonconst(), pre, post);
236  }
237  else if(instruction.is_function_call())
238  {
239  // these have arguments and a return LHS
240 
241  code_function_callt &code_function_call =
242  to_code_function_call(instruction.code_nonconst());
243 
244  // do arguments
245  for(exprt::operandst::iterator
246  it=code_function_call.arguments().begin();
247  it!=code_function_call.arguments().end();
248  it++)
249  nondet_volatile_rhs(symbol_table, *it, pre, post);
250 
251  // do return value
252  nondet_volatile_lhs(symbol_table, code_function_call.lhs(), pre, post);
253  }
254  else if(instruction.has_condition())
255  {
256  // do condition
258  symbol_table, instruction.condition_nonconst(), pre, post);
259  }
260 
261  const auto pre_size = pre.instructions.size();
262  goto_program.insert_before_swap(i_it, pre);
263  std::advance(i_it, pre_size);
264 
265  const auto post_size = post.instructions.size();
266  goto_program.destructive_insert(std::next(i_it), post);
267  std::advance(i_it, post_size);
268  }
269 }
270 
271 const symbolt &
273 {
274  const symbolt *symbol;
275 
276  if(ns.lookup(id, symbol))
277  {
279  "given symbol `" + id2string(id) + "` not found in symbol table",
281  }
282 
283  if(!symbol->is_static_lifetime || !symbol->type.get_bool(ID_C_volatile))
284  {
286  "symbol `" + id2string(id) +
287  "` does not represent a volatile variable "
288  "with static lifetime",
290  }
291 
292  INVARIANT(!symbol->is_type, "symbol must not represent a type");
293 
294  INVARIANT(!symbol->is_function(), "symbol must not represent a function");
295 
296  return *symbol;
297 }
298 
300  const irep_idt &id,
301  const symbolt &variable,
302  const namespacet &ns)
303 {
304  const symbolt *symbol;
305 
306  if(ns.lookup(id, symbol))
307  {
309  "given model name " + id2string(id) + " not found in symbol table",
311  }
312 
313  if(!symbol->is_function())
314  {
316  "symbol `" + id2string(id) + "` is not a function",
318  }
319 
320  const auto &code_type = to_code_type(symbol->type);
321 
322  if(variable.type != code_type.return_type())
323  {
325  "return type of model `" + id2string(id) +
326  "` is not compatible with the "
327  "type of the modelled variable " +
328  id2string(variable.name),
330  }
331 
332  if(!code_type.parameters().empty())
333  {
335  "model `" + id2string(id) + "` must not take parameters ",
337  }
338 }
339 
341 {
344  PRECONDITION(variable_models.empty());
345 
347  {
348  all_nondet = true;
349  return;
350  }
351 
353 
355  {
356  const auto &variable_list =
358 
359  nondet_variables.insert(variable_list.begin(), variable_list.end());
360 
361  for(const auto &id : nondet_variables)
362  {
363  typecheck_variable(id, ns);
364  }
365  }
366 
367  if(options.is_set(NONDET_VOLATILE_MODEL_OPT))
368  {
369  const auto &model_list = options.get_list_option(NONDET_VOLATILE_MODEL_OPT);
370 
371  for(const auto &s : model_list)
372  {
373  std::string variable;
374  std::string model;
375 
376  try
377  {
378  split_string(s, ':', variable, model, true);
379  }
380  catch(const deserialization_exceptiont &e)
381  {
383  "cannot split argument `" + s + "` into variable name and model name",
385  }
386 
387  const auto &variable_symbol = typecheck_variable(variable, ns);
388 
389  if(nondet_variables.count(variable) != 0)
390  {
392  "conflicting options for variable `" + variable + "`",
394  }
395 
396  typecheck_model(model, variable_symbol, ns);
397 
398  const auto p = variable_models.insert(std::make_pair(variable, model));
399 
400  if(!p.second && p.first->second != model)
401  {
403  "conflicting models for variable `" + variable + "`",
405  }
406  }
407  }
408 }
409 
410 void parse_nondet_volatile_options(const cmdlinet &cmdline, optionst &options)
411 {
415 
416  const bool nondet_volatile_opt = cmdline.isset(NONDET_VOLATILE_OPT);
417  const bool nondet_volatile_variable_opt =
419  const bool nondet_volatile_model_opt =
421 
422  if(
423  nondet_volatile_opt &&
424  (nondet_volatile_variable_opt || nondet_volatile_model_opt))
425  {
428  " cannot be used with --" NONDET_VOLATILE_VARIABLE_OPT
429  " or --" NONDET_VOLATILE_MODEL_OPT,
432  }
433 
434  if(nondet_volatile_opt)
435  {
436  options.set_option(NONDET_VOLATILE_OPT, true);
437  }
438  else
439  {
440  if(nondet_volatile_variable_opt)
441  {
442  options.set_option(
445  }
446 
447  if(nondet_volatile_model_opt)
448  {
449  options.set_option(
452  }
453  }
454 }
455 
456 void nondet_volatile(goto_modelt &goto_model, const optionst &options)
457 {
458  nondet_volatilet nv(goto_model, options);
459  nv();
460 }
virtual bool isset(char option) const
Definition: cmdline.cpp:30
const std::list< std::string > & get_values(const std::string &option) const
Definition: cmdline.cpp:109
goto_instruction_codet representation of a function call statement.
const typet & return_type() const
Definition: std_types.h:689
Thrown when failing to deserialize a value from some low level format, like JSON or raw bytes.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
const source_locationt & source_location() const
Definition: expr.h:231
typet & type()
Return the type of the expression.
Definition: expr.h:84
function_mapt function_map
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:34
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:181
bool has_condition() const
Does this instruction have a condition?
Definition: goto_program.h:360
exprt & assign_rhs_nonconst()
Get the rhs of the assignment for ASSIGN.
Definition: goto_program.h:221
exprt & condition_nonconst()
Get the condition of gotos, assume, assert.
Definition: goto_program.h:373
goto_instruction_codet & code_nonconst()
Set the code represented by this instruction.
Definition: goto_program.h:194
exprt & assign_lhs_nonconst()
Get the lhs of the assignment for ASSIGN.
Definition: goto_program.h:207
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
static instructiont make_dead(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:971
void insert_before_swap(targett target)
Insertion that preserves jumps to "target".
Definition: goto_program.h:643
void destructive_insert(const_targett target, goto_programt &p)
Inserts the given program p before target.
Definition: goto_program.h:730
static instructiont make_function_call(const code_function_callt &_code, const source_locationt &l=source_locationt::nil())
Create a function call instruction.
static instructiont make_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:964
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
void remove(const irep_idt &name)
Definition: irep.cpp:87
const irep_idt & id() const
Definition: irep.h:384
void swap(irept &irep)
Definition: irep.h:430
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
goto_modelt & goto_model
void nondet_volatile(symbol_table_baset &symbol_table, goto_programt &goto_program)
void typecheck_model(const irep_idt &id, const symbolt &variable, const namespacet &ns)
std::set< irep_idt > nondet_variables
static bool is_volatile(const namespacet &ns, const typet &src)
nondet_volatilet(goto_modelt &goto_model, const optionst &options)
void handle_volatile_expression(exprt &expr, const namespacet &ns, goto_programt &pre, goto_programt &post)
std::map< irep_idt, irep_idt > variable_models
const symbolt & typecheck_variable(const irep_idt &id, const namespacet &ns)
void nondet_volatile_rhs(const symbol_table_baset &symbol_table, exprt &expr, goto_programt &pre, goto_programt &post)
void typecheck_options(const optionst &options)
void nondet_volatile_lhs(const symbol_table_baset &symbol_table, exprt &expr, goto_programt &pre, goto_programt &post)
bool is_set(const std::string &option) const
N.B. opts.is_set("foo") does not imply opts.get_bool_option("foo")
Definition: options.cpp:62
bool get_bool_option(const std::string &option) const
Definition: options.cpp:44
void set_option(const std::string &option, const bool value)
Definition: options.cpp:28
const value_listt & get_list_option(const std::string &option) const
Definition: options.cpp:80
A side_effect_exprt that returns a non-deterministically chosen value.
Definition: std_code.h:1520
const irep_idt & get_identifier() const
Definition: std_expr.h:160
The symbol table base class interface.
Symbol table entry.
Definition: symbol.h:28
bool is_static_lifetime
Definition: symbol.h:70
bool is_type
Definition: symbol.h:61
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
bool is_function() const
Definition: symbol.h:106
typet type
Type of symbol.
Definition: symbol.h:31
irep_idt name
The unique identifier.
Definition: symbol.h:40
The type of an expression, extends irept.
Definition: type.h:29
#define Forall_operands(it, expr)
Definition: expr.h:27
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)
Symbol Table + CFG.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
void parse_nondet_volatile_options(const cmdlinet &cmdline, optionst &options)
void nondet_volatile(goto_modelt &goto_model, const optionst &options)
Havoc reads from volatile expressions, if enabled in the options.
Volatile Variables.
#define NONDET_VOLATILE_MODEL_OPT
#define NONDET_VOLATILE_OPT
#define NONDET_VOLATILE_VARIABLE_OPT
Options.
API to expression classes for Pointers.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:890
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
API to expression classes.
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2450
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2933
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)