Skip to content

Commit 001b6f9

Browse files
authored
Merge pull request #5095 from xbauch/fix/snapshot-harness-order
Fix the ordering of variable initialisation in goto-harness
2 parents cb20917 + fbb40a0 commit 001b6f9

File tree

6 files changed

+193
-38
lines changed

6 files changed

+193
-38
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <assert.h>
2+
#include <malloc.h>
3+
4+
int a;
5+
int *a1;
6+
int *iterator1;
7+
int *a2;
8+
int *a3;
9+
int *iterator2;
10+
int *a4;
11+
int *a5;
12+
int *iterator3;
13+
int *a6;
14+
int *a7;
15+
int *array2;
16+
int *a8;
17+
18+
void initialize()
19+
{
20+
array2 = (int *)malloc(sizeof(int) * 10);
21+
array2[0] = 1;
22+
array2[1] = 2;
23+
array2[2] = 3;
24+
array2[3] = 4;
25+
array2[4] = 5;
26+
array2[5] = 6;
27+
array2[6] = 7;
28+
array2[7] = 8;
29+
array2[8] = 9;
30+
array2[9] = 10;
31+
iterator1 = (int *)array2;
32+
iterator2 = &array2[1];
33+
iterator3 = array2 + 1;
34+
a1 = &a;
35+
a2 = a1;
36+
a3 = a2;
37+
a4 = a3;
38+
a5 = a4;
39+
a6 = a5;
40+
a7 = a6;
41+
a8 = a7;
42+
}
43+
44+
void checkpoint()
45+
{
46+
}
47+
48+
int main()
49+
{
50+
initialize();
51+
checkpoint();
52+
53+
assert(*iterator1 == 1);
54+
assert(iterator1 != iterator2);
55+
assert(iterator2 == iterator3);
56+
assert(iterator2 == &array2[1]);
57+
assert(*iterator3 == array2[1]);
58+
assert(*iterator3 == 2);
59+
iterator3 = &array2[9];
60+
iterator3++;
61+
assert(*iterator3 == 0);
62+
63+
return 0;
64+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
main.c
3+
a,a1,iterator1,a2,a3,iterator2,a4,a5,iterator3,a6,a7,array2,a8 --harness-type initialise-with-memory-snapshot --initial-goto-location main:4
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
\[main.assertion.1\] line [0-9]+ assertion \*iterator1 == 1: SUCCESS
7+
\[main.assertion.2\] line [0-9]+ assertion iterator1 != iterator2: SUCCESS
8+
\[main.assertion.3\] line [0-9]+ assertion iterator2 == iterator3: SUCCESS
9+
\[main.assertion.4\] line [0-9]+ assertion iterator2 == \&array2\[1\]: SUCCESS
10+
\[main.assertion.5\] line [0-9]+ assertion \*iterator3 == array2\[1\]: SUCCESS
11+
\[main.assertion.6\] line [0-9]+ assertion \*iterator3 == 2: SUCCESS
12+
\[main.pointer_dereference.27\] line [0-9]+ dereference failure: pointer outside object bounds in \*iterator3: FAILURE
13+
\[main.assertion.7\] line [0-9]+ assertion \*iterator3 == 0: FAILURE
14+
VERIFICATION FAILED
15+
--
16+
unwinding assertion loop \d+: FAILURE

regression/snapshot-harness/dynamic-array-int/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
array,iterator1,iterator2,iterator3 --harness-type initialise-with-memory-snapshot --initial-goto-location main:4
44
^EXIT=10$

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,6 +1,6 @@
11
CORE
22
main.c
3-
first,second,string_size,prefix,prefix_size --harness-type initialise-with-memory-snapshot --initial-goto-location main:4 --havoc-variables prefix,prefix_size --size-of-array prefix:prefix_size --max-array-size 5
3+
first,second,string_size,prefix,prefix_size --harness-type initialise-with-memory-snapshot --initial-goto-location main:4 --havoc-variables prefix --size-of-array prefix:prefix_size --max-array-size 5
44
^SIGNAL=0$
55
^EXIT=0$
66
VERIFICATION SUCCESSFUL

src/goto-harness/memory_snapshot_harness_generator.cpp

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -209,47 +209,38 @@ size_t memory_snapshot_harness_generatort::pointer_depth(const typet &t) const
209209
return pointer_depth(t.subtype()) + 1;
210210
}
211211

212-
bool memory_snapshot_harness_generatort::refers_to(
213-
const exprt &expr,
214-
const irep_idt &name) const
215-
{
216-
if(expr.id() == ID_symbol)
217-
return to_symbol_expr(expr).get_identifier() == name;
218-
return std::any_of(
219-
expr.operands().begin(),
220-
expr.operands().end(),
221-
[this, name](const exprt &subexpr) { return refers_to(subexpr, name); });
222-
}
223-
224212
code_blockt memory_snapshot_harness_generatort::add_assignments_to_globals(
225213
const symbol_tablet &snapshot,
226214
goto_modelt &goto_model) const
227215
{
228216
recursive_initializationt recursive_initialization{
229217
recursive_initialization_config, goto_model};
230218

231-
using snapshot_pairt = std::pair<irep_idt, symbolt>;
232-
std::vector<snapshot_pairt> ordered_snapshot_symbols;
233-
for(auto pair : snapshot)
234-
{
235-
const auto name = id2string(pair.first);
236-
if(!has_prefix(name, CPROVER_PREFIX))
237-
ordered_snapshot_symbols.push_back(pair);
238-
}
239-
219+
std::vector<std::pair<irep_idt, symbolt>> ordered_snapshot_symbols;
240220
// sort the snapshot symbols so that the non-pointer symbols are first, then
241221
// pointers, then pointers-to-pointers, etc. so that we don't assign
242222
// uninitialized values
243-
std::stable_sort(
244-
ordered_snapshot_symbols.begin(),
245-
ordered_snapshot_symbols.end(),
246-
[this](const snapshot_pairt &left, const snapshot_pairt &right) {
247-
if(refers_to(right.second.value, left.first))
248-
return true;
249-
else
250-
return pointer_depth(left.second.symbol_expr().type()) <
251-
pointer_depth(right.second.symbol_expr().type());
252-
});
223+
{
224+
std::vector<std::pair<irep_idt, symbolt>> selected_snapshot_symbols;
225+
using relationt = typename preordert<irep_idt>::relationt;
226+
relationt reference_relation;
227+
228+
for(const auto &snapshot_pair : snapshot)
229+
{
230+
const auto name = id2string(snapshot_pair.first);
231+
if(name.find(CPROVER_PREFIX) != 0)
232+
{
233+
collect_references(
234+
snapshot_pair.second.value,
235+
[&reference_relation, &snapshot_pair](const irep_idt &id) {
236+
reference_relation.insert(std::make_pair(snapshot_pair.first, id));
237+
});
238+
selected_snapshot_symbols.push_back(snapshot_pair);
239+
}
240+
}
241+
preordert<irep_idt> reference_order{reference_relation};
242+
reference_order.sort(selected_snapshot_symbols, ordered_snapshot_symbols);
243+
}
253244

254245
code_blockt code{};
255246

src/goto-harness/memory_snapshot_harness_generator.h

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,95 @@ class memory_snapshot_harness_generatort : public goto_harness_generatort
275275
/// \return pointer depth of type \p t
276276
size_t pointer_depth(const typet &t) const;
277277

278-
/// Recursively test pointer reference
279-
/// \param expr: expression to be tested
280-
/// \param name: name to be located
281-
/// \return true if \p expr refers to an object named \p name
282-
bool refers_to(const exprt &expr, const irep_idt &name) const;
278+
template <typename Adder>
279+
void collect_references(const exprt &expr, Adder &&add_reference) const
280+
{
281+
if(expr.id() == ID_symbol)
282+
add_reference(to_symbol_expr(expr).get_identifier());
283+
for(const auto &operand : expr.operands())
284+
{
285+
collect_references(operand, add_reference);
286+
}
287+
}
288+
289+
/// Simple structure for linearising posets. Should be constructed with a map
290+
/// assigning a key to a set of keys that precede it.
291+
template <typename Key>
292+
struct preordert
293+
{
294+
public:
295+
using relationt = std::multimap<Key, Key>;
296+
using keyst = std::set<Key>;
297+
298+
explicit preordert(const relationt &preorder_relation)
299+
: preorder_relation(preorder_relation)
300+
{
301+
}
302+
303+
template <typename T>
304+
void sort(
305+
const std::vector<std::pair<Key, T>> &input,
306+
std::vector<std::pair<Key, T>> &output)
307+
{
308+
std::unordered_map<Key, T> searchable_input;
309+
using valuet = std::pair<Key, T>;
310+
311+
for(const auto &item : input)
312+
{
313+
searchable_input[item.first] = item.second;
314+
}
315+
auto associate_key_with_t =
316+
[&searchable_input](const Key &key) -> optionalt<valuet> {
317+
if(searchable_input.count(key) != 0)
318+
return valuet(key, searchable_input[key]);
319+
else
320+
return {};
321+
};
322+
auto push_to_output = [&output](const valuet &value) {
323+
output.push_back(value);
324+
};
325+
for(const auto &item : input)
326+
{
327+
dfs(item, associate_key_with_t, push_to_output);
328+
}
329+
}
330+
331+
private:
332+
const relationt &preorder_relation;
333+
334+
keyst seen;
335+
keyst inserted;
336+
337+
template <typename Value, typename Map, typename Handler>
338+
void dfs(Value &&node, Map &&key_to_t, Handler &&handle)
339+
{
340+
PRECONDITION(seen.empty() && inserted.empty());
341+
dfs_inner(node, key_to_t, handle);
342+
seen.clear();
343+
inserted.clear();
344+
}
345+
346+
template <typename Value, typename Map, typename Handler>
347+
void dfs_inner(Value &&node, Map &&key_to_t, Handler &&handle)
348+
{
349+
const Key &key = node.first;
350+
if(seen.count(key) == 0)
351+
{
352+
seen.insert(key);
353+
auto key_range = preorder_relation.equal_range(key);
354+
for(auto it = key_range.first; it != key_range.second; ++it)
355+
{
356+
auto maybe_value = key_to_t(it->second);
357+
if(maybe_value.has_value())
358+
dfs_inner(*maybe_value, key_to_t, handle);
359+
}
360+
}
361+
if(inserted.count(key) != 0)
362+
return;
363+
handle(node);
364+
inserted.insert(key);
365+
}
366+
};
283367

284368
/// data to store the command-line options
285369
std::string memory_snapshot_file;

0 commit comments

Comments
 (0)