Skip to content

Commit 65bfa60

Browse files
committed
Extend to support multiple members for havocing
via a comma-separated list. Plus one more test.
1 parent d005873 commit 65bfa60

File tree

6 files changed

+103
-34
lines changed

6 files changed

+103
-34
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st1
5+
{
6+
int data11;
7+
struct innert1
8+
{
9+
int inner_data11;
10+
int inner_data12;
11+
} inner1;
12+
int data12;
13+
} st1_t;
14+
15+
typedef struct st2
16+
{
17+
int data21;
18+
struct innert2
19+
{
20+
int inner_data21;
21+
int inner_data22;
22+
} inner2;
23+
int data22;
24+
} st2_t;
25+
26+
st1_t dummy1 = {.data11 = 0,
27+
.inner1.inner_data11 = 0,
28+
.inner1.inner_data12 = 0,
29+
.data12 = 0};
30+
31+
st2_t dummy2 = {.data21 = 0,
32+
.inner2.inner_data21 = 0,
33+
.inner2.inner_data22 = 0,
34+
.data22 = 0};
35+
36+
void func(st1_t *p)
37+
{
38+
assert(dummy1.data11 == 0); //should succeed
39+
assert(dummy1.inner1.inner_data11 == 0);
40+
assert(dummy1.inner1.inner_data12 == 0); //should fail
41+
assert(dummy1.data12 == 0);
42+
assert(dummy2.data21 == 0); //should succeed
43+
assert(dummy2.inner2.inner_data21 == 0); //should fail
44+
assert(dummy2.inner2.inner_data22 == 0);
45+
assert(dummy2.data22 == 0);
46+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--function func --min-null-tree-depth 10 --max-nondet-tree-depth 3 --harness-type call-function --havoc-member 'dummy1.inner1.inner_data12,dummy2.inner2.inner_data21' --nondet-globals
4+
^\[func.assertion.\d+\] line \d+ assertion dummy1.data11 == 0: SUCCESS$
5+
^\[func.assertion.\d+\] line \d+ assertion dummy1.inner1.inner_data11 == 0: SUCCESS$
6+
^\[func.assertion.\d+\] line \d+ assertion dummy1.inner1.inner_data12 == 0: FAILURE$
7+
^\[func.assertion.\d+\] line \d+ assertion dummy1.data12 == 0: SUCCESS$
8+
^\[func.assertion.\d+\] line \d+ assertion dummy2.inner2.inner_data21 == 0: FAILURE$
9+
^EXIT=10$
10+
^SIGNAL=0$
11+
VERIFICATION FAILED
12+
--
13+
^warning: ignoring

regression/goto-harness/select-struct-member-to-havoc/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CORE
22
main.c
3-
--function func --min-null-tree-depth 10 --max-nondet-tree-depth 3 --harness-type call-function --member-selection 'dummy.inner.inner_data2' --nondet-globals
3+
--function func --min-null-tree-depth 10 --max-nondet-tree-depth 3 --harness-type call-function --havoc-member 'dummy.inner.inner_data2' --nondet-globals
44
^\[func.assertion.\d+\] line \d+ assertion dummy.data1 == 0: SUCCESS$
55
^\[func.assertion.\d+\] line \d+ assertion dummy.inner.inner_data1 == 0: SUCCESS$
66
^\[func.assertion.\d+\] line \d+ assertion dummy.inner.inner_data2 == 0: FAILURE$

src/goto-harness/common_harness_generator_options.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Author: Diffblue Ltd.
1616
#define COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT "max-array-size"
1717
#define COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT \
1818
"function-pointer-can-be-null"
19-
#define COMMON_HARNESS_GENERATOR_MEMBER_SELECTION_OPT "member-selection"
19+
#define COMMON_HARNESS_GENERATOR_HAVOC_MEMBER_OPT "havoc-member"
2020

2121
// clang-format off
2222
#define COMMON_HARNESS_GENERATOR_OPTIONS \
@@ -25,7 +25,7 @@ Author: Diffblue Ltd.
2525
"(" COMMON_HARNESS_GENERATOR_MIN_ARRAY_SIZE_OPT "):" \
2626
"(" COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT "):" \
2727
"(" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT "):" \
28-
"(" COMMON_HARNESS_GENERATOR_MEMBER_SELECTION_OPT "):" \
28+
"(" COMMON_HARNESS_GENERATOR_HAVOC_MEMBER_OPT "):" \
2929
// COMMON_HARNESS_GENERATOR_OPTIONS
3030

3131
// clang-format on
@@ -47,7 +47,7 @@ Author: Diffblue Ltd.
4747
"--" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT \
4848
" <function-name>, name of the function(s) pointer parameters\n" \
4949
" that can be NULL pointing." \
50-
"--" COMMON_HARNESS_GENERATOR_MEMBER_SELECTION_OPT \
50+
"--" COMMON_HARNESS_GENERATOR_HAVOC_MEMBER_OPT \
5151
" path to the member to be havoced\n" \
5252
// COMMON_HARNESS_GENERATOR_HELP
5353

src/goto-harness/recursive_initialization.cpp

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -87,20 +87,26 @@ bool recursive_initialization_configt::handle_option(
8787
[](const std::string &opt) -> irep_idt { return irep_idt{opt}; });
8888
return true;
8989
}
90-
else if(option == COMMON_HARNESS_GENERATOR_MEMBER_SELECTION_OPT)
90+
else if(option == COMMON_HARNESS_GENERATOR_HAVOC_MEMBER_OPT)
9191
{
92-
auto selection_spec_strings = split_string(
92+
const auto list_of_members_string =
9393
harness_options_parser::require_exactly_one_value(
94-
COMMON_HARNESS_GENERATOR_MEMBER_SELECTION_OPT, values),
95-
'.');
96-
97-
std::transform(
98-
selection_spec_strings.begin(),
99-
selection_spec_strings.end(),
100-
std::back_inserter(selection_spec),
101-
[](const std::string &member_name_string) {
102-
return irep_idt{member_name_string};
103-
});
94+
COMMON_HARNESS_GENERATOR_HAVOC_MEMBER_OPT, values);
95+
const auto list_of_members = split_string(list_of_members_string, ',');
96+
for(const auto &member : list_of_members)
97+
{
98+
const auto selection_spec_strings = split_string(member, '.');
99+
100+
selection_specs.push_back({});
101+
auto &selection_spec = selection_specs.back();
102+
std::transform(
103+
selection_spec_strings.begin(),
104+
selection_spec_strings.end(),
105+
std::back_inserter(selection_spec),
106+
[](const std::string &member_name_string) {
107+
return irep_idt{member_name_string};
108+
});
109+
}
104110
return true;
105111
}
106112
return false;
@@ -131,20 +137,22 @@ void recursive_initializationt::initialize(
131137
const exprt &depth,
132138
code_blockt &body)
133139
{
134-
if(
135-
lhs.id() == ID_symbol && !initialization_config.selection_spec.empty() &&
136-
initialization_config.selection_spec.front() ==
137-
to_symbol_expr(lhs).get_identifier())
140+
if(lhs.id() == ID_symbol && !initialization_config.selection_specs.empty())
138141
{
139-
initialize_selected_member(lhs, depth, body);
140-
return;
142+
auto lhs_id = to_symbol_expr(lhs).get_identifier();
143+
for(const auto &selection_spec : initialization_config.selection_specs)
144+
{
145+
if(selection_spec.front() == lhs_id)
146+
{
147+
initialize_selected_member(lhs, depth, body, selection_spec);
148+
return;
149+
}
150+
}
141151
}
142152
// special handling for the case that pointer arguments should be treated
143153
// equal: if the equality is enforced (rather than the pointers may be equal),
144154
// then we don't even build the constructor functions
145-
if(
146-
lhs.id() == ID_symbol &&
147-
should_be_treated_equal(to_symbol_expr(lhs).get_identifier()))
155+
if(lhs.id() == ID_symbol)
148156
{
149157
const auto maybe_cluster_index =
150158
find_equal_cluster(to_symbol_expr(lhs).get_identifier());
@@ -987,24 +995,23 @@ code_blockt recursive_initializationt::build_function_pointer_constructor(
987995
void recursive_initializationt::initialize_selected_member(
988996
const exprt &lhs,
989997
const exprt &depth,
990-
code_blockt &body)
998+
code_blockt &body,
999+
const std::vector<irep_idt> &selection_spec)
9911000
{
9921001
PRECONDITION(lhs.id() == ID_symbol);
9931002
PRECONDITION(lhs.type().id() == ID_struct_tag);
994-
PRECONDITION(!initialization_config.selection_spec.empty());
1003+
PRECONDITION(!selection_spec.empty());
9951004

9961005
auto component_member = lhs;
9971006
const namespacet ns{goto_model.symbol_table};
9981007

999-
for(auto it = initialization_config.selection_spec.begin() + 1;
1000-
it != initialization_config.selection_spec.end();
1001-
it++)
1008+
for(auto it = selection_spec.begin() + 1; it != selection_spec.end(); it++)
10021009
{
10031010
if(component_member.type().id() != ID_struct_tag)
10041011
{
10051012
throw invalid_command_line_argument_exceptiont{
10061013
"'" + id2string(*it) + "' is not a component name",
1007-
"--" COMMON_HARNESS_GENERATOR_MEMBER_SELECTION_OPT};
1014+
"--" COMMON_HARNESS_GENERATOR_HAVOC_MEMBER_OPT};
10081015
}
10091016
const auto &struct_tag_type = to_struct_tag_type(component_member.type());
10101017
const auto &struct_type = to_struct_type(ns.follow_tag(struct_tag_type));
@@ -1027,7 +1034,7 @@ void recursive_initializationt::initialize_selected_member(
10271034
{
10281035
throw invalid_command_line_argument_exceptiont{
10291036
"'" + id2string(*it) + "' is not a component name",
1030-
"--" COMMON_HARNESS_GENERATOR_MEMBER_SELECTION_OPT};
1037+
"--" COMMON_HARNESS_GENERATOR_HAVOC_MEMBER_OPT};
10311038
}
10321039
}
10331040
initialize(component_member, depth, body);

src/goto-harness/recursive_initialization.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct recursive_initialization_configt
4242

4343
bool arguments_may_be_equal = false;
4444

45-
std::vector<irep_idt> selection_spec;
45+
std::vector<std::vector<irep_idt>> selection_specs;
4646

4747
std::string to_string() const; // for debugging purposes
4848

@@ -271,10 +271,13 @@ class recursive_initializationt
271271
/// \param lhs: symbol expression of the top structure
272272
/// \param depth: only to be passed
273273
/// \param body: code block for the initializing assignment
274+
/// \param selection_spec: the user specification of the particular member to
275+
/// havoc
274276
void initialize_selected_member(
275277
const exprt &lhs,
276278
const exprt &depth,
277-
code_blockt &body);
279+
code_blockt &body,
280+
const std::vector<irep_idt> &selection_spec);
278281
};
279282

280283
#endif // CPROVER_GOTO_HARNESS_RECURSIVE_INITIALIZATION_H

0 commit comments

Comments
 (0)