Skip to content

Commit 550e6ab

Browse files
committed
Only apply tree limit to recursive struct
Now the depth limit only applies to structs if we have seen this struct before (i.e. the initialisation chain is recursive)
1 parent 5ce492c commit 550e6ab

File tree

5 files changed

+113
-19
lines changed

5 files changed

+113
-19
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct A A;
5+
typedef struct B B;
6+
typedef struct C C;
7+
typedef struct D D;
8+
9+
struct A
10+
{
11+
B *b;
12+
};
13+
14+
struct B
15+
{
16+
C *c;
17+
};
18+
19+
struct C
20+
{
21+
D *d;
22+
};
23+
24+
struct D
25+
{
26+
A *a;
27+
};
28+
29+
void func(A *a)
30+
{
31+
assert(a != NULL);
32+
assert(a->b != NULL);
33+
assert(a->b->c != NULL);
34+
assert(a->b->c->d != NULL);
35+
assert(a->b->c->d->a == NULL);
36+
}
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 1 --harness-type call-function
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
^warning: ignoring

src/goto-harness/function_call_harness_generator.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Author: Diffblue Ltd.
1515
#include <util/exception_utils.h>
1616
#include <util/std_code.h>
1717
#include <util/std_expr.h>
18+
#include <util/string2int.h>
1819
#include <util/ui_message.h>
1920

2021
#include "function_harness_generator_options.h"
@@ -79,14 +80,34 @@ void function_call_harness_generatort::handle_option(
7980
else if(option == FUNCTION_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT)
8081
{
8182
auto const value = require_exactly_one_value(option, values);
82-
p_impl->recursive_initialization_config.min_null_tree_depth =
83-
std::stoul(value);
83+
auto const min_null_tree_depth = string2optional<std::size_t>(value, 10);
84+
if(min_null_tree_depth.has_value())
85+
{
86+
p_impl->recursive_initialization_config.min_null_tree_depth =
87+
min_null_tree_depth.value();
88+
}
89+
else
90+
{
91+
throw invalid_command_line_argument_exceptiont{
92+
"failed to convert `" + value + "' to integer",
93+
"--" FUNCTION_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT};
94+
}
8495
}
8596
else if(option == FUNCTION_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT)
8697
{
8798
auto const value = require_exactly_one_value(option, values);
88-
p_impl->recursive_initialization_config.max_nondet_tree_depth =
89-
std::stoul(value);
99+
auto const max_nondet_tree_depth = string2optional<std::size_t>(value, 10);
100+
if(max_nondet_tree_depth.has_value())
101+
{
102+
p_impl->recursive_initialization_config.max_nondet_tree_depth =
103+
max_nondet_tree_depth.value();
104+
}
105+
else
106+
{
107+
throw invalid_command_line_argument_exceptiont{
108+
"failed to convert `" + value + "' to integer",
109+
"--" FUNCTION_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT};
110+
}
90111
}
91112
else
92113
{
@@ -176,7 +197,7 @@ void function_call_harness_generatort::implt::generate_initialisation_code_for(
176197
code_blockt &block,
177198
const exprt &lhs)
178199
{
179-
recursive_initialization->initialize(lhs, 0, block);
200+
recursive_initialization->initialize(lhs, 0, {}, block);
180201
}
181202

182203
void function_call_harness_generatort::validate_options()

src/goto-harness/recursive_initialization.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,21 @@ recursive_initializationt::recursive_initializationt(
2626
void recursive_initializationt::initialize(
2727
const exprt &lhs,
2828
std::size_t depth,
29+
const recursion_sett &known_tags,
2930
code_blockt &body)
3031
{
3132
auto const &type = lhs.type();
3233
if(type.id() == ID_struct_tag)
3334
{
34-
initialize_struct_tag(lhs, depth, body);
35+
initialize_struct_tag(lhs, depth, known_tags, body);
3536
}
3637
else if(type.id() == ID_pointer)
3738
{
38-
initialize_pointer(lhs, depth, body);
39+
initialize_pointer(lhs, depth, known_tags, body);
3940
}
4041
else
4142
{
42-
initialize_nondet(lhs, depth, body);
43+
initialize_nondet(lhs, depth, known_tags, body);
4344
}
4445
}
4546

@@ -64,20 +65,24 @@ symbol_exprt recursive_initializationt::get_malloc_function()
6465
void recursive_initializationt::initialize_struct_tag(
6566
const exprt &lhs,
6667
std::size_t depth,
68+
const recursion_sett &known_tags,
6769
code_blockt &body)
6870
{
6971
PRECONDITION(lhs.type().id() == ID_struct_tag);
7072
auto const &type = to_struct_tag_type(lhs.type());
73+
auto new_known_tags = known_tags;
74+
new_known_tags.insert(type.get_identifier());
7175
auto const &ns = namespacet{goto_model.symbol_table};
7276
for(auto const &component : ns.follow_tag(type).components())
7377
{
74-
initialize(member_exprt{lhs, component}, depth, body);
78+
initialize(member_exprt{lhs, component}, depth, new_known_tags, body);
7579
}
7680
}
7781

7882
void recursive_initializationt::initialize_pointer(
7983
const exprt &lhs,
8084
std::size_t depth,
85+
const recursion_sett &known_tags,
8186
code_blockt &body)
8287
{
8388
PRECONDITION(lhs.type().id() == ID_pointer);
@@ -92,17 +97,24 @@ void recursive_initializationt::initialize_pointer(
9297
allocate_objects.allocate_automatic_local_object(type.subtype(), "pointee");
9398
allocate_objects.declare_created_symbols(body);
9499
body.add(code_assignt{lhs, null_pointer_exprt{type}});
95-
if(depth < initialization_config.max_nondet_tree_depth)
100+
bool is_unknown_struct_tag =
101+
can_cast_type<tag_typet>(type.subtype()) &&
102+
known_tags.find(to_tag_type(type.subtype()).get_identifier()) ==
103+
known_tags.end();
104+
105+
if(
106+
depth < initialization_config.max_nondet_tree_depth ||
107+
is_unknown_struct_tag)
96108
{
97109
if(depth < initialization_config.min_null_tree_depth)
98110
{
99-
initialize(pointee, depth + 1, body);
111+
initialize(pointee, depth + 1, known_tags, body);
100112
body.add(code_assignt{lhs, address_of_exprt{pointee}});
101113
}
102114
else
103115
{
104116
code_blockt then_case{};
105-
initialize(pointee, depth + 1, then_case);
117+
initialize(pointee, depth + 1, known_tags, then_case);
106118
then_case.add(code_assignt{lhs, address_of_exprt{pointee}});
107119
body.add(code_ifthenelset{choice, then_case});
108120
}
@@ -112,6 +124,7 @@ void recursive_initializationt::initialize_pointer(
112124
void recursive_initializationt::initialize_nondet(
113125
const exprt &lhs,
114126
std::size_t depth,
127+
const recursion_sett &known_tags,
115128
code_blockt &body)
116129
{
117130
body.add(code_assignt{lhs, side_effect_expr_nondett{lhs.type()}});

src/goto-harness/recursive_initialization.h

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,22 @@ struct recursive_initialization_configt
2828
class recursive_initializationt
2929
{
3030
public:
31+
using recursion_sett = std::set<irep_idt>;
32+
3133
recursive_initializationt(
3234
recursive_initialization_configt initialization_config,
3335
goto_modelt &goto_model);
3436

3537
/// Generate initialisation code for lhs into body.
3638
/// \param lhs: The expression to initialise.
3739
/// \param depth: The number of pointer follows. Starts at 0.
40+
/// \param known_tags: The struct tags we've already seen during recursion.
3841
/// \param body: The code block to write initialisation code to.
39-
void initialize(const exprt &lhs, std::size_t depth, code_blockt &body);
42+
void initialize(
43+
const exprt &lhs,
44+
std::size_t depth,
45+
const recursion_sett &known_tags,
46+
code_blockt &body);
4047

4148
private:
4249
const recursive_initialization_configt initialization_config;
@@ -47,12 +54,21 @@ class recursive_initializationt
4754
/// exist already.
4855
symbol_exprt get_malloc_function();
4956

50-
void
51-
initialize_struct_tag(const exprt &lhs, std::size_t depth, code_blockt &body);
52-
void
53-
initialize_pointer(const exprt &lhs, std::size_t depth, code_blockt &body);
54-
void
55-
initialize_nondet(const exprt &lhs, std::size_t depth, code_blockt &body);
57+
void initialize_struct_tag(
58+
const exprt &lhs,
59+
std::size_t depth,
60+
const recursion_sett &known_tags,
61+
code_blockt &body);
62+
void initialize_pointer(
63+
const exprt &lhs,
64+
std::size_t depth,
65+
const recursion_sett &known_tags,
66+
code_blockt &body);
67+
void initialize_nondet(
68+
const exprt &lhs,
69+
std::size_t depth,
70+
const recursion_sett &known_tags,
71+
code_blockt &body);
5672
};
5773

5874
#endif // CPROVER_GOTO_HARNESS_RECURSIVE_INITIALIZATION_H

0 commit comments

Comments
 (0)