@@ -48,6 +48,11 @@ class symbol_factoryt
48
48
allocate_objects(ID_C, loc, loc.get_function(), symbol_table)
49
49
{}
50
50
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
+
51
56
void gen_nondet_init (
52
57
code_blockt &assignments,
53
58
const exprt &expr,
@@ -210,6 +215,144 @@ void symbol_factoryt::gen_nondet_array_init(
210
215
}
211
216
}
212
217
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
+
213
356
// / Creates a symbol and generates code so that it can vary over all possible
214
357
// / values for its type. For pointers this involves allocating symbols which it
215
358
// / can point to.
0 commit comments