Skip to content

Commit f06afc4

Browse files
committed
goto-harness: use __CPROVER_(de)?allocate, not malloc/free
Do not use C-specific functions when amending GOTO programs. Fixes: #8681
1 parent 8f1868c commit f06afc4

File tree

5 files changed

+71
-58
lines changed

5 files changed

+71
-58
lines changed

jbmc/unit/java_bytecode/java_object_factory/gen_nondet_string_init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ SCENARIO(
9292
CPROVER_PREFIX "assume(tmp_object_factory <= 20);",
9393
"char (*nondet_infinite_array_pointer)[INFINITY()];",
9494
"nondet_infinite_array_pointer = "
95-
"__CPROVER_allocate(INFINITY(), false);",
95+
CPROVER_PREFIX "allocate(INFINITY(), false);",
9696
"*nondet_infinite_array_pointer = NONDET(char [INFINITY()]);",
9797
"int return_array;",
9898
"return_array = cprover_associate_array_to_pointer_func"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <assert.h>
2+
3+
void test_fn(int *a)
4+
// clang-format off
5+
__CPROVER_requires((a == (int*)0) || __CPROVER_is_fresh(a, sizeof(*a)))
6+
__CPROVER_requires((a != (int*)0) ==> (*a != 5))
7+
__CPROVER_ensures((a != (int*)0) ==> (*a == 5))
8+
__CPROVER_assigns(*a)
9+
// clang-format on
10+
{
11+
assert((a == (int *)0) || (*a != 5));
12+
if(a != (int *)0)
13+
{
14+
*a = 5;
15+
}
16+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--harness-type call-function --function test_fn
4+
^\[test_fn.assertion.1\] line 11 assertion \(a == \(int \*\)0\) \|\| \(\*a != 5\): FAILURE$
5+
^\*\* 1 of \d+ failed
6+
VERIFICATION FAILED
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
CALL.*malloc
11+
CALL.*free
12+
--
13+
Ensure that we do not generate calls to malloc or free.

src/goto-harness/recursive_initialization.cpp

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -372,24 +372,6 @@ irep_idt recursive_initializationt::build_constructor(const exprt &expr)
372372
return type_constructor_names.at(key);
373373
}
374374

375-
symbol_exprt recursive_initializationt::get_malloc_function()
376-
{
377-
auto malloc_sym = goto_model.symbol_table.lookup("malloc");
378-
if(malloc_sym == nullptr)
379-
{
380-
symbolt new_malloc_sym{
381-
"malloc",
382-
code_typet{
383-
{code_typet::parametert{size_type()}}, pointer_type(empty_typet{})},
384-
initialization_config.mode};
385-
new_malloc_sym.pretty_name = "malloc";
386-
new_malloc_sym.base_name = "malloc";
387-
goto_model.symbol_table.insert(new_malloc_sym);
388-
return new_malloc_sym.symbol_expr();
389-
}
390-
return malloc_sym->symbol_expr();
391-
}
392-
393375
bool recursive_initializationt::should_be_treated_as_array(
394376
const irep_idt &array_name) const
395377
{
@@ -630,24 +612,6 @@ std::string recursive_initializationt::type2id(const typet &type) const
630612
return "";
631613
}
632614

633-
symbol_exprt recursive_initializationt::get_free_function()
634-
{
635-
auto free_sym = goto_model.symbol_table.lookup("free");
636-
if(free_sym == nullptr)
637-
{
638-
symbolt new_free_sym{
639-
"free",
640-
code_typet{
641-
{code_typet::parametert{pointer_type(empty_typet{})}}, empty_typet{}},
642-
initialization_config.mode};
643-
new_free_sym.pretty_name = "free";
644-
new_free_sym.base_name = "free";
645-
goto_model.symbol_table.insert(new_free_sym);
646-
return new_free_sym.symbol_expr();
647-
}
648-
return free_sym->symbol_expr();
649-
}
650-
651615
code_blockt recursive_initializationt::build_pointer_constructor(
652616
const exprt &depth,
653617
const symbol_exprt &result)
@@ -724,10 +688,13 @@ code_blockt recursive_initializationt::build_pointer_constructor(
724688

725689
then_case.add(code_declt{local_result});
726690
const namespacet ns{goto_model.symbol_table};
727-
then_case.add(code_function_callt{
691+
then_case.add(code_assignt{
728692
local_result,
729-
get_malloc_function(),
730-
{*size_of_expr(non_const_pointer_type.base_type(), ns)}});
693+
side_effect_exprt{
694+
ID_allocate,
695+
{*size_of_expr(non_const_pointer_type.base_type(), ns), false_exprt{}},
696+
non_const_pointer_type,
697+
source_locationt::nil()}});
731698
initialize(
732699
dereference_exprt{local_result},
733700
plus_exprt{depth, from_integer(1, depth.type())},
@@ -869,10 +836,16 @@ code_blockt recursive_initializationt::build_dynamic_array_constructor(
869836
{
870837
body.add(code_ifthenelset{
871838
equal_exprt{nondet_size, from_integer(array_size, nondet_size.type())},
872-
code_function_callt{local_result,
873-
get_malloc_function(),
874-
{mult_exprt{from_integer(array_size, size_type()),
875-
*size_of_expr(element_type, ns)}}}});
839+
code_assignt{
840+
local_result,
841+
side_effect_exprt{
842+
ID_allocate,
843+
{mult_exprt{
844+
from_integer(array_size, size_type()),
845+
*size_of_expr(element_type, ns)},
846+
false_exprt{}},
847+
mutable_dynamic_array_type,
848+
source_locationt::nil()}}});
876849
}
877850

878851
const symbol_exprt &index_iter = get_fresh_local_symexpr("index");
@@ -942,18 +915,35 @@ bool recursive_initializationt::needs_freeing(const exprt &expr) const
942915
return true;
943916
}
944917

918+
code_blockt
919+
recursive_initializationt::deallocate_code(const exprt &pointer) const
920+
{
921+
code_blockt block;
922+
const auto should_track =
923+
get_fresh_local_typed_symexpr("mark_deallocated", bool_typet{});
924+
block.add(code_declt{should_track});
925+
const symbol_exprt deallocated = goto_model.get_symbol_table()
926+
.lookup_ref(CPROVER_PREFIX "deallocated")
927+
.symbol_expr();
928+
block.add(code_ifthenelset{
929+
should_track,
930+
code_assignt{
931+
deallocated,
932+
typecast_exprt::conditional_cast(pointer, deallocated.type())}});
933+
return block;
934+
}
935+
945936
void recursive_initializationt::free_if_possible(
946937
const exprt &expr,
947938
code_blockt &body)
948939
{
949940
PRECONDITION(expr.id() == ID_symbol);
950941
const auto expr_id = to_symbol_expr(expr).get_identifier();
951942
const auto maybe_cluster_index = find_equal_cluster(expr_id);
952-
const auto call_free = code_function_callt{get_free_function(), {expr}};
953943
if(!maybe_cluster_index.has_value())
954944
{
955945
// not in any equality cluster -> just free
956-
body.add(call_free);
946+
body.add(deallocate_code(expr));
957947
return;
958948
}
959949

@@ -965,7 +955,7 @@ void recursive_initializationt::free_if_possible(
965955
// in equality cluster but not common origin -> free if not equal to origin
966956
const auto condition =
967957
notequal_exprt{expr, *common_arguments_origins[*maybe_cluster_index]};
968-
body.add(code_ifthenelset{condition, call_free});
958+
body.add(code_ifthenelset{condition, deallocate_code(expr)});
969959
}
970960
else
971961
{
@@ -979,7 +969,7 @@ void recursive_initializationt::free_cluster_origins(code_blockt &body)
979969
{
980970
for(auto const &origin : common_arguments_origins)
981971
{
982-
body.add(code_function_callt{get_free_function(), {*origin}});
972+
body.add(deallocate_code(*origin));
983973
}
984974
}
985975

src/goto-harness/recursive_initialization.h

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,6 @@ class recursive_initializationt
9898
/// \param body: The code block to write initialisation code to.
9999
void initialize(const exprt &lhs, const exprt &depth, code_blockt &body);
100100

101-
/// Get the `free` function as symbol expression, and inserts it into the
102-
/// goto-model if it doesn't exist already.
103-
/// \return the symbol expression for the `free` function
104-
symbol_exprt get_free_function();
105-
106101
static bool is_initialization_allowed(const symbolt &symbol)
107102
{
108103
auto const symbol_name = id2string(symbol.name);
@@ -125,11 +120,6 @@ class recursive_initializationt
125120
type_constructor_namest type_constructor_names;
126121
std::vector<std::optional<exprt>> common_arguments_origins;
127122

128-
/// Get the malloc function as symbol exprt,
129-
/// and inserts it into the goto-model if it doesn't
130-
/// exist already.
131-
symbol_exprt get_malloc_function();
132-
133123
bool should_be_treated_as_array(const irep_idt &pointer_name) const;
134124
std::optional<equal_cluster_idt>
135125
find_equal_cluster(const irep_idt &name) const;
@@ -275,6 +265,10 @@ class recursive_initializationt
275265
const exprt &depth,
276266
code_blockt &body,
277267
const std::vector<irep_idt> &selection_spec);
268+
269+
/// Generate code mimicking __CPROVER_deallocate (which is what C's free
270+
/// calls) with \p pointer as argument.
271+
code_blockt deallocate_code(const exprt &pointer) const;
278272
};
279273

280274
#endif // CPROVER_GOTO_HARNESS_RECURSIVE_INITIALIZATION_H

0 commit comments

Comments
 (0)