Skip to content

Commit 33c02db

Browse files
Fix bug that prevented --malloc-may-fail from working
We have code in our stdlib models that depends on two global variables, __CPROVER_malloc_may_fail and __CPROVER_malloc_failure_mode. Previously these were set based on the ansi-c config in builtin_additions by generating C code containing definitions for these variables. The problem with that is that if you compile an executable using goto-cc we also load the builtin_additions, so this executable already contains definitions for these variables which can't be overridden. This works around this issue by instead declaring these variables as extern in builtin_additions, and setting their values dynamically as last-minute instrumentation at the end of __CPROVER_initialize. Giving these no/nondet initial values is important because otherwise preprocessing like constant folding on goto-binaries before cbmc actually runs could remove branches we can, in fact, take with different values set by --malloc-fail-* flags. An alternative would be to instead dynamically change the code for the models functions as instrumentation, but this has a couple of problems; For instance this means we might change the behaviour of custom stdlib models (which we allow via --no-library) or custom goto instrumentation in unexpected ways. I believe this way is the least likely to cause any friction like that.
1 parent a6feed2 commit 33c02db

File tree

7 files changed

+108
-5
lines changed

7 files changed

+108
-5
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
int main(void)
5+
{
6+
int *array = calloc(10, sizeof(int));
7+
assert(array != NULL);
8+
free(array);
9+
return 0;
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
test.c
3+
--malloc-may-fail --malloc-fail-null
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
\[main.assertion.1\] line 6 assertion array != NULL: FAILURE
7+
--
8+
--
9+
Compiling a file with goto-cc should not affect how --malloc-may-fail behaves

src/ansi-c/ansi_c_internal_additions.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,17 +186,15 @@ void ansi_c_internal_additions(std::string &code)
186186
CPROVER_PREFIX "size_t size, " CPROVER_PREFIX "bool zero);\n"
187187
"const void *" CPROVER_PREFIX "alloca_object = 0;\n"
188188

189-
"int " CPROVER_PREFIX "malloc_failure_mode="+
190-
std::to_string(config.ansi_c.malloc_failure_mode)+";\n"
189+
"extern int " CPROVER_PREFIX "malloc_failure_mode;\n"
191190
"int " CPROVER_PREFIX "malloc_failure_mode_return_null="+
192191
std::to_string(config.ansi_c.malloc_failure_mode_return_null)+";\n"
193192
"int " CPROVER_PREFIX "malloc_failure_mode_assert_then_assume="+
194193
std::to_string(config.ansi_c.malloc_failure_mode_assert_then_assume)+";\n"
195194
CPROVER_PREFIX "size_t " CPROVER_PREFIX "max_malloc_size="+
196195
integer2string(max_malloc_size(config.ansi_c.pointer_width, config
197196
.bv_encoding.object_bits))+";\n"
198-
CPROVER_PREFIX "bool " CPROVER_PREFIX "malloc_may_fail = " +
199-
std::to_string(config.ansi_c.malloc_may_fail) + ";\n"
197+
"extern " CPROVER_PREFIX "bool " CPROVER_PREFIX "malloc_may_fail;\n"
200198

201199
// this is ANSI-C
202200
"extern " CPROVER_PREFIX "thread_local const char __func__["

src/cbmc/cbmc_parse_options.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Author: Daniel Kroening, [email protected]
4848
#include <goto-checker/stop_on_fail_verifier.h>
4949
#include <goto-checker/stop_on_fail_verifier_with_fault_localization.h>
5050

51+
#include <goto-programs/add_malloc_may_fail_variable_initializations.h>
5152
#include <goto-programs/adjust_float_expressions.h>
5253
#include <goto-programs/initialize_goto_model.h>
5354
#include <goto-programs/instrument_preconditions.h>
@@ -879,6 +880,8 @@ bool cbmc_parse_optionst::process_goto_program(
879880
link_to_library(
880881
goto_model, log.get_message_handler(), cprover_c_library_factory);
881882

883+
add_malloc_may_fail_variable_initializations(goto_model);
884+
882885
if(options.get_bool_option("string-abstraction"))
883886
string_instrumentation(goto_model, log.get_message_handler());
884887

src/goto-programs/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
SRC = adjust_float_expressions.cpp \
1+
SRC = add_malloc_may_fail_variable_initializations.cpp \
2+
adjust_float_expressions.cpp \
23
builtin_functions.cpp \
34
class_hierarchy.cpp \
45
class_identifier.cpp \
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/// \file
2+
/// \author Diffblue Ltd.
3+
4+
#include "add_malloc_may_fail_variable_initializations.h"
5+
6+
#include "goto_model.h"
7+
8+
#include <util/arith_tools.h>
9+
#include <util/config.h>
10+
#include <util/irep.h>
11+
12+
template <typename T>
13+
code_assignt make_integer_assignment(
14+
const symbol_table_baset &symbol_table,
15+
const irep_idt &symbol_name,
16+
T &&value)
17+
{
18+
const auto &symbol = symbol_table.lookup_ref(symbol_name).symbol_expr();
19+
return code_assignt{symbol, from_integer(value, symbol.type())};
20+
}
21+
22+
void add_malloc_may_fail_variable_initializations(goto_modelt &goto_model)
23+
{
24+
const auto malloc_may_fail_id = irep_idt{CPROVER_PREFIX "malloc_may_fail"};
25+
const auto malloc_failure_mode_id =
26+
irep_idt{CPROVER_PREFIX "malloc_failure_mode"};
27+
if(!goto_model.symbol_table.has_symbol(malloc_may_fail_id))
28+
{
29+
// if malloc_may_fail isn't in the symbol table (i.e. builtin library not
30+
// loaded) then we don't generate initialisation code for it.
31+
return;
32+
}
33+
34+
INVARIANT(
35+
goto_model.symbol_table.has_symbol(malloc_failure_mode_id),
36+
"if malloc_may_fail is in the symbol table then so should "
37+
"malloc_failure_mode");
38+
39+
auto const initialize_function_name = CPROVER_PREFIX "initialize";
40+
PRECONDITION(
41+
goto_model.get_goto_functions().function_map.count(
42+
initialize_function_name) == 1);
43+
auto &initialize_function =
44+
goto_model.goto_functions.function_map.find(initialize_function_name)
45+
->second;
46+
const auto initialize_function_end =
47+
--initialize_function.body.instructions.end();
48+
49+
initialize_function.body.insert_before(
50+
initialize_function_end,
51+
goto_programt::make_assignment(make_integer_assignment(
52+
goto_model.symbol_table,
53+
malloc_may_fail_id,
54+
config.ansi_c.malloc_may_fail)));
55+
56+
initialize_function.body.insert_before(
57+
initialize_function_end,
58+
goto_programt::make_assignment(make_integer_assignment(
59+
goto_model.symbol_table,
60+
malloc_failure_mode_id,
61+
config.ansi_c.malloc_failure_mode)));
62+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// \file
2+
/// \author Diffblue Ltd.
3+
/// Adds an instrumentation to add initialisations for variables
4+
/// used by the --malloc-may-fail and related flags in cbmc
5+
6+
// NOLINT(whitespace/line_length)
7+
#ifndef CPROVER_GOTO_PROGRAMS_ADD_MALLOC_MAY_FAIL_VARIABLE_INITIALIZATIONS_H
8+
// NOLINT(whitespace/line_length)
9+
#define CPROVER_GOTO_PROGRAMS_ADD_MALLOC_MAY_FAIL_VARIABLE_INITIALIZATIONS_H
10+
11+
class goto_modelt;
12+
13+
/// Some variables have different initial values based on what flags are being
14+
/// passed to cbmc; since the _start function might've been generated by goto-cc
15+
/// before getting passed over here we need to add the initialisation of these
16+
/// variables here as a post-processing step
17+
void add_malloc_may_fail_variable_initializations(goto_modelt &goto_model);
18+
19+
// NOLINT(whitespace/line_length)
20+
#endif // CPROVER_GOTO_PROGRAMS_ADD_MALLOC_MAY_FAIL_VARIABLE_INITIALIZATIONS_H

0 commit comments

Comments
 (0)