Skip to content

Make directed callgraph include nodes with no edges #2053

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions regression/goto-instrument/call-graph1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@

int x;

void func0()
{
func0();
}

void func1()
{
x = 1;
}

void func2()
{
x = 2;
func3();
}

void func3()
{
x = 3;
}

void func4(int b)
{
x = 4;
if(b)
{
func5(0);
}
}

void func5(int b)
{
x = 5;
func4(b);
}

void func6()
{
x = 6;
}

void func7(int b)
{
x = 7;
if(b)
{
func8(0);
}
}

void func8(int b)
{
x = 8;
func7(b);
}

void func9()
{
x = 9;
funca();
}

void funca()
{
x = 10;
func9();
}



int main()
{
func1();
func2();
func4(1);

return 0;
}
20 changes: 20 additions & 0 deletions regression/goto-instrument/call-graph1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
CORE
main.c
--call-graph
^EXIT=0$
^SIGNAL=0$
^main -> func2$
^main -> func1$
^main -> func4$
^funca -> func9$
^func9 -> funca$
^func8 -> func7$
^func7 -> func8$
^__CPROVER__start -> __CPROVER_initialize$
^__CPROVER__start -> main$
^func2 -> func3$
^func0 -> func0$
^func4 -> func5$
^func5 -> func4$
--
^warning: ignoring
81 changes: 81 additions & 0 deletions regression/goto-instrument/reachable-call-graph1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@

int x;

void func0()
{
func0();
}

void func1()
{
x = 1;
}

void func2()
{
x = 2;
func3();
}

void func3()
{
x = 3;
}

void func4(int b)
{
x = 4;
if(b)
{
func5(0);
}
}

void func5(int b)
{
x = 5;
func4(b);
}

void func6()
{
x = 6;
}

void func7(int b)
{
x = 7;
if(b)
{
func8(0);
}
}

void func8(int b)
{
x = 8;
func7(b);
}

void func9()
{
x = 9;
funca();
}

void funca()
{
x = 10;
func9();
}



int main()
{
func1();
func2();
func4(1);

return 0;
}
20 changes: 20 additions & 0 deletions regression/goto-instrument/reachable-call-graph1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
CORE
main.c
--reachable-call-graph
^EXIT=0$
^SIGNAL=0$
^main -> func2$
^main -> func1$
^main -> func4$
^__CPROVER__start -> __CPROVER_initialize$
^__CPROVER__start -> main$
^func2 -> func3$
^func4 -> func5$
^func5 -> func4$
--
^funca -> func9$
^func9 -> funca$
^func8 -> func7$
^func7 -> func8$
^func0 -> func0$
^warning: ignoring
30 changes: 21 additions & 9 deletions src/analyses/call_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ call_grapht::call_grapht(
{
forall_goto_functions(f_it, goto_functions)
{
const goto_programt &body=f_it->second.body;
add(f_it->first, body);
const irep_idt &function_name = f_it->first;
const goto_programt &body = f_it->second.body;
nodes.insert(function_name);
add(function_name, body);
}
}

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

nodes.insert(function);

forall_callsites(
goto_program,
[&](goto_programt::const_targett i_it, const irep_idt &callee)
{
add(function, callee, i_it);
if(graph.find(callee)==graph.end())
if(edges.find(callee)==edges.end())
pending_stack.push(callee);
}
); // NOLINT
Expand Down Expand Up @@ -129,7 +133,9 @@ void call_grapht::add(
const irep_idt &caller,
const irep_idt &callee)
{
graph.insert(std::pair<irep_idt, irep_idt>(caller, callee));
edges.insert({caller, callee});
nodes.insert(caller);
nodes.insert(callee);
}

/// Add edge with optional callsite information
Expand All @@ -152,7 +158,8 @@ void call_grapht::add(
call_grapht call_grapht::get_inverted() const
{
call_grapht result;
for(const auto &caller_callee : graph)
result.nodes = nodes;
for(const auto &caller_callee : edges)
result.add(caller_callee.second, caller_callee.first);
return result;
}
Expand Down Expand Up @@ -197,7 +204,12 @@ call_grapht::directed_grapht call_grapht::get_directed_graph() const
call_grapht::directed_grapht ret;
function_indicest function_indices(ret);

for(const auto &edge : graph)
// To make sure we include unreachable functions we first create indices
// for all nodes in the graph
for(const irep_idt &function_name : nodes)
function_indices[function_name];

for(const auto &edge : edges)
{
auto a_index=function_indices[edge.first];
auto b_index=function_indices[edge.second];
Expand Down Expand Up @@ -237,7 +249,7 @@ void call_grapht::output_dot(std::ostream &out) const
{
out << "digraph call_graph {\n";

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

void call_grapht::output(std::ostream &out) const
{
for(const auto &edge : graph)
for(const auto &edge : edges)
{
out << edge.first << " -> " << edge.second << "\n";
if(collect_callsites)
Expand All @@ -267,7 +279,7 @@ void call_grapht::output_xml(std::ostream &out) const
if(collect_callsites)
out << "<!-- XML call-graph representation does not document callsites yet."
" If you need this, edit call_grapht::output_xml -->\n";
for(const auto &edge : graph)
for(const auto &edge : edges)
{
out << "<call_graph_edge caller=\"";
xmlt::escape_attribute(id2string(edge.first), out);
Expand Down
14 changes: 9 additions & 5 deletions src/analyses/call_graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,14 @@ class call_grapht
void output(std::ostream &out) const;
void output_xml(std::ostream &out) const;

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

/// Type of a call graph edge in `grapht`
/// Type of the edges in the call graph. Note parallel edges (e.g. A having
/// two callsites both targeting B) result in multiple graph edges.
typedef std::multimap<irep_idt, irep_idt> edgest;

/// Type of a call graph edge in `edgest`
typedef std::pair<irep_idt, irep_idt> edget;

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

/// Map from call-graph edges to a set of callsites that make the given call.
callsitest callsites;
Expand Down
Loading