@@ -48,6 +48,11 @@ class symbol_factoryt
4848 allocate_objects(ID_C, loc, loc.get_function(), symbol_table)
4949 {}
5050
51+ // / Generate a function that behaves like malloc from our stdlib
52+ // / implementation
53+ // / \param malloc_symbol_name The name of the malloc function
54+ const symbolt &gen_malloc_function (const irep_idt &malloc_symbol_name);
55+
5156 void gen_nondet_init (
5257 code_blockt &assignments,
5358 const exprt &expr,
@@ -210,6 +215,144 @@ void symbol_factoryt::gen_nondet_array_init(
210215 }
211216}
212217
218+ const symbolt &
219+ symbol_factoryt::gen_malloc_function (const irep_idt &malloc_symbol_name)
220+ {
221+ // the name passed in as parameter should not exist in the symbol
222+ // table already
223+ PRECONDITION (symbol_table.lookup (malloc_symbol_name) == nullptr );
224+
225+ auto source_location = source_locationt{};
226+ source_location.set_file (
227+ " <builtin-library-" + id2string (malloc_symbol_name) + " >" );
228+ symbolt malloc_sym;
229+ malloc_sym.base_name = malloc_sym.name = malloc_sym.pretty_name =
230+ malloc_symbol_name;
231+ malloc_sym.mode = " C" ;
232+
233+ auto malloc_body = code_blockt{};
234+ malloc_body.add_source_location () = source_location;
235+
236+ // create a new local variable with this name and type, and return
237+ // a symbol_expr that represents this variable
238+ auto declare_local_variable = [&](
239+ const std::string &name, const typet &type) {
240+ auto const local_id = irep_idt{id2string (malloc_symbol_name) + " ::" + name};
241+ auto local_sym = symbolt{};
242+ local_sym.type = type;
243+ local_sym.pretty_name = name;
244+ local_sym.name = id2string (local_id);
245+ local_sym.base_name = name;
246+ local_sym.is_lvalue = false ;
247+ local_sym.is_static_lifetime = false ;
248+ local_sym.is_type = false ;
249+ local_sym.mode = " C" ;
250+ symbol_table.insert (local_sym);
251+ malloc_body.add (code_declt{local_sym.symbol_expr ()});
252+ return local_sym.symbol_expr ();
253+ };
254+
255+ // declare the parameter `size_t malloc_size` for malloc
256+ auto malloc_size_param_symbol = symbolt{};
257+ malloc_size_param_symbol.type = size_type ();
258+ malloc_size_param_symbol.name =
259+ id2string (malloc_symbol_name) + " ::malloc_size" ;
260+ malloc_size_param_symbol.pretty_name = " malloc_size" ;
261+ malloc_size_param_symbol.base_name = " malloc_size" ;
262+ malloc_size_param_symbol.is_static_lifetime = false ;
263+ malloc_size_param_symbol.is_parameter = true ;
264+ symbol_table.insert (malloc_size_param_symbol);
265+ auto malloc_size_param = code_typet::parametert{size_type ()};
266+ malloc_size_param.set_base_name (" malloc_size" );
267+ malloc_size_param.set_identifier (malloc_size_param_symbol.name );
268+
269+ // the signature for our malloc is
270+ // void *__CPROVER_malloc(size_t malloc_size);
271+ malloc_sym.type = code_typet{code_typet::parameterst{malloc_size_param},
272+ pointer_type (void_type ())};
273+
274+ auto const &local_size_variable = malloc_size_param_symbol.symbol_expr ();
275+
276+ // the variable that holds the allocation result, i.e. a valid void*
277+ // that points to a memory region of malloc_size bytes
278+ // void *malloc_res = __CPROVER_allocate(malloc_size, 0);
279+ auto const malloc_res =
280+ declare_local_variable (" malloc_res" , pointer_type (void_type ()));
281+
282+ // the actual allocation
283+ auto malloc_allocate = side_effect_exprt{ID_allocate};
284+ malloc_allocate.copy_to_operands (local_size_variable);
285+ malloc_allocate.copy_to_operands (false_exprt{});
286+ malloc_body.add (code_assignt{malloc_res, malloc_allocate});
287+
288+ // the following are all setting various CBMC book-keeping variables
289+
290+ // __CPROVER_deallocated=(malloc_res==__CPROVER_deallocated)?0:__CPROVER_deallocated;
291+ auto const &cprover_deallocated =
292+ symbol_table.lookup_ref (CPROVER_PREFIX " deallocated" );
293+ malloc_body.add (code_assignt{
294+ cprover_deallocated.symbol_expr (),
295+ if_exprt{equal_exprt{malloc_res, cprover_deallocated.symbol_expr ()},
296+ from_integer (0 , cprover_deallocated.type ),
297+ cprover_deallocated.symbol_expr ()}});
298+
299+ // __CPROVER_bool record_malloc=__VERIFIER_nondet___CPROVER_bool();
300+ auto const record_malloc =
301+ declare_local_variable (" record_malloc" , bool_typet{});
302+ malloc_body.add (
303+ code_assignt{record_malloc, get_nondet_bool (bool_typet{}, loc)});
304+
305+ // __CPROVER_malloc_object=record_malloc?malloc_res:__CPROVER_malloc_object;
306+ auto const &malloc_object =
307+ symbol_table.lookup_ref (CPROVER_PREFIX " malloc_object" );
308+ malloc_body.add (code_assignt{malloc_object.symbol_expr (),
309+ if_exprt{record_malloc,
310+ malloc_res,
311+ malloc_object.symbol_expr (),
312+ malloc_object.type }});
313+
314+ // __CPROVER_malloc_size=record_malloc?malloc_size:__CPROVER_malloc_size;
315+ auto const &malloc_size =
316+ symbol_table.lookup_ref (CPROVER_PREFIX " malloc_size" );
317+ malloc_body.add (code_assignt{malloc_size.symbol_expr (),
318+ if_exprt{record_malloc,
319+ local_size_variable,
320+ malloc_size.symbol_expr (),
321+ malloc_size.type }});
322+
323+ // __CPROVER_malloc_is_new_array=record_malloc?0:__CPROVER_malloc_is_new_array;
324+ auto const &malloc_is_new_array =
325+ symbol_table.lookup_ref (CPROVER_PREFIX " malloc_is_new_array" );
326+ malloc_body.add (code_assignt{
327+ malloc_is_new_array.symbol_expr (),
328+ if_exprt{record_malloc, false_exprt{}, malloc_is_new_array.symbol_expr ()}});
329+
330+ // __CPROVER_bool record_may_leak=__VERIFIER_nondet___CPROVER_bool();
331+ auto const record_may_leak =
332+ declare_local_variable (" record_may_leak" , bool_typet{});
333+ malloc_body.add (code_declt{record_may_leak});
334+ malloc_body.add (
335+ code_assignt{record_may_leak, get_nondet_bool (bool_typet{}, loc)});
336+
337+ // __CPROVER_memory_leak=record_may_leak?malloc_res:__CPROVER_memory_leak;
338+ auto const &memory_leak =
339+ symbol_table.lookup_ref (CPROVER_PREFIX " memory_leak" );
340+ malloc_body.add (code_assignt{
341+ memory_leak.symbol_expr (),
342+ if_exprt{record_may_leak, malloc_res, memory_leak.symbol_expr ()}});
343+
344+ // return malloc_res;
345+ malloc_body.add (code_returnt{malloc_res});
346+
347+ malloc_sym.value = malloc_body;
348+ auto inserted_sym = symbol_table.insert (malloc_sym);
349+
350+ // since the function is only called when there's no symbol with
351+ // malloc_sym.name already in the symbol table, inserting it does succeed
352+ CHECK_RETURN (inserted_sym.second );
353+ return inserted_sym.first ;
354+ }
355+
213356// / Creates a symbol and generates code so that it can vary over all possible
214357// / values for its type. For pointers this involves allocating symbols which it
215358// / can point to.
0 commit comments