CBMC
memory_predicates.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Predicates to specify memory footprint in function contracts.
4 
5 Author: Felipe R. Monteiro
6 
7 Date: July 2021
8 
9 \*******************************************************************/
10 
13 
14 #include "memory_predicates.h"
15 
16 #include <util/arith_tools.h>
17 #include <util/c_types.h>
18 #include <util/config.h>
19 #include <util/fresh_symbol.h>
20 #include <util/prefix.h>
21 
23 
24 #include <ansi-c/ansi_c_language.h>
25 #include <ansi-c/expr2c.h>
27 
29 #include "utils.h"
30 
32 {
33  return function_set;
34 }
35 
37 {
39  {
40  if(ins->is_function_call())
41  {
42  const auto &function = ins->call_function();
43 
44  if(function.id() != ID_symbol)
45  {
46  log.error().source_location = ins->source_location();
47  log.error() << "Function pointer used in function invoked by "
48  "function contract: "
49  << messaget::eom;
50  throw 0;
51  }
52  else
53  {
54  const irep_idt &fun_name = to_symbol_expr(function).get_identifier();
55  if(function_set.find(fun_name) == function_set.end())
56  {
57  function_set.insert(fun_name);
58  auto called_fun = goto_functions.function_map.find(fun_name);
59  if(called_fun == goto_functions.function_map.end())
60  {
61  log.warning() << "Could not find function '" << fun_name
62  << "' in goto-program." << messaget::eom;
63  throw 0;
64  }
65  if(called_fun->second.body_available())
66  {
67  const goto_programt &program = called_fun->second.body;
68  (*this)(program);
69  }
70  else
71  {
72  log.warning() << "No body for function: " << fun_name
73  << "invoked from function contract." << messaget::eom;
74  }
75  }
76  }
77  }
78  }
79 }
80 
81 std::set<goto_programt::targett> &find_is_fresh_calls_visitort::is_fresh_calls()
82 {
83  return function_set;
84 }
85 
87 {
88  function_set.clear();
89 }
90 
92 {
94  {
95  if(ins->is_function_call())
96  {
97  const auto &function = ins->call_function();
98 
99  if(function.id() == ID_symbol)
100  {
101  const irep_idt &fun_name = to_symbol_expr(function).get_identifier();
102 
103  if(fun_name == (CPROVER_PREFIX + std::string("is_fresh")))
104  {
105  function_set.insert(ins);
106  }
107  }
108  }
109  }
110 }
111 
113 {
114  find_is_fresh_calls_visitort requires_visitor;
115  requires_visitor(requires);
116  for(auto it : requires_visitor.is_fresh_calls())
117  {
119  }
120 }
121 
123 {
124  find_is_fresh_calls_visitort ensures_visitor;
125  ensures_visitor(ensures);
126  for(auto it : ensures_visitor.is_fresh_calls())
127  {
129  }
130 }
131 
132 //
133 //
134 // Code largely copied from model_argc_argv.cpp
135 //
136 //
137 
139 {
141 }
142 
144 {
145  source_locationt source_location;
146  add_pragma_disable_assigns_check(source_location);
147  auto memmap_type = get_memmap_type();
148  program.add(
153  source_location));
154 }
155 
157 {
158  source_locationt source_location;
159  add_pragma_disable_assigns_check(source_location);
160  program.add(
162 }
163 
164 void is_fresh_baset::add_declarations(const std::string &decl_string)
165 {
166  log.debug() << "Creating declarations: \n" << decl_string << "\n";
167 
168  std::istringstream iss(decl_string);
169 
170  ansi_c_languaget ansi_c_language;
171  ansi_c_language.set_message_handler(log.get_message_handler());
174  ansi_c_language.parse(iss, "");
176 
177  symbol_tablet tmp_symbol_table;
178  ansi_c_language.typecheck(tmp_symbol_table, "<built-in-library>");
179  exprt value = nil_exprt();
180 
181  goto_functionst tmp_functions;
182 
183  // Add the new functions into the goto functions table.
185  tmp_functions.function_map[ensures_fn_name]);
186 
188  tmp_functions.function_map[requires_fn_name]);
189 
190  for(const auto &symbol_pair : tmp_symbol_table.symbols)
191  {
192  if(
193  symbol_pair.first == memmap_name ||
194  symbol_pair.first == ensures_fn_name ||
195  symbol_pair.first == requires_fn_name || symbol_pair.first == "malloc")
196  {
197  this->parent.get_symbol_table().insert(symbol_pair.second);
198  }
199  // Parameters are stored as scoped names in the symbol table.
200  else if(
201  (has_prefix(
202  id2string(symbol_pair.first), id2string(ensures_fn_name) + "::") ||
203  has_prefix(
204  id2string(symbol_pair.first), id2string(requires_fn_name) + "::")) &&
205  parent.get_symbol_table().add(symbol_pair.second))
206  {
207  UNREACHABLE;
208  }
209  }
210 
212  {
216  goto_convert(
222  }
223 }
224 
227  const std::string &fn_name,
228  bool add_address_of)
229 {
230  // adjusting the expression for the first argument, if required
231  if(add_address_of)
232  {
233  INVARIANT(
234  as_const(*ins).call_arguments().size() > 0,
235  "Function must have arguments");
236  ins->call_arguments()[0] = address_of_exprt(ins->call_arguments()[0]);
237  }
238 
239  // fixing the function name.
240  to_symbol_expr(ins->call_function()).set_identifier(fn_name);
241 
242  // pass the memory mmap
243  ins->call_arguments().push_back(address_of_exprt(
245 }
246 
247 /* Declarations for contract enforcement */
248 
250  code_contractst &_parent,
251  messaget _log,
252  irep_idt _fun_id)
253  : is_fresh_baset(_parent, _log, _fun_id)
254 {
255  std::stringstream ssreq, ssensure, ssmemmap;
256  ssreq << CPROVER_PREFIX "enforce_requires_is_fresh";
257  this->requires_fn_name = ssreq.str();
258 
259  ssensure << CPROVER_PREFIX "enforce_ensures_is_fresh";
260  this->ensures_fn_name = ssensure.str();
261 
262  ssmemmap << CPROVER_PREFIX "is_fresh_memory_map_" << fun_id;
263  this->memmap_name = ssmemmap.str();
264 
265  const auto &mode = parent.get_symbol_table().lookup_ref(_fun_id).mode;
267  get_memmap_type(),
269  mode,
271  this->memmap_name,
272  true);
273 }
274 
276 {
277  // Check if symbols are already declared
279  return;
280 
281  std::ostringstream oss;
282  std::string cprover_prefix(CPROVER_PREFIX);
283  oss << "_Bool " << requires_fn_name
284  << "(void **elem, " + cprover_prefix + "size_t size, _Bool *mmap) { \n"
285  << "#pragma CPROVER check push\n"
286  << "#pragma CPROVER check disable \"pointer\"\n"
287  << "#pragma CPROVER check disable \"pointer-primitive\"\n"
288  << "#pragma CPROVER check disable \"pointer-overflow\"\n"
289  << "#pragma CPROVER check disable \"signed-overflow\"\n"
290  << "#pragma CPROVER check disable \"unsigned-overflow\"\n"
291  << "#pragma CPROVER check disable \"conversion\"\n"
292  << " *elem = malloc(size); \n"
293  << " if (!*elem) return 0; \n"
294  << " mmap[" + cprover_prefix + "POINTER_OBJECT(*elem)] = 1; \n"
295  << " return 1; \n"
296  << "#pragma CPROVER check pop\n"
297  << "} \n"
298  << "\n"
299  << "_Bool " << ensures_fn_name
300  << "(void *elem, " + cprover_prefix + "size_t size, _Bool *mmap) { \n"
301  << "#pragma CPROVER check push\n"
302  << "#pragma CPROVER check disable \"pointer\"\n"
303  << "#pragma CPROVER check disable \"pointer-primitive\"\n"
304  << "#pragma CPROVER check disable \"pointer-overflow\"\n"
305  << "#pragma CPROVER check disable \"signed-overflow\"\n"
306  << "#pragma CPROVER check disable \"unsigned-overflow\"\n"
307  << "#pragma CPROVER check disable \"conversion\"\n"
308  << " _Bool ok = (!mmap[" + cprover_prefix + "POINTER_OBJECT(elem)] && "
309  << cprover_prefix + "r_ok(elem, size)); \n"
310  << " mmap[" + cprover_prefix << "POINTER_OBJECT(elem)] = 1; \n"
311  << " return ok; \n"
312  << "#pragma CPROVER check pop\n"
313  << "}";
314 
315  add_declarations(oss.str());
316 }
317 
319 {
320  update_fn_call(ins, requires_fn_name, true);
321 }
322 
324 {
325  update_fn_call(ins, ensures_fn_name, false);
326 }
327 
329  code_contractst &_parent,
330  messaget _log,
331  irep_idt _fun_id)
332  : is_fresh_baset(_parent, _log, _fun_id)
333 {
334  std::stringstream ssreq, ssensure, ssmemmap;
335  ssreq << CPROVER_PREFIX "replace_requires_is_fresh";
336  this->requires_fn_name = ssreq.str();
337 
338  ssensure << CPROVER_PREFIX "replace_ensures_is_fresh";
339  this->ensures_fn_name = ssensure.str();
340 
341  ssmemmap << CPROVER_PREFIX "is_fresh_memory_map_" << fun_id;
342  this->memmap_name = ssmemmap.str();
343 
344  const auto &mode = parent.get_symbol_table().lookup_ref(_fun_id).mode;
346  get_memmap_type(),
348  mode,
350  this->memmap_name,
351  true);
352 }
353 
355 {
356  // Check if symbols are already declared
358  return;
359  std::ostringstream oss;
360  std::string cprover_prefix(CPROVER_PREFIX);
361  oss << "static _Bool " << requires_fn_name
362  << "(void *elem, " + cprover_prefix + "size_t size, _Bool *mmap) { \n"
363  << "#pragma CPROVER check push\n"
364  << "#pragma CPROVER check disable \"pointer\"\n"
365  << "#pragma CPROVER check disable \"pointer-primitive\"\n"
366  << "#pragma CPROVER check disable \"pointer-overflow\"\n"
367  << "#pragma CPROVER check disable \"signed-overflow\"\n"
368  << "#pragma CPROVER check disable \"unsigned-overflow\"\n"
369  << "#pragma CPROVER check disable \"conversion\"\n"
370  << " _Bool r_ok = " + cprover_prefix + "r_ok(elem, size); \n"
371  << " if (mmap[" + cprover_prefix + "POINTER_OBJECT(elem)]"
372  << " != 0 || !r_ok) return 0; \n"
373  << " mmap[" << cprover_prefix + "POINTER_OBJECT(elem)] = 1; \n"
374  << " return 1; \n"
375  << "#pragma CPROVER check pop\n"
376  << "} \n"
377  << " \n"
378  << "_Bool " << ensures_fn_name
379  << "(void **elem, " + cprover_prefix + "size_t size, _Bool *mmap) { \n"
380  << "#pragma CPROVER check push\n"
381  << "#pragma CPROVER check disable \"pointer\"\n"
382  << "#pragma CPROVER check disable \"pointer-primitive\"\n"
383  << "#pragma CPROVER check disable \"pointer-overflow\"\n"
384  << "#pragma CPROVER check disable \"signed-overflow\"\n"
385  << "#pragma CPROVER check disable \"unsigned-overflow\"\n"
386  << "#pragma CPROVER check disable \"conversion\"\n"
387  << " *elem = malloc(size); \n"
388  << " return (*elem != 0); \n"
389  << "#pragma CPROVER check pop\n"
390  << "} \n";
391 
392  add_declarations(oss.str());
393 }
394 
396 {
397  update_fn_call(ins, requires_fn_name, false);
398 }
399 
401 {
402  update_fn_call(ins, ensures_fn_name, true);
403 }
messaget
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
Forall_goto_program_instructions
#define Forall_goto_program_instructions(it, program)
Definition: goto_program.h:1234
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
symbol_tablet
The symbol table.
Definition: symbol_table.h:13
symbol_table_baset::lookup_ref
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Definition: symbol_table_base.h:104
is_fresh_baset::add_declarations
void add_declarations(const std::string &decl_string)
Definition: memory_predicates.cpp:164
arith_tools.h
goto_programt::make_dead
static instructiont make_dead(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:962
is_fresh_baset::requires_fn_name
std::string requires_fn_name
Definition: memory_predicates.h:54
is_fresh_baset::ensures_fn_name
std::string ensures_fn_name
Definition: memory_predicates.h:55
fresh_symbol.h
is_fresh_replacet::is_fresh_replacet
is_fresh_replacet(code_contractst &_parent, messaget _log, const irep_idt _fun_id)
Definition: memory_predicates.cpp:328
is_fresh_replacet::create_ensures_fn_call
virtual void create_ensures_fn_call(goto_programt::targett &target)
Definition: memory_predicates.cpp:400
is_fresh_enforcet::create_requires_fn_call
virtual void create_requires_fn_call(goto_programt::targett &target)
Definition: memory_predicates.cpp:318
is_fresh_baset::get_memmap_type
array_typet get_memmap_type()
Definition: memory_predicates.cpp:138
configt::ansi_ct::preprocessort
preprocessort
Definition: config.h:239
prefix.h
functions_in_scope_visitort::function_calls
std::set< irep_idt > & function_calls()
Definition: memory_predicates.cpp:31
goto_programt::add
targett add(instructiont &&instruction)
Adds a given instruction at the end.
Definition: goto_program.h:709
functions_in_scope_visitort::operator()
void operator()(const goto_programt &prog)
Definition: memory_predicates.cpp:36
exprt
Base class for all expressions.
Definition: expr.h:55
find_is_fresh_calls_visitort::operator()
void operator()(goto_programt &prog)
Definition: memory_predicates.cpp:91
messaget::eom
static eomt eom
Definition: message.h:297
configt::ansi_c
struct configt::ansi_ct ansi_c
goto_functionst::function_map
function_mapt function_map
Definition: goto_functions.h:29
goto_programt::make_decl
static instructiont make_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:955
goto_programt::make_assignment
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
Definition: goto_program.h:1056
infinity_exprt
An expression denoting infinity.
Definition: std_expr.h:3041
is_fresh_baset::update_ensures
void update_ensures(goto_programt &ensures)
Definition: memory_predicates.cpp:122
is_fresh_baset::parent
code_contractst & parent
Definition: memory_predicates.h:48
is_fresh_baset::log
messaget log
Definition: memory_predicates.h:49
goto_convert
void goto_convert(const codet &code, symbol_table_baset &symbol_table, goto_programt &dest, message_handlert &message_handler, const irep_idt &mode)
Definition: goto_convert.cpp:1905
c_bool_typet
The C/C++ Booleans.
Definition: c_types.h:74
memory_predicates.h
is_fresh_replacet::create_requires_fn_call
virtual void create_requires_fn_call(goto_programt::targett &target)
Definition: memory_predicates.cpp:395
functions_in_scope_visitort::function_set
std::set< irep_idt > function_set
Definition: memory_predicates.h:131
utils.h
symbolt::mode
irep_idt mode
Language mode.
Definition: symbol.h:49
as_const
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition: as_const.h:14
messaget::error
mstreamt & error() const
Definition: message.h:399
has_prefix
bool has_prefix(const std::string &s, const std::string &prefix)
Definition: converter.cpp:13
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
configt::ansi_ct::preprocessor
preprocessort preprocessor
Definition: config.h:248
messaget::mstreamt::source_location
source_locationt source_location
Definition: message.h:247
is_fresh_baset::update_fn_call
void update_fn_call(goto_programt::targett &target, const std::string &name, bool add_address_of)
Definition: memory_predicates.cpp:225
expr2c.h
is_fresh_enforcet::create_ensures_fn_call
virtual void create_ensures_fn_call(goto_programt::targett &target)
Definition: memory_predicates.cpp:323
symbol_exprt::get_identifier
const irep_idt & get_identifier() const
Definition: std_expr.h:142
nil_exprt
The NIL expression.
Definition: std_expr.h:3025
array_of_exprt
Array constructor from single element.
Definition: std_expr.h:1497
find_is_fresh_calls_visitort::function_set
std::set< goto_programt::targett > function_set
Definition: memory_predicates.h:107
is_fresh_baset::fun_id
irep_idt fun_id
Definition: memory_predicates.h:50
add_pragma_disable_assigns_check
void add_pragma_disable_assigns_check(source_locationt &location)
Adds a pragma on a source_locationt to disable inclusion checking.
Definition: instrument_spec_assigns.cpp:70
symbolt::symbol_expr
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
INITIALIZE_FUNCTION
#define INITIALIZE_FUNCTION
Definition: static_lifetime_init.h:22
code_contractst
Definition: contracts.h:55
messaget::set_message_handler
virtual void set_message_handler(message_handlert &_message_handler)
Definition: message.h:179
symbol_tablet::insert
virtual std::pair< symbolt &, bool > insert(symbolt symbol) override
Author: Diffblue Ltd.
Definition: symbol_table.cpp:17
to_symbol_expr
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:222
is_fresh_baset::add_memory_map_dead
void add_memory_map_dead(goto_programt &program)
Definition: memory_predicates.cpp:156
functions_in_scope_visitort::log
messaget & log
Definition: memory_predicates.h:130
is_fresh_baset::memmap_symbol
symbolt memmap_symbol
Definition: memory_predicates.h:56
is_fresh_baset::create_ensures_fn_call
virtual void create_ensures_fn_call(goto_programt::targett &target)=0
config
configt config
Definition: config.cpp:25
source_locationt
Definition: source_location.h:18
is_fresh_baset
Definition: memory_predicates.h:19
find_is_fresh_calls_visitort
Predicate to be used with the exprt::visit() function.
Definition: memory_predicates.h:93
configt::ansi_ct::preprocessort::NONE
@ NONE
symbol_table_baset::add
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
Definition: symbol_table_base.cpp:18
find_is_fresh_calls_visitort::is_fresh_calls
std::set< goto_programt::targett > & is_fresh_calls()
Definition: memory_predicates.cpp:81
goto_functionst
A collection of goto functions.
Definition: goto_functions.h:24
messaget::get_message_handler
message_handlert & get_message_handler()
Definition: message.h:184
array_typet
Arrays with given size.
Definition: std_types.h:762
ansi_c_language.h
is_fresh_enforcet::is_fresh_enforcet
is_fresh_enforcet(code_contractst &_parent, messaget _log, const irep_idt _fun_id)
Definition: memory_predicates.cpp:249
symbolt::location
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:37
ansi_c_languaget::parse
bool parse(std::istream &instream, const std::string &path) override
Definition: ansi_c_language.cpp:50
instrument_spec_assigns.h
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
static_lifetime_init
static optionalt< codet > static_lifetime_init(const irep_idt &identifier, symbol_tablet &symbol_table)
Definition: static_lifetime_init.cpp:22
symbol_table_baset::symbols
const symbolst & symbols
Read-only field, used to look up symbols given their names.
Definition: symbol_table_base.h:30
is_fresh_baset::memmap_name
std::string memmap_name
Definition: memory_predicates.h:53
code_contractst::get_symbol_table
symbol_tablet & get_symbol_table()
Definition: contracts.cpp:1176
CPROVER_PREFIX
#define CPROVER_PREFIX
Definition: cprover_prefix.h:14
goto_functionst::update
void update()
Definition: goto_functions.h:83
is_fresh_baset::create_requires_fn_call
virtual void create_requires_fn_call(goto_programt::targett &target)=0
goto_programt
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:72
config.h
symbol_table_baset::lookup
const symbolt * lookup(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Definition: symbol_table_base.h:95
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
is_fresh_enforcet::create_declarations
virtual void create_declarations()
Definition: memory_predicates.cpp:275
messaget::debug
mstreamt & debug() const
Definition: message.h:429
ansi_c_languaget::typecheck
bool typecheck(symbol_tablet &symbol_table, const std::string &module, const bool keep_file_local) override
typecheck without removing specified entries from the symbol table
Definition: ansi_c_language.cpp:103
goto_convert_functions.h
index_exprt
Array index operator.
Definition: std_expr.h:1409
static_lifetime_init.h
address_of_exprt
Operator to return the address of an object.
Definition: pointer_expr.h:370
is_fresh_replacet::create_declarations
virtual void create_declarations()
Definition: memory_predicates.cpp:354
size_type
unsignedbv_typet size_type()
Definition: c_types.cpp:68
code_contractst::get_goto_functions
goto_functionst & get_goto_functions()
Definition: contracts.cpp:1181
messaget::warning
mstreamt & warning() const
Definition: message.h:404
c_index_type
bitvector_typet c_index_type()
Definition: c_types.cpp:16
find_is_fresh_calls_visitort::clear_set
void clear_set()
Definition: memory_predicates.cpp:86
ansi_c_languaget
Definition: ansi_c_language.h:34
c_types.h
symbol_exprt::set_identifier
void set_identifier(const irep_idt &identifier)
Definition: std_expr.h:137
goto_programt::targett
instructionst::iterator targett
Definition: goto_program.h:586
forall_goto_program_instructions
#define forall_goto_program_instructions(it, program)
Definition: goto_program.h:1229
validation_modet::INVARIANT
@ INVARIANT
is_fresh_baset::update_requires
void update_requires(goto_programt &requires)
Definition: memory_predicates.cpp:112
is_fresh_baset::add_memory_map_decl
void add_memory_map_decl(goto_programt &program)
Definition: memory_predicates.cpp:143
functions_in_scope_visitort::goto_functions
const goto_functionst & goto_functions
Definition: memory_predicates.h:129