Skip to content

Commit b025b32

Browse files
Petr BauchPetr Bauch
Petr Bauch
authored and
Petr Bauch
committed
Cumulative fix
Based on comments. Will be squashed.
1 parent f7846a3 commit b025b32

File tree

8 files changed

+162
-63
lines changed

8 files changed

+162
-63
lines changed

regression/snapshot-harness/pointer-to-array-char/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33
first,second,array_size --harness-type initialise-with-memory-snapshot --initial-location main:4
44
^SIGNAL=0$

regression/snapshot-harness/pointer-to-array-function-parameters-multi-arg-right/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33
first,second,string_size,prefix,prefix_size --harness-type initialise-with-memory-snapshot --initial-location main:4 --havoc-variables prefix,prefix_size --size-of-array prefix:prefix_size --max-array-size 5
44
^SIGNAL=0$

src/goto-harness/function_call_harness_generator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ void function_call_harness_generatort::handle_option(
9595

9696
if(p_impl->recursive_initialization_config.handle_option(option, values))
9797
{
98+
// the option belongs to recursive initialization
9899
}
99100
else if(option == FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT)
100101
{

src/goto-harness/memory_snapshot_harness_generator.cpp

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Author: Daniel Poetzl
2525

2626
#include <linking/static_lifetime_init.h>
2727

28+
#include <algorithm>
29+
2830
void memory_snapshot_harness_generatort::handle_option(
2931
const std::string &option,
3032
const std::list<std::string> &values)
@@ -33,6 +35,7 @@ void memory_snapshot_harness_generatort::handle_option(
3335
harness_options_parsert::require_exactly_one_value;
3436
if(recursive_initialization_config.handle_option(option, values))
3537
{
38+
// the option belongs to recursive initialization
3639
}
3740
else if(option == MEMORY_SNAPSHOT_HARNESS_TREAT_POINTER_AS_ARRAY_OPT)
3841
{
@@ -103,7 +106,12 @@ void memory_snapshot_harness_generatort::handle_option(
103106
}
104107
else if(option == MEMORY_SNAPSHOT_HARNESS_HAVOC_VARIABLES_OPT)
105108
{
106-
variables_to_havoc.insert(values.begin(), values.end());
109+
std::vector<std::string> havoc_candidates;
110+
split_string(values.front(), ',', havoc_candidates, true);
111+
for(const auto &candidate : havoc_candidates)
112+
{
113+
variables_to_havoc.insert(candidate);
114+
}
107115
}
108116
else
109117
{
@@ -256,20 +264,50 @@ const symbolt &memory_snapshot_harness_generatort::fresh_symbol_copy(
256264
snapshot_symbol.mode,
257265
symbol_table);
258266
tmp_symbol.is_static_lifetime = true;
267+
tmp_symbol.is_auxiliary = false;
259268
tmp_symbol.value = snapshot_symbol.value;
260269

261270
return tmp_symbol;
262271
}
263272

273+
size_t memory_snapshot_harness_generatort::pointer_depth(const typet &t) const
274+
{
275+
if(t.id() != ID_pointer)
276+
return 0;
277+
else
278+
return pointer_depth(t.subtype()) + 1;
279+
}
280+
264281
code_blockt memory_snapshot_harness_generatort::add_assignments_to_globals(
265282
const symbol_tablet &snapshot,
266283
goto_modelt &goto_model) const
267284
{
268285
recursive_initializationt recursive_initialization{
269286
recursive_initialization_config, goto_model};
270287

288+
using snapshot_pairt = std::pair<irep_idt, symbolt>;
289+
std::vector<snapshot_pairt> ordered_snapshot_symbols;
290+
for(auto pair : snapshot)
291+
{
292+
const auto name = id2string(pair.first);
293+
if(name.find(CPROVER_PREFIX) != 0)
294+
ordered_snapshot_symbols.push_back(pair);
295+
}
296+
297+
// sort the snapshot symbols so that the non-pointer symbols are first, then
298+
// pointers, then pointers-to-pointers, etc. so that we don't assign
299+
// uninitialized values
300+
std::stable_sort(
301+
ordered_snapshot_symbols.begin(),
302+
ordered_snapshot_symbols.end(),
303+
[this](const snapshot_pairt &left, const snapshot_pairt &right) {
304+
return pointer_depth(left.second.symbol_expr().type()) <
305+
pointer_depth(right.second.symbol_expr().type());
306+
});
307+
271308
code_blockt code;
272-
for(const auto &pair : snapshot)
309+
// for(const auto &pair : snapshot)
310+
for(const auto &pair : ordered_snapshot_symbols)
273311
{
274312
const symbolt &snapshot_symbol = pair.second;
275313
symbol_tablet &symbol_table = goto_model.symbol_table;

src/goto-harness/memory_snapshot_harness_generator.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ class memory_snapshot_harness_generatort : public goto_harness_generatort
138138
goto_modelt &goto_model,
139139
const symbolt &function) const;
140140

141+
/// Recursively compute the pointer depth
142+
/// \param t: input type
143+
/// \return pointer depth of type \p t
144+
size_t pointer_depth(const typet &t) const;
145+
141146
std::string memory_snapshot_file;
142147

143148
irep_idt entry_function_name;

src/goto-harness/recursive_initialization.cpp

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,59 @@ Author: Diffblue Ltd.
2020

2121
#include <functional>
2222

23+
bool recursive_initialization_configt::handle_option(
24+
const std::string &option,
25+
const std::list<std::string> &values)
26+
{
27+
if(option == COMMON_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT)
28+
{
29+
auto const value = require_exactly_one_value(option, values);
30+
auto const user_min_null_tree_depth =
31+
string2optional<std::size_t>(value, 10);
32+
if(user_min_null_tree_depth.has_value())
33+
{
34+
min_null_tree_depth = user_min_null_tree_depth.value();
35+
}
36+
else
37+
{
38+
throw invalid_command_line_argument_exceptiont{
39+
"failed to convert `" + value + "' to integer",
40+
"--" COMMON_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT};
41+
}
42+
return true;
43+
}
44+
else if(option == COMMON_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT)
45+
{
46+
auto const value = require_exactly_one_value(option, values);
47+
auto const user_max_nondet_tree_depth =
48+
string2optional<std::size_t>(value, 10);
49+
if(user_max_nondet_tree_depth.has_value())
50+
{
51+
max_nondet_tree_depth = user_max_nondet_tree_depth.value();
52+
}
53+
else
54+
{
55+
throw invalid_command_line_argument_exceptiont{
56+
"failed to convert `" + value + "' to integer",
57+
"--" COMMON_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT};
58+
}
59+
return true;
60+
}
61+
else if(option == COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT)
62+
{
63+
max_dynamic_array_size = require_one_size_value(
64+
COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT, values);
65+
return true;
66+
}
67+
else if(option == COMMON_HARNESS_GENERATOR_MIN_ARRAY_SIZE_OPT)
68+
{
69+
min_dynamic_array_size = require_one_size_value(
70+
COMMON_HARNESS_GENERATOR_MIN_ARRAY_SIZE_OPT, values);
71+
return true;
72+
}
73+
return false;
74+
}
75+
2376
recursive_initializationt::recursive_initializationt(
2477
recursive_initialization_configt initialization_config,
2578
goto_modelt &goto_model)
@@ -416,56 +469,3 @@ recursive_initializationt::cstring_member_initialization()
416469
}
417470
};
418471
}
419-
420-
bool recursive_initialization_configt::handle_option(
421-
const std::string &option,
422-
const std::list<std::string> &values)
423-
{
424-
if(option == COMMON_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT)
425-
{
426-
auto const value = require_exactly_one_value(option, values);
427-
auto const user_min_null_tree_depth =
428-
string2optional<std::size_t>(value, 10);
429-
if(user_min_null_tree_depth.has_value())
430-
{
431-
min_null_tree_depth = user_min_null_tree_depth.value();
432-
}
433-
else
434-
{
435-
throw invalid_command_line_argument_exceptiont{
436-
"failed to convert `" + value + "' to integer",
437-
"--" COMMON_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT};
438-
}
439-
return true;
440-
}
441-
else if(option == COMMON_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT)
442-
{
443-
auto const value = require_exactly_one_value(option, values);
444-
auto const user_max_nondet_tree_depth =
445-
string2optional<std::size_t>(value, 10);
446-
if(user_max_nondet_tree_depth.has_value())
447-
{
448-
max_nondet_tree_depth = user_max_nondet_tree_depth.value();
449-
}
450-
else
451-
{
452-
throw invalid_command_line_argument_exceptiont{
453-
"failed to convert `" + value + "' to integer",
454-
"--" COMMON_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT};
455-
}
456-
return true;
457-
}
458-
else if(option == COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT)
459-
{
460-
max_dynamic_array_size = require_one_size_value(
461-
COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT, values);
462-
return true;
463-
}
464-
else if(option == COMMON_HARNESS_GENERATOR_MIN_ARRAY_SIZE_OPT)
465-
{
466-
min_dynamic_array_size = require_one_size_value(
467-
COMMON_HARNESS_GENERATOR_MIN_ARRAY_SIZE_OPT, values);
468-
return true;
469-
}
470-
return false;
471-
}

src/goto-harness/recursive_initialization.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ struct recursive_initialization_configt : harness_options_parsert
3939

4040
std::string to_string() const; // for debugging purposes
4141

42+
/// Parse the options specific for recursive initialisation
43+
/// \param option: the user option name
44+
/// \param values: the (one-or-more) values for this option
45+
/// \return true if the option belonged to recursive initialisation and was
46+
/// successfully parsed here
4247
bool handle_option(
4348
const std::string &option,
4449
const std::list<std::string> &values);

src/memory-analyzer/analyze_symbol.cpp

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,13 @@ exprt symbol_analyzert::get_char_pointer_value(
186186

187187
values.insert(std::make_pair(memory_location, new_symbol));
188188

189+
// check that we are returning objects of the right type
190+
CHECK_RETURN(new_symbol.type().subtype() == expr.type().subtype());
189191
return new_symbol;
190192
}
191193
else
192194
{
195+
CHECK_RETURN(it->second.type().subtype() == expr.type().subtype());
193196
return it->second;
194197
}
195198
}
@@ -200,7 +203,6 @@ exprt symbol_analyzert::get_pointer_to_member_value(
200203
const source_locationt &location)
201204
{
202205
PRECONDITION(expr.type().id() == ID_pointer);
203-
PRECONDITION(!is_c_char(expr.type().subtype()));
204206
std::string memory_location = pointer_value.address;
205207
PRECONDITION(memory_location != "0x0");
206208
PRECONDITION(!pointer_value.pointee.empty());
@@ -221,14 +223,17 @@ exprt symbol_analyzert::get_pointer_to_member_value(
221223
}
222224

223225
const symbolt *struct_symbol = symbol_table.lookup(struct_name);
226+
224227
DATA_INVARIANT(struct_symbol != nullptr, "unknown struct");
225228

226229
const auto maybe_member_expr = get_subexpression_at_offset(
227230
struct_symbol->symbol_expr(), member_offset, expr.type().subtype(), ns);
228-
if(maybe_member_expr.has_value())
229-
return *maybe_member_expr;
231+
DATA_INVARIANT(
232+
maybe_member_expr.has_value(), "structure doesn't have member");
230233

231-
UNREACHABLE;
234+
// check that we return the right type
235+
CHECK_RETURN(maybe_member_expr->type() == expr.type().subtype());
236+
return *maybe_member_expr;
232237
}
233238

234239
exprt symbol_analyzert::get_non_char_pointer_value(
@@ -315,7 +320,44 @@ exprt symbol_analyzert::get_pointer_value(
315320
{
316321
if(is_c_char(expr.type().subtype()))
317322
{
318-
return get_char_pointer_value(expr, memory_location, location);
323+
// pointers-to-char can point to members as well, e.g. char[]
324+
if(points_to_member(value))
325+
{
326+
const auto target_expr =
327+
get_pointer_to_member_value(expr, value, location);
328+
if(target_expr.id() == ID_nil)
329+
{
330+
outstanding_assignments[expr] = memory_location;
331+
}
332+
else
333+
{
334+
const auto result_expr = address_of_exprt(target_expr);
335+
CHECK_RETURN(result_expr.type() == zero_expr.type());
336+
return result_expr;
337+
}
338+
}
339+
INVARIANT(
340+
!points_to_member(value),
341+
"pointers-to-char shouldn't point to members");
342+
const auto result_pointee_expr =
343+
get_char_pointer_value(expr, memory_location, location);
344+
345+
// the pointee was (probably) dynamically allocated (but the allocation
346+
// would not be visible in the snapshot) so we pretend it is statically
347+
// allocated (we have the value) and return address to the first element
348+
// of the array (instead of the array as char*)
349+
if(result_pointee_expr.type().id() == ID_array)
350+
{
351+
const auto result_indexed_expr = get_subexpression_at_offset(
352+
result_pointee_expr, 0, zero_expr.type().subtype(), ns);
353+
CHECK_RETURN(result_indexed_expr.has_value());
354+
const auto result_expr = address_of_exprt{*result_indexed_expr};
355+
return result_expr;
356+
}
357+
// cast to expected type to prevent symex assign check failing
358+
const auto maybe_cast_result =
359+
typecast_exprt::conditional_cast(result_pointee_expr, zero_expr.type());
360+
return maybe_cast_result;
319361
}
320362
else
321363
{
@@ -388,7 +430,15 @@ exprt symbol_analyzert::get_expr_value(
388430
{
389431
INVARIANT(zero_expr.is_constant(), "zero initializer is a constant");
390432

391-
return zero_expr; // currently left at 0
433+
// check the char-value and return as bitvector-type value
434+
std::string c_expr = c_converter.convert(expr);
435+
const std::string value = gdb_api.get_value(c_expr);
436+
437+
if(value.empty())
438+
return zero_expr;
439+
440+
const mp_integer int_rep = value[0];
441+
return from_integer(int_rep, type);
392442
}
393443
else if(type.id() == ID_c_bool)
394444
{

0 commit comments

Comments
 (0)