Skip to content

Commit fc92f17

Browse files
committed
Shortest path grapht
Builds CFG of all program locations and computes the shortest distance from all locations in the graph to a single property. WARNING: if more than one property is given, we use the first one only. Writes these distances to the corresponding node in a locs structure passed as argument to the constructor, in order for this to be used to guide the symex search
1 parent 3138002 commit fc92f17

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

src/symex/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ SRC = path_search.cpp \
22
symex_cover.cpp \
33
symex_main.cpp \
44
symex_parse_options.cpp \
5+
shortest_path_graph.cpp \
56
# Empty last line
67

78
OBJ += ../../$(CPROVER_DIR)/ansi-c/ansi-c$(LIBEXT) \

src/symex/shortest_path_graph.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*******************************************************************\
2+
3+
Module: Shortest path graph
4+
5+
6+
7+
\*******************************************************************/
8+
9+
#include "shortest_path_graph.h"
10+
11+
#include <algorithm>
12+
void shortest_path_grapht::bfs(node_indext property_index)
13+
{
14+
// does BFS, not Dijkstra
15+
// we hope the graph is sparse
16+
std::vector<node_indext> frontier_set;
17+
18+
frontier_set.reserve(nodes.size());
19+
20+
frontier_set.push_back(property_index);
21+
nodes[property_index].visited = true;
22+
23+
for(std::size_t d = 1; !frontier_set.empty(); ++d)
24+
{
25+
std::vector<node_indext> new_frontier_set;
26+
27+
for(const auto &node_index : frontier_set)
28+
{
29+
const nodet &n = nodes[node_index];
30+
31+
// do all neighbors
32+
// we go backwards through the graph
33+
for(const auto &edge_in : n.in)
34+
{
35+
node_indext node_in = edge_in.first;
36+
37+
if(!nodes[node_in].visited)
38+
{
39+
nodes[node_in].shortest_path_to_property = d;
40+
nodes[node_in].visited = true;
41+
new_frontier_set.push_back(node_in);
42+
}
43+
}
44+
}
45+
46+
frontier_set.swap(new_frontier_set);
47+
}
48+
}
49+
50+
void shortest_path_grapht::write_lengths_to_locs()
51+
{
52+
for(const auto &n : nodes)
53+
{
54+
loc_reft l = target_to_loc_map[n.PC];
55+
locs.loc_vector[l.loc_number].distance_to_property
56+
= n.shortest_path_to_property;
57+
}
58+
}
59+
60+
void shortest_path_grapht::get_path_lengths_to_property()
61+
{
62+
node_indext property_index;
63+
bool found_property=false;
64+
for(node_indext n=0; n<nodes.size(); n++)
65+
{
66+
if(nodes[n].PC->is_assert())
67+
{
68+
if(found_property == false)
69+
{
70+
nodes[n].is_property = true;
71+
nodes[n].shortest_path_to_property = 0;
72+
working_set.insert(n);
73+
property_index = n;
74+
found_property = true;
75+
}
76+
else
77+
throw "shortest path search cannot be used for multiple properties";
78+
}
79+
}
80+
if(!found_property)
81+
throw "unable to find property";
82+
83+
bfs(property_index);
84+
85+
write_lengths_to_locs();
86+
}
87+
88+

src/symex/shortest_path_graph.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*******************************************************************\
2+
3+
Module: Shortest path graph
4+
5+
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_SYMEX_SHORTEST_PATH_GRAPH_H
10+
#define CPROVER_SYMEX_SHORTEST_PATH_GRAPH_H
11+
12+
#include <goto-programs/cfg.h>
13+
#include <path-symex/locs.h>
14+
#include <goto-programs/goto_model.h>
15+
#include <limits>
16+
17+
18+
struct shortest_path_nodet
19+
{
20+
bool visited;
21+
std::size_t shortest_path_to_property;
22+
bool is_property;
23+
shortest_path_nodet():
24+
visited(false),
25+
is_property(false)
26+
{
27+
shortest_path_to_property = std::numeric_limits<std::size_t>::max();
28+
}
29+
};
30+
31+
/// \brief constructs a CFG of all program locations. Then computes
32+
/// the shortest path from every program location to a single property.
33+
/// WARNING: if more than one property is present in the graph, we will
34+
/// use the first property found
35+
/// The distances computed for each node are written to the corresponding
36+
/// loct in the locst passed as param to the constructor. This allows us
37+
/// to use these numbers to guide a symex search
38+
/// \param goto functions to create the CFG from, locs struct made from the
39+
/// same goto_functions
40+
class shortest_path_grapht: public cfg_baset<shortest_path_nodet>
41+
{
42+
public:
43+
explicit shortest_path_grapht(
44+
const goto_functionst &_goto_functions, locst &_locs):
45+
locs(_locs),
46+
target_to_loc_map(_locs)
47+
{
48+
cfg_baset<shortest_path_nodet>::operator()(_goto_functions);
49+
get_path_lengths_to_property();
50+
}
51+
52+
protected:
53+
/// \brief writes the computed shortest path for every node
54+
/// in the graph to the corresponding location in locst.
55+
/// This is done so that we can use these numbers to guide
56+
/// a search heuristic for symex
57+
void write_lengths_to_locs();
58+
/// \brief computes the shortest path from every node in
59+
/// the graph to a single property. WARNING: if more than one property
60+
/// is present, we use the first one discovered.
61+
/// Calls bfs() to do this.
62+
void get_path_lengths_to_property();
63+
/// \brief implements backwards BFS to compute distance from every node in
64+
/// the graph to the node index given as parameter
65+
/// \param destination node index
66+
void bfs(node_indext property_index);
67+
std::set<node_indext> working_set;
68+
locst &locs;
69+
target_to_loc_mapt target_to_loc_map;
70+
};
71+
72+
#endif /* CPROVER_SYMEX_SHORTEST_PATH_GRAPH_H */

0 commit comments

Comments
 (0)