Skip to content

Commit 49b86dc

Browse files
committed
Extend to allow conditional equality
between pointer arguments. Whether or not they will be equal is now a non-deterministic choice. Freeing pointer had to be extended.
1 parent 0040862 commit 49b86dc

File tree

6 files changed

+120
-26
lines changed

6 files changed

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

src/goto-harness/function_call_harness_generator.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ void function_call_harness_generatort::handle_option(
169169
p_impl->function_parameters_to_treat_as_cstrings.insert(
170170
values.begin(), values.end());
171171
}
172+
else if(option == FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_MAYBE_OPT)
173+
{
174+
p_impl->recursive_initialization_config.arguments_may_be_equal = true;
175+
}
172176
else
173177
{
174178
throw invalid_command_line_argument_exceptiont{
@@ -219,9 +223,9 @@ void function_call_harness_generatort::implt::generate(
219223
call_function(arguments, function_body);
220224
for(const auto &global_pointer : global_pointers)
221225
{
222-
function_body.add(code_function_callt{
223-
recursive_initialization->get_free_function(), {global_pointer}});
226+
recursive_initialization->free_if_possible(global_pointer, function_body);
224227
}
228+
recursive_initialization->free_cluster_origins(function_body);
225229
add_harness_function_to_goto_model(std::move(function_body));
226230
}
227231

src/goto-harness/function_harness_generator_options.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Author: Diffblue Ltd.
2121
"associated-array-size"
2222
#define FUNCTION_HARNESS_GENERATOR_TREAT_POINTER_AS_CSTRING \
2323
"treat-pointer-as-cstring"
24+
#define FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_MAYBE_OPT \
25+
"treat-pointers-equal-maybe"
2426

2527
// clang-format off
2628
#define FUNCTION_HARNESS_GENERATOR_OPTIONS \
@@ -30,6 +32,7 @@ Author: Diffblue Ltd.
3032
"(" FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_OPT "):" \
3133
"(" FUNCTION_HARNESS_GENERATOR_ASSOCIATED_ARRAY_SIZE_OPT "):" \
3234
"(" FUNCTION_HARNESS_GENERATOR_TREAT_POINTER_AS_CSTRING "):" \
35+
"(" FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_MAYBE_OPT ")" \
3336
// FUNCTION_HARNESS_GENERATOR_OPTIONS
3437

3538
// clang-format on
@@ -49,6 +52,8 @@ Author: Diffblue Ltd.
4952
"--" FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_OPT \
5053
" p,q,r[;s,t] treat the function parameters `q,r' equal\n" \
5154
" to parameter `p'; `s` to `t` and so on\n" \
55+
"--" FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_MAYBE_OPT \
56+
" function parameters equality is non-deterministic\n" \
5257
"--" FUNCTION_HARNESS_GENERATOR_ASSOCIATED_ARRAY_SIZE_OPT \
5358
" array_name:size_name\n" \
5459
" set the parameter <size_name> to the size" \

src/goto-harness/recursive_initialization.cpp

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ void recursive_initializationt::initialize(
102102
const exprt &depth,
103103
code_blockt &body)
104104
{
105+
// special handling for the case that pointer arguments should be treated
106+
// equal: if the equality is enforced (rather than the pointers may be equal),
107+
// then we don't even build the constructor functions
105108
if(lhs.id() == ID_symbol)
106109
{
107110
const auto maybe_cluster_index =
@@ -110,8 +113,25 @@ void recursive_initializationt::initialize(
110113
{
111114
if(common_arguments_origins[*maybe_cluster_index].has_value())
112115
{
113-
body.add(
114-
code_assignt{lhs, *common_arguments_origins[*maybe_cluster_index]});
116+
const auto set_equal_case =
117+
code_assignt{lhs, *common_arguments_origins[*maybe_cluster_index]};
118+
if(initialization_config.arguments_may_be_equal)
119+
{
120+
const irep_idt &fun_name = build_constructor(lhs);
121+
const symbolt &fun_symbol =
122+
goto_model.symbol_table.lookup_ref(fun_name);
123+
const auto proper_init_case = code_function_callt{
124+
fun_symbol.symbol_expr(), {depth, address_of_exprt{lhs}}};
125+
126+
body.add(code_ifthenelset{
127+
side_effect_expr_nondett{bool_typet{}, source_locationt{}},
128+
set_equal_case,
129+
proper_init_case});
130+
}
131+
else
132+
{
133+
body.add(set_equal_case);
134+
}
115135
return;
116136
}
117137
else
@@ -301,10 +321,10 @@ bool recursive_initializationt::should_be_treated_as_array(
301321
initialization_config.pointers_to_treat_as_arrays.end();
302322
}
303323

304-
optionalt<std::size_t>
324+
optionalt<recursive_initializationt::equal_cluster_idt>
305325
recursive_initializationt::find_equal_cluster(const irep_idt &name) const
306326
{
307-
for(size_t index = 0;
327+
for(equal_cluster_idt index = 0;
308328
index != initialization_config.pointers_to_treat_equal.size();
309329
++index)
310330
{
@@ -800,25 +820,46 @@ code_blockt recursive_initializationt::build_dynamic_array_constructor(
800820

801821
bool recursive_initializationt::needs_freeing(const exprt &expr) const
802822
{
803-
if(expr.type().id() != ID_pointer || expr.type().id() == ID_code)
804-
return false;
805-
if(expr.id() == ID_symbol)
823+
return expr.type().id() == ID_pointer && expr.type().id() != ID_code;
824+
}
825+
826+
void recursive_initializationt::free_if_possible(
827+
const exprt &expr,
828+
code_blockt &body)
829+
{
830+
PRECONDITION(expr.id() == ID_symbol);
831+
const auto expr_id = to_symbol_expr(expr).get_identifier();
832+
const auto maybe_cluster_index = find_equal_cluster(expr_id);
833+
const auto call_free = code_function_callt{get_free_function(), {expr}};
834+
if(!maybe_cluster_index.has_value())
806835
{
807-
auto expr_name = to_symbol_expr(expr).get_identifier();
808-
if(find_equal_cluster(expr_name).has_value())
809-
{
810-
for(auto const &origin_expr : common_arguments_origins)
811-
{
812-
if(!origin_expr.has_value())
813-
continue;
814-
INVARIANT(
815-
origin_expr->id() == ID_symbol, "common origin is not a symbol");
816-
auto origin_name = to_symbol_expr(*origin_expr).get_identifier();
817-
if(origin_name == expr_name)
818-
return true;
819-
}
820-
return false;
821-
}
836+
// not in any equality cluster -> just free
837+
body.add(call_free);
838+
return;
839+
}
840+
841+
if(
842+
to_symbol_expr(*common_arguments_origins[*maybe_cluster_index])
843+
.get_identifier() != expr_id &&
844+
initialization_config.arguments_may_be_equal)
845+
{
846+
// in equality cluster but not common origin -> free if not equal to origin
847+
const auto condition =
848+
notequal_exprt{expr, *common_arguments_origins[*maybe_cluster_index]};
849+
body.add(code_ifthenelset{condition, call_free});
850+
}
851+
else
852+
{
853+
// expr is common origin, leave freeing until the rest of the cluster is
854+
// freed
855+
return;
856+
}
857+
}
858+
859+
void recursive_initializationt::free_cluster_origins(code_blockt &body)
860+
{
861+
for(auto const &origin : common_arguments_origins)
862+
{
863+
body.add(code_function_callt{get_free_function(), {*origin}});
822864
}
823-
return true;
824865
}

src/goto-harness/recursive_initialization.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ struct recursive_initialization_configt
3939
std::set<irep_idt> pointers_to_treat_as_cstrings;
4040
std::vector<std::set<irep_idt>> pointers_to_treat_equal;
4141

42+
bool arguments_may_be_equal = false;
43+
4244
std::string to_string() const; // for debugging purposes
4345

4446
/// Parse the options specific for recursive initialisation
@@ -58,6 +60,7 @@ class recursive_initializationt
5860
public:
5961
using recursion_sett = std::set<irep_idt>;
6062
using type_constructor_namest = std::map<typet, irep_idt>;
63+
using equal_cluster_idt = std::size_t;
6164

6265
recursive_initializationt(
6366
recursive_initialization_configt initialization_config,
@@ -83,6 +86,8 @@ class recursive_initializationt
8386
}
8487

8588
bool needs_freeing(const exprt &expr) const;
89+
void free_if_possible(const exprt &expr, code_blockt &body);
90+
void free_cluster_origins(code_blockt &body);
8691

8792
private:
8893
const recursive_initialization_configt initialization_config;
@@ -98,7 +103,7 @@ class recursive_initializationt
98103
symbol_exprt get_malloc_function();
99104

100105
bool should_be_treated_as_array(const irep_idt &pointer_name) const;
101-
optionalt<std::size_t> find_equal_cluster(const irep_idt &name) const;
106+
optionalt<equal_cluster_idt> find_equal_cluster(const irep_idt &name) const;
102107
bool is_array_size_parameter(const irep_idt &cmdline_arg) const;
103108
optionalt<irep_idt>
104109
get_associated_size_variable(const irep_idt &array_name) const;

0 commit comments

Comments
 (0)