Skip to content

Commit dcf0ea3

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 dcf0ea3

File tree

6 files changed

+117
-21
lines changed

6 files changed

+117
-21
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: 63 additions & 19 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
@@ -802,23 +822,47 @@ bool recursive_initializationt::needs_freeing(const exprt &expr) const
802822
{
803823
if(expr.type().id() != ID_pointer || expr.type().id() == ID_code)
804824
return false;
805-
if(expr.id() == ID_symbol)
825+
else
826+
return true;
827+
}
828+
829+
void recursive_initializationt::free_if_possible(
830+
const exprt &expr,
831+
code_blockt &body)
832+
{
833+
PRECONDITION(expr.id() == ID_symbol);
834+
const auto expr_id = to_symbol_expr(expr).get_identifier();
835+
const auto maybe_cluster_index = find_equal_cluster(expr_id);
836+
const auto call_free = code_function_callt{get_free_function(), {expr}};
837+
if(!maybe_cluster_index.has_value())
806838
{
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-
}
839+
// not in any equality cluster -> just free
840+
body.add(call_free);
841+
return;
842+
}
843+
844+
if(
845+
to_symbol_expr(*common_arguments_origins[*maybe_cluster_index])
846+
.get_identifier() != expr_id &&
847+
initialization_config.arguments_may_be_equal)
848+
{
849+
// in equality cluster but not common origin -> free if equal to origin
850+
const auto condition =
851+
equal_exprt{expr, *common_arguments_origins[*maybe_cluster_index]};
852+
body.add(code_ifthenelset{condition, call_free});
853+
}
854+
else
855+
{
856+
// expr is common origin, leave freeing until the rest of the cluster is
857+
// freed
858+
return;
859+
}
860+
}
861+
862+
void recursive_initializationt::free_cluster_origins(code_blockt &body)
863+
{
864+
for(auto const &origin : common_arguments_origins)
865+
{
866+
body.add(code_function_callt{get_free_function(), {*origin}});
822867
}
823-
return true;
824868
}

src/goto-harness/recursive_initialization.h

Lines changed: 4 additions & 0 deletions
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
@@ -83,6 +85,8 @@ class recursive_initializationt
8385
}
8486

8587
bool needs_freeing(const exprt &expr) const;
88+
void free_if_possible(const exprt &expr, code_blockt &body);
89+
void free_cluster_origins(code_blockt &body);
8690

8791
private:
8892
const recursive_initialization_configt initialization_config;

0 commit comments

Comments
 (0)