Skip to content

Commit 31ffef4

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 31ffef4

File tree

4 files changed

+65
-4
lines changed

4 files changed

+65
-4
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: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Author: Daniel Kroening, [email protected]
1616
#include <iostream>
1717
#include <memory>
1818

19+
#include <util/c_types.h>
1920
#include <util/config.h>
2021
#include <util/exception_utils.h>
2122
#include <util/exit_codes.h>
@@ -778,6 +779,47 @@ bool cbmc_parse_optionst::set_properties()
778779
return false;
779780
}
780781

782+
template <typename T>
783+
code_assignt make_integer_assignment(
784+
const symbol_table_baset &symbol_table,
785+
const irep_idt &symbol_name,
786+
T &&value)
787+
{
788+
const auto &symbol = symbol_table.lookup_ref(symbol_name).symbol_expr();
789+
return code_assignt{symbol, from_integer(value, symbol.type())};
790+
}
791+
792+
/// Some variables have different initial values based on what flags are being passed to cbmc;
793+
/// since the _start function might've been generated by goto-cc before getting passed over here
794+
/// we need to add the initialisation of these variables here as a post-processing step
795+
static void
796+
add_malloc_may_fail_variable_initializations(goto_modelt &goto_model)
797+
{
798+
auto const initialize_function_name = CPROVER_PREFIX "initialize";
799+
PRECONDITION(
800+
goto_model.get_goto_functions().function_map.count(
801+
initialize_function_name) == 1);
802+
auto &initialize_function =
803+
goto_model.goto_functions.function_map.find(initialize_function_name)
804+
->second;
805+
const auto initialize_function_end =
806+
--initialize_function.body.instructions.end();
807+
808+
initialize_function.body.insert_before(
809+
initialize_function_end,
810+
goto_programt::make_assignment(make_integer_assignment(
811+
goto_model.symbol_table,
812+
CPROVER_PREFIX "malloc_may_fail",
813+
config.ansi_c.malloc_may_fail)));
814+
815+
initialize_function.body.insert_before(
816+
initialize_function_end,
817+
goto_programt::make_assignment(make_integer_assignment(
818+
goto_model.symbol_table,
819+
CPROVER_PREFIX "malloc_failure_mode",
820+
config.ansi_c.malloc_failure_mode)));
821+
}
822+
781823
int cbmc_parse_optionst::get_goto_program(
782824
goto_modelt &goto_model,
783825
const optionst &options,
@@ -879,6 +921,8 @@ bool cbmc_parse_optionst::process_goto_program(
879921
link_to_library(
880922
goto_model, log.get_message_handler(), cprover_c_library_factory);
881923

924+
add_malloc_may_fail_variable_initializations(goto_model);
925+
882926
if(options.get_bool_option("string-abstraction"))
883927
string_instrumentation(goto_model, log.get_message_handler());
884928

0 commit comments

Comments
 (0)