Skip to content

Commit b7ef5af

Browse files
authored
Merge pull request #2053 from owen-jones-diffblue/owen-jones-diffblue/bugfix/make-callgraph-include-uncalled-functions
Make directed callgraph include nodes with no edges
2 parents de1915a + d73f6bc commit b7ef5af

File tree

7 files changed

+258
-19
lines changed

7 files changed

+258
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
int x;
3+
4+
void func0()
5+
{
6+
func0();
7+
}
8+
9+
void func1()
10+
{
11+
x = 1;
12+
}
13+
14+
void func2()
15+
{
16+
x = 2;
17+
func3();
18+
}
19+
20+
void func3()
21+
{
22+
x = 3;
23+
}
24+
25+
void func4(int b)
26+
{
27+
x = 4;
28+
if(b)
29+
{
30+
func5(0);
31+
}
32+
}
33+
34+
void func5(int b)
35+
{
36+
x = 5;
37+
func4(b);
38+
}
39+
40+
void func6()
41+
{
42+
x = 6;
43+
}
44+
45+
void func7(int b)
46+
{
47+
x = 7;
48+
if(b)
49+
{
50+
func8(0);
51+
}
52+
}
53+
54+
void func8(int b)
55+
{
56+
x = 8;
57+
func7(b);
58+
}
59+
60+
void func9()
61+
{
62+
x = 9;
63+
funca();
64+
}
65+
66+
void funca()
67+
{
68+
x = 10;
69+
func9();
70+
}
71+
72+
73+
74+
int main()
75+
{
76+
func1();
77+
func2();
78+
func4(1);
79+
80+
return 0;
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CORE
2+
main.c
3+
--call-graph
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^main -> func2$
7+
^main -> func1$
8+
^main -> func4$
9+
^funca -> func9$
10+
^func9 -> funca$
11+
^func8 -> func7$
12+
^func7 -> func8$
13+
^__CPROVER__start -> __CPROVER_initialize$
14+
^__CPROVER__start -> main$
15+
^func2 -> func3$
16+
^func0 -> func0$
17+
^func4 -> func5$
18+
^func5 -> func4$
19+
--
20+
^warning: ignoring
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
int x;
3+
4+
void func0()
5+
{
6+
func0();
7+
}
8+
9+
void func1()
10+
{
11+
x = 1;
12+
}
13+
14+
void func2()
15+
{
16+
x = 2;
17+
func3();
18+
}
19+
20+
void func3()
21+
{
22+
x = 3;
23+
}
24+
25+
void func4(int b)
26+
{
27+
x = 4;
28+
if(b)
29+
{
30+
func5(0);
31+
}
32+
}
33+
34+
void func5(int b)
35+
{
36+
x = 5;
37+
func4(b);
38+
}
39+
40+
void func6()
41+
{
42+
x = 6;
43+
}
44+
45+
void func7(int b)
46+
{
47+
x = 7;
48+
if(b)
49+
{
50+
func8(0);
51+
}
52+
}
53+
54+
void func8(int b)
55+
{
56+
x = 8;
57+
func7(b);
58+
}
59+
60+
void func9()
61+
{
62+
x = 9;
63+
funca();
64+
}
65+
66+
void funca()
67+
{
68+
x = 10;
69+
func9();
70+
}
71+
72+
73+
74+
int main()
75+
{
76+
func1();
77+
func2();
78+
func4(1);
79+
80+
return 0;
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CORE
2+
main.c
3+
--reachable-call-graph
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^main -> func2$
7+
^main -> func1$
8+
^main -> func4$
9+
^__CPROVER__start -> __CPROVER_initialize$
10+
^__CPROVER__start -> main$
11+
^func2 -> func3$
12+
^func4 -> func5$
13+
^func5 -> func4$
14+
--
15+
^funca -> func9$
16+
^func9 -> funca$
17+
^func8 -> func7$
18+
^func7 -> func8$
19+
^func0 -> func0$
20+
^warning: ignoring

src/analyses/call_graph.cpp

+21-9
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ call_grapht::call_grapht(
4141
{
4242
forall_goto_functions(f_it, goto_functions)
4343
{
44-
const goto_programt &body=f_it->second.body;
45-
add(f_it->first, body);
44+
const irep_idt &function_name = f_it->first;
45+
const goto_programt &body = f_it->second.body;
46+
nodes.insert(function_name);
47+
add(function_name, body);
4648
}
4749
}
4850

@@ -84,12 +86,14 @@ call_grapht::call_grapht(
8486
const goto_programt &goto_program=
8587
goto_functions.function_map.at(function).body;
8688

89+
nodes.insert(function);
90+
8791
forall_callsites(
8892
goto_program,
8993
[&](goto_programt::const_targett i_it, const irep_idt &callee)
9094
{
9195
add(function, callee, i_it);
92-
if(graph.find(callee)==graph.end())
96+
if(edges.find(callee)==edges.end())
9397
pending_stack.push(callee);
9498
}
9599
); // NOLINT
@@ -129,7 +133,9 @@ void call_grapht::add(
129133
const irep_idt &caller,
130134
const irep_idt &callee)
131135
{
132-
graph.insert(std::pair<irep_idt, irep_idt>(caller, callee));
136+
edges.insert({caller, callee});
137+
nodes.insert(caller);
138+
nodes.insert(callee);
133139
}
134140

135141
/// Add edge with optional callsite information
@@ -152,7 +158,8 @@ void call_grapht::add(
152158
call_grapht call_grapht::get_inverted() const
153159
{
154160
call_grapht result;
155-
for(const auto &caller_callee : graph)
161+
result.nodes = nodes;
162+
for(const auto &caller_callee : edges)
156163
result.add(caller_callee.second, caller_callee.first);
157164
return result;
158165
}
@@ -197,7 +204,12 @@ call_grapht::directed_grapht call_grapht::get_directed_graph() const
197204
call_grapht::directed_grapht ret;
198205
function_indicest function_indices(ret);
199206

200-
for(const auto &edge : graph)
207+
// To make sure we include unreachable functions we first create indices
208+
// for all nodes in the graph
209+
for(const irep_idt &function_name : nodes)
210+
function_indices[function_name];
211+
212+
for(const auto &edge : edges)
201213
{
202214
auto a_index=function_indices[edge.first];
203215
auto b_index=function_indices[edge.second];
@@ -237,7 +249,7 @@ void call_grapht::output_dot(std::ostream &out) const
237249
{
238250
out << "digraph call_graph {\n";
239251

240-
for(const auto &edge : graph)
252+
for(const auto &edge : edges)
241253
{
242254
out << " \"" << edge.first << "\" -> "
243255
<< "\"" << edge.second << "\" "
@@ -252,7 +264,7 @@ void call_grapht::output_dot(std::ostream &out) const
252264

253265
void call_grapht::output(std::ostream &out) const
254266
{
255-
for(const auto &edge : graph)
267+
for(const auto &edge : edges)
256268
{
257269
out << edge.first << " -> " << edge.second << "\n";
258270
if(collect_callsites)
@@ -267,7 +279,7 @@ void call_grapht::output_xml(std::ostream &out) const
267279
if(collect_callsites)
268280
out << "<!-- XML call-graph representation does not document callsites yet."
269281
" If you need this, edit call_grapht::output_xml -->\n";
270-
for(const auto &edge : graph)
282+
for(const auto &edge : edges)
271283
{
272284
out << "<call_graph_edge caller=\"";
273285
xmlt::escape_attribute(id2string(edge.first), out);

src/analyses/call_graph.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,14 @@ class call_grapht
6262
void output(std::ostream &out) const;
6363
void output_xml(std::ostream &out) const;
6464

65-
/// Type of the call graph. Note parallel edges (e.g. A having two callsites
66-
/// both targeting B) result in multiple graph edges.
67-
typedef std::multimap<irep_idt, irep_idt> grapht;
65+
/// Type of the nodes in the call graph.
66+
typedef std::unordered_set<irep_idt, irep_id_hash> nodest;
6867

69-
/// Type of a call graph edge in `grapht`
68+
/// Type of the edges in the call graph. Note parallel edges (e.g. A having
69+
/// two callsites both targeting B) result in multiple graph edges.
70+
typedef std::multimap<irep_idt, irep_idt> edgest;
71+
72+
/// Type of a call graph edge in `edgest`
7073
typedef std::pair<irep_idt, irep_idt> edget;
7174

7275
/// Type of a callsite stored in member `callsites`
@@ -84,7 +87,8 @@ class call_grapht
8487
/// backward compatibility; use `get_directed_graph()` to get a generic
8588
/// directed graph representation that provides more graph algorithms
8689
/// (shortest path, SCCs and so on).
87-
grapht graph;
90+
edgest edges;
91+
nodest nodes;
8892

8993
/// Map from call-graph edges to a set of callsites that make the given call.
9094
callsitest callsites;

0 commit comments

Comments
 (0)