Skip to content

Commit feb3f50

Browse files
Initialise const values recursively.
Previously the `dump-c` output of recursive initialisation wouldn't work with types that have nested const things in them, such as pointer-to-const or array with constant elements.
1 parent 4dd0359 commit feb3f50

File tree

10 files changed

+122
-11
lines changed

10 files changed

+122
-11
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+
3+
void entry_point(const int x)
4+
{
5+
// expected to succeed
6+
assert(x - x == 0);
7+
8+
// expected to fail
9+
assert(x != 13);
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
test.c
3+
--function entry_point --harness-type call-function
4+
\[entry_point.assertion.1\] line \d+ assertion x - x == 0: SUCCESS
5+
\[entry_point.assertion.2\] line \d+ assertion x != 13: FAILURE
6+
^EXIT=10$
7+
^SIGNAL=0$
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdlib.h>
2+
3+
struct SomeStruct
4+
{
5+
int x;
6+
};
7+
8+
void entry_point(const struct SomeStruct value)
9+
{
10+
assert(value.x - value.x == 0);
11+
assert(value.x != 13);
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
test.c
3+
--function entry_point --harness-type call-function
4+
\[entry_point.assertion.1\] line \d+ assertion value.x - value.x == 0: SUCCESS
5+
\[entry_point.assertion.2\] line \d+ assertion value.x != 13: FAILURE
6+
^EXIT=10$
7+
^SIGNAL=0$
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void entry_point(const int *x)
5+
{
6+
if(x != NULL)
7+
{
8+
assert(*x - *x == 0);
9+
}
10+
// expected to fail because we should get non-null pointers
11+
assert(x == NULL);
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
test.c
3+
--function entry_point --harness-type call-function
4+
\[entry_point.assertion.1\] line \d+ assertion \*x - \*x == 0: SUCCESS
5+
\[entry_point.assertion.2\] line \d+ assertion x == .*: FAILURE
6+
^EXIT=10$
7+
^SIGNAL=0$
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <assert.h>
2+
3+
struct SomeStruct
4+
{
5+
const int x;
6+
};
7+
8+
void entry_point(struct SomeStruct value)
9+
{
10+
// expected to succeed
11+
assert(value.x - value.x == 0);
12+
13+
// expected to fail
14+
assert(value.x != 13);
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
test.c
3+
--function entry_point --harness-type call-function
4+
\[entry_point.assertion.1\] line \d+ assertion value.x - value.x == 0: SUCCESS
5+
\[entry_point.assertion.2\] line \d+ assertion value.x != 13: FAILURE
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
--
9+
--
10+
Note that the generated C code has a bug - the constant field actually isn't constant in CBMC.
11+
This is a bug that gets introduced somewhere in the C frontend, so we have no way of fixing this
12+
over here, but this test may have to be revisited once this has been resolved.

src/goto-harness/function_call_harness_generator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ function_call_harness_generatort::implt::declare_arguments(
478478
for(const auto &parameter : parameters)
479479
{
480480
auto argument = allocate_objects.allocate_automatic_local_object(
481-
parameter.type(), parameter.get_base_name());
481+
remove_const(parameter.type()), parameter.get_base_name());
482482
parameter_name_to_argument_name.insert(
483483
{parameter.get_base_name(), argument.get_identifier()});
484484
arguments.push_back(argument);

src/goto-harness/recursive_initialization.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -690,12 +690,17 @@ code_blockt recursive_initializationt::build_pointer_constructor(
690690
seen_assign_prev = code_assignt{*has_seen, has_seen_prev};
691691
}
692692

693-
const symbol_exprt &local_result =
694-
get_fresh_local_typed_symexpr("local_result", type, nullptr_expr);
693+
// we want to initialize the pointee as non-const even for pointer to const
694+
const typet non_const_pointer_type =
695+
pointer_type(remove_const(type.subtype()));
696+
const symbol_exprt &local_result = get_fresh_local_typed_symexpr(
697+
"local_result", non_const_pointer_type, nullptr_expr);
695698
then_case.add(code_declt{local_result});
696699
const namespacet ns{goto_model.symbol_table};
697-
then_case.add(code_function_callt{
698-
local_result, get_malloc_function(), {*size_of_expr(type.subtype(), ns)}});
700+
then_case.add(
701+
code_function_callt{local_result,
702+
get_malloc_function(),
703+
{*size_of_expr(non_const_pointer_type.subtype(), ns)}});
699704
initialize(
700705
dereference_exprt{local_result},
701706
plus_exprt{depth, from_integer(1, depth.type())},
@@ -774,7 +779,28 @@ code_blockt recursive_initializationt::build_struct_constructor(
774779
for(const auto &component :
775780
ns.follow_tag(to_struct_tag_type(struct_type)).components())
776781
{
777-
initialize(member_exprt{dereference_exprt{result}, component}, depth, body);
782+
if(component.get_is_padding())
783+
{
784+
continue;
785+
}
786+
// if the struct component is const we need to cast away the const
787+
// for initialisation purposes.
788+
// As far as I'm aware that's the closest thing to a 'correct' way
789+
// to initialize dynamically allocated structs with const components
790+
exprt component_initialisation_lhs = [&result, &component]() -> exprt {
791+
auto member_expr = member_exprt{dereference_exprt{result}, component};
792+
if(component.type().get_bool(ID_C_constant))
793+
{
794+
return dereference_exprt{
795+
typecast_exprt{address_of_exprt{std::move(member_expr)},
796+
pointer_type(remove_const(component.type()))}};
797+
}
798+
else
799+
{
800+
return std::move(member_expr);
801+
}
802+
}();
803+
initialize(component_initialisation_lhs, depth, body);
778804
}
779805
return body;
780806
}
@@ -797,9 +823,9 @@ code_blockt recursive_initializationt::build_dynamic_array_constructor(
797823
const optionalt<irep_idt> &lhs_name)
798824
{
799825
PRECONDITION(result.type().id() == ID_pointer);
800-
const typet &pointer_type = result.type().subtype();
801-
PRECONDITION(pointer_type.id() == ID_pointer);
802-
const typet &element_type = pointer_type.subtype();
826+
const typet &dynamic_array_type = result.type().subtype();
827+
PRECONDITION(dynamic_array_type.id() == ID_pointer);
828+
const typet &element_type = dynamic_array_type.subtype();
803829
PRECONDITION(element_type.id() != ID_empty);
804830

805831
// builds:
@@ -831,8 +857,11 @@ code_blockt recursive_initializationt::build_dynamic_array_constructor(
831857
binary_relation_exprt{
832858
nondet_size, ID_le, from_integer(max_array_size, nondet_size.type())}}});
833859

834-
const symbol_exprt &local_result =
835-
get_fresh_local_typed_symexpr("local_result", pointer_type, exprt{});
860+
// we want the local result to be mutable so we can initialise it
861+
const typet mutable_dynamic_array_type =
862+
pointer_type(remove_const(element_type));
863+
const symbol_exprt &local_result = get_fresh_local_typed_symexpr(
864+
"local_result", mutable_dynamic_array_type, exprt{});
836865
body.add(code_declt{local_result});
837866
const namespacet ns{goto_model.symbol_table};
838867
for(auto array_size = min_array_size; array_size <= max_array_size;

0 commit comments

Comments
 (0)