Skip to content

Commit 7eff3f5

Browse files
Add recursive initialisation of structs
Recursively initialise non-deterministically struct components and pointers. Co-authored-by: Fotis Koutoulakis <[email protected]> Co-authored-by: Hannes Steffenhagen <[email protected]>
1 parent 068a306 commit 7eff3f5

File tree

13 files changed

+356
-1
lines changed

13 files changed

+356
-1
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st1
5+
{
6+
struct st2 *to_st2;
7+
int data;
8+
} st1_t;
9+
10+
typedef struct st2
11+
{
12+
struct st1 *to_st1;
13+
int data;
14+
} st2_t;
15+
16+
st1_t dummy1;
17+
st2_t dummy2;
18+
19+
void func(st1_t *p)
20+
{
21+
assert(p != NULL);
22+
assert(p->to_st2 != NULL);
23+
assert(p->to_st2->to_st1 != NULL);
24+
assert(p->to_st2->to_st1->to_st2 == NULL);
25+
26+
assert(p != &dummy1);
27+
assert(p->to_st2 != &dummy2);
28+
assert(p->to_st2->to_st1 != &dummy1);
29+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--function func --min-null-tree-depth 10 --max-nondet-tree-depth 3 --harness-type call-function
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
^warning: ignoring
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st
5+
{
6+
int data;
7+
} st_t;
8+
9+
st_t dummy;
10+
11+
void func(st_t *p)
12+
{
13+
assert(p != NULL);
14+
assert(p != &dummy);
15+
assert(p->data >= 4854549);
16+
assert(p->data < 4854549);
17+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--function func --min-null-tree-depth 10 --harness-type call-function
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
\[func.assertion.1\] line [0-9]+ assertion p != .*((NULL)|0).*: SUCCESS
7+
\[func.assertion.2\] line [0-9]+ assertion p != &dummy: SUCCESS
8+
\[func.assertion.3\] line [0-9]+ assertion p->data >= 4854549: FAILURE
9+
\[func.assertion.4\] line [0-9]+ assertion p->data < 4854549: FAILURE
10+
--
11+
^warning: ignoring
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st
5+
{
6+
struct st *next;
7+
struct st *prev;
8+
int data;
9+
} st_t;
10+
11+
st_t dummy;
12+
13+
void func(st_t *p)
14+
{
15+
assert(p != NULL);
16+
assert(p != &dummy);
17+
18+
assert(p->prev != NULL);
19+
assert(p->prev != &dummy);
20+
21+
assert(p->next != NULL);
22+
assert(p->next != &dummy);
23+
24+
assert(p->prev->prev == NULL);
25+
assert(p->prev->next == NULL);
26+
assert(p->next->prev == NULL);
27+
assert(p->next->next == NULL);
28+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--function func --min-null-tree-depth 10 --max-nondet-tree-depth 2 --harness-type call-function
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
^warning: ignoring
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st
5+
{
6+
struct st *next;
7+
int data;
8+
} st_t;
9+
10+
st_t dummy;
11+
12+
void func(st_t *p)
13+
{
14+
assert(p != NULL);
15+
assert(p->next != NULL);
16+
assert(p->next->next != NULL);
17+
assert(p->next->next->next == NULL);
18+
19+
assert(p != &dummy);
20+
assert(p->next != &dummy);
21+
assert(p->next->next != &dummy);
22+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--function func --min-null-tree-depth 10 --max-nondet-tree-depth 3 --harness-type call-function
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
^warning: ignoring

src/goto-harness/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ SRC = \
44
goto_harness_generator_factory.cpp \
55
goto_harness_main.cpp \
66
goto_harness_parse_options.cpp \
7+
recursive_initialization.cpp \
78
# Empty last line
89

910
OBJ += \

src/goto-harness/function_call_harness_generator.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Author: Diffblue Ltd.
1919

2020
#include "function_harness_generator_options.h"
2121
#include "goto_harness_parse_options.h"
22+
#include "recursive_initialization.h"
2223

2324
/// This contains implementation details of
2425
/// function call harness generator to avoid
@@ -33,6 +34,9 @@ struct function_call_harness_generatort::implt
3334
goto_functionst *goto_functions;
3435
bool nondet_globals = false;
3536

37+
recursive_initialization_configt recursive_initialization_config;
38+
std::unique_ptr<recursive_initializationt> recursive_initialization;
39+
3640
/// \see goto_harness_generatort::generate
3741
void generate(goto_modelt &goto_model, const irep_idt &harness_function_name);
3842
/// Iterate over the symbol table and generate initialisation code for
@@ -72,6 +76,18 @@ void function_call_harness_generatort::handle_option(
7276
{
7377
p_impl->nondet_globals = true;
7478
}
79+
else if(option == FUNCTION_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT)
80+
{
81+
auto const value = require_exactly_one_value(option, values);
82+
p_impl->recursive_initialization_config.min_null_tree_depth =
83+
std::stoul(value);
84+
}
85+
else if(option == FUNCTION_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT)
86+
{
87+
auto const value = require_exactly_one_value(option, values);
88+
p_impl->recursive_initialization_config.max_nondet_tree_depth =
89+
std::stoul(value);
90+
}
7591
else
7692
{
7793
throw invalid_command_line_argument_exceptiont{
@@ -123,6 +139,10 @@ void function_call_harness_generatort::implt::generate(
123139
{
124140
symbol_table = &goto_model.symbol_table;
125141
goto_functions = &goto_model.goto_functions;
142+
const auto &function_to_call = lookup_function_to_call();
143+
recursive_initialization_config.mode = function_to_call.mode;
144+
recursive_initialization = util_make_unique<recursive_initializationt>(
145+
recursive_initialization_config, goto_model, *message_handler);
126146
this->harness_function_name = harness_function_name;
127147
ensure_harness_does_not_already_exist();
128148

@@ -156,7 +176,7 @@ void function_call_harness_generatort::implt::generate_initialisation_code_for(
156176
code_blockt &block,
157177
const exprt &lhs)
158178
{
159-
block.add(code_assignt{lhs, side_effect_expr_nondett{lhs.type()}});
179+
recursive_initialization->initialize(lhs, 0, block);
160180
}
161181

162182
void function_call_harness_generatort::validate_options()

src/goto-harness/function_harness_generator_options.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ Author: Diffblue Ltd.
1111

1212
#define FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT "function"
1313
#define FUNCTION_HARNESS_GENERATOR_NONDET_GLOBALS_OPT "nondet-globals"
14+
#define FUNCTION_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT "min-null-tree-depth"
15+
#define FUNCTION_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT \
16+
"max-nondet-tree-depth"
1417

1518
// clang-format off
1619
#define FUNCTION_HARNESS_GENERATOR_OPTIONS \
1720
"(" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT "):" \
1821
"(" FUNCTION_HARNESS_GENERATOR_NONDET_GLOBALS_OPT ")" \
22+
"(" FUNCTION_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT "):" \
23+
"(" FUNCTION_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT "):" \
1924
// FUNCTION_HARNESS_GENERATOR_OPTIONS
2025

2126
// clang-format on
@@ -27,6 +32,12 @@ Author: Diffblue Ltd.
2732
" the function the harness should call\n" \
2833
"--" FUNCTION_HARNESS_GENERATOR_NONDET_GLOBALS_OPT \
2934
" set global variables to non-deterministic values in harness\n" \
35+
"--" FUNCTION_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT \
36+
" N minimum level at which a pointer can first be\n" \
37+
" NULL in a recursively nondet initialized struct\n" \
38+
"--" FUNCTION_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT \
39+
" N limit size of nondet (e.g. input) object tree;\n" \
40+
" at level N pointers are set to null\n" \
3041
// FUNCTION_HARNESS_GENERATOR_HELP
3142

3243
// clang-format on
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/******************************************************************\
2+
3+
Module: recursive_initialization
4+
5+
Author: Diffblue Ltd.
6+
7+
\******************************************************************/
8+
9+
#include "recursive_initialization.h"
10+
11+
#include <util/allocate_objects.h>
12+
#include <util/c_types.h>
13+
#include <util/fresh_symbol.h>
14+
#include <util/irep.h>
15+
#include <util/std_code.h>
16+
#include <util/std_expr.h>
17+
18+
recursive_initializationt::recursive_initializationt(
19+
recursive_initialization_configt initialization_config,
20+
goto_modelt &goto_model,
21+
message_handlert &message_handler)
22+
: initialization_config(std::move(initialization_config)),
23+
goto_model(goto_model),
24+
message_handler(message_handler)
25+
{
26+
}
27+
28+
void recursive_initializationt::initialize(
29+
const exprt &lhs,
30+
std::size_t depth,
31+
code_blockt &body)
32+
{
33+
auto const &type = lhs.type();
34+
if(type.id() == ID_struct_tag)
35+
{
36+
get_struct_tag_initializer(lhs, depth, body);
37+
}
38+
else if(type.id() == ID_pointer)
39+
{
40+
get_pointer_initializer(lhs, depth, body);
41+
}
42+
else
43+
{
44+
get_nondet_initializer(lhs, depth, body);
45+
}
46+
}
47+
48+
symbol_exprt recursive_initializationt::get_malloc_function()
49+
{
50+
// unused for now, we'll need it for arrays
51+
auto malloc_sym = goto_model.symbol_table.lookup("malloc");
52+
if(malloc_sym == nullptr)
53+
{
54+
symbolt new_malloc_sym;
55+
new_malloc_sym.type = code_typet{code_typet{
56+
{code_typet::parametert{size_type()}}, pointer_type(empty_typet{})}};
57+
new_malloc_sym.name = new_malloc_sym.pretty_name =
58+
new_malloc_sym.base_name = "malloc";
59+
new_malloc_sym.mode = initialization_config.mode;
60+
goto_model.symbol_table.insert(new_malloc_sym);
61+
return new_malloc_sym.symbol_expr();
62+
}
63+
return malloc_sym->symbol_expr();
64+
}
65+
66+
void recursive_initializationt::get_struct_tag_initializer(
67+
const exprt &lhs,
68+
std::size_t depth,
69+
code_blockt &body)
70+
{
71+
PRECONDITION(lhs.type().id() == ID_struct_tag);
72+
auto const &type = to_struct_tag_type(lhs.type());
73+
auto const &ns = namespacet{goto_model.symbol_table};
74+
for(auto const &component : ns.follow_tag(type).components())
75+
{
76+
initialize(member_exprt{lhs, component}, depth, body);
77+
}
78+
}
79+
80+
void recursive_initializationt::get_pointer_initializer(
81+
const exprt &lhs,
82+
std::size_t depth,
83+
code_blockt &body)
84+
{
85+
PRECONDITION(lhs.type().id() == ID_pointer);
86+
auto const &type = to_pointer_type(lhs.type());
87+
allocate_objectst allocate_objects{initialization_config.mode,
88+
type.source_location(),
89+
"initializer",
90+
goto_model.symbol_table};
91+
exprt choice;
92+
if(
93+
depth > initialization_config.min_null_tree_depth &&
94+
depth < initialization_config.max_nondet_tree_depth)
95+
{
96+
choice =
97+
allocate_objects.allocate_automatic_local_object(bool_typet{}, "choice");
98+
}
99+
auto pointee =
100+
allocate_objects.allocate_automatic_local_object(type.subtype(), "pointee");
101+
allocate_objects.declare_created_symbols(body);
102+
body.add(code_assignt{lhs, null_pointer_exprt{type}});
103+
auto const &ns = namespacet{goto_model.symbol_table};
104+
if(
105+
depth < initialization_config.min_null_tree_depth &&
106+
depth < initialization_config.max_nondet_tree_depth)
107+
{
108+
initialize(pointee, depth + 1, body);
109+
body.add(code_assignt{lhs, address_of_exprt{pointee}});
110+
}
111+
else if(depth < initialization_config.max_nondet_tree_depth)
112+
{
113+
code_blockt then_case{};
114+
initialize(pointee, depth + 1, then_case);
115+
then_case.add(code_assignt{lhs, address_of_exprt{pointee}});
116+
body.add(code_ifthenelset{choice, then_case});
117+
}
118+
}
119+
120+
void recursive_initializationt::get_nondet_initializer(
121+
const exprt &lhs,
122+
std::size_t depth,
123+
code_blockt &body)
124+
{
125+
body.add(code_assignt{lhs, side_effect_expr_nondett{lhs.type()}});
126+
}

0 commit comments

Comments
 (0)