Skip to content

Cleanup duplicate static inline functions at/after linking #1987

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

Closed
wants to merge 1 commit into from
Closed
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
6 changes: 6 additions & 0 deletions regression/ansi-c/linking2/foo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
static inline void foo(int x)
{
x = x + 1;
}

void bar(int);
8 changes: 8 additions & 0 deletions regression/ansi-c/linking2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "foo.h"

int main(int argc, char *argv[])
{
foo(argc);
bar(argc);
return 0;
}
14 changes: 14 additions & 0 deletions regression/ansi-c/linking2/other.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef TEST2
# include "foo.h"
#else
inline void foo(int x)
{
x = 0;
}
#endif

void bar(int y)
{
foo(y);
y = 2;
}
13 changes: 13 additions & 0 deletions regression/ansi-c/linking2/test1.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CORE
main.c
other.c --verbosity 10
^EXIT=0$
^SIGNAL=0$
^Functions: 5; 5 have a body.$
--
^warning: ignoring
^CONVERSION ERROR$
--
The implementation of a function named "foo" (static inline void foo(int x)) is
the same in both translation units, thus linking can safely discard one of the
copies and does not need to do any renaming.
13 changes: 13 additions & 0 deletions regression/ansi-c/linking2/test2.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CORE
main.c
other.c --verbosity 10 -DTEST2
^EXIT=0$
^SIGNAL=0$
^Functions: 6; 6 have a body.$
--
^warning: ignoring
^CONVERSION ERROR$
--
The implementation of a function named "foo" (void foo(int x)) differs between
translation units; as at least one of them is static this is acceptable at link
time and can be resolved by renaming one of them.
2 changes: 1 addition & 1 deletion regression/ansi-c/static2/main2.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
static int foo(int a)
{
return a+1;
return a + 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sure the functions are actually different so that the static variant doesn't get ignored after the changes in this PR.

}
2 changes: 1 addition & 1 deletion regression/ansi-c/static3/main2.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
static int foo(int a)
{
return a+1;
return a + 2;
}
32 changes: 31 additions & 1 deletion src/goto-programs/link_goto_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,45 @@ static bool link_functions(
goto_functionst &dest_functions,
const symbol_tablet &src_symbol_table,
goto_functionst &src_functions,
const rename_symbolt &rename_symbol,
rename_symbolt &rename_symbol,
const std::unordered_set<irep_idt> &weak_symbols)
{
namespacet ns(dest_symbol_table);
namespacet src_ns(src_symbol_table);

// remove any unnecessary duplicates
std::unordered_set<irep_idt> duplicates;
for(const auto &f_pair : src_functions.function_map)
{
rename_symbolt::expr_mapt::iterator rename_it =
rename_symbol.expr_map.find(f_pair.first);
if(rename_it == rename_symbol.expr_map.end())
continue;

std::string new_name = id2string(rename_it->second);
std::string::size_type suffix_pos = new_name.find("$link");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this grungy string decomposition, how about annotating such symbols with a comment ID_C_original_function_identifier or such?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would seem nice, but I'm struggling to find a good place to put it in a symbolt?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been sticking annotations like this on the type myself. We should agree on a policy though, or make a breaking change to add symbolt::attributes

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think that the name and the type are really disjoint, so I'd much rather sort this out via some to-be-added symbolt::attributes.

if(suffix_pos == std::string::npos)
continue;

irep_idt original_name = new_name.substr(0, suffix_pos);
goto_functionst::function_mapt::iterator existing_func =
dest_functions.function_map.find(original_name);
if(existing_func == dest_functions.function_map.end())
continue;

if(f_pair.second.body.equals(existing_func->second.body))
{
duplicates.insert(f_pair.first);
rename_symbol.expr_map.erase(rename_it);
}
}

// merge functions
for(auto &gf_entry : src_functions.function_map)
{
if(duplicates.find(gf_entry.first) != duplicates.end())
continue;

// the function might have been renamed
rename_symbolt::expr_mapt::const_iterator e_it =
rename_symbol.expr_map.find(gf_entry.first);
Expand Down
27 changes: 12 additions & 15 deletions src/linking/linking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,11 +537,9 @@ bool linkingt::needs_renaming_non_type(
// We first take care of file-local non-type symbols.
// These are static functions, or static variables
// inside static function bodies.
if(new_symbol.is_file_local ||
old_symbol.is_file_local)
return true;

return false;
return (new_symbol.is_file_local || old_symbol.is_file_local) &&
(new_symbol.type.id() != ID_code || new_symbol.is_compiled() ||
new_symbol.value != old_symbol.value);
}

void linkingt::duplicate_code_symbol(
Expand Down Expand Up @@ -848,19 +846,18 @@ void linkingt::duplicate_code_symbol(
object_type_updates.insert(
old_symbol.symbol_expr(), old_symbol.symbol_expr());
}
else if(to_code_type(old_symbol.type).get_inlined())
{
// ok, silently ignore
}
else if(old_symbol.type == new_symbol.type)
{
// keep the one in old_symbol -- libraries come last!
debug().source_location = new_symbol.location;
if(!new_symbol.is_file_local || !old_symbol.is_file_local)
{
// keep the one in old_symbol -- libraries come last!
debug().source_location = new_symbol.location;

debug() << "function '" << old_symbol.name << "' in module '"
<< new_symbol.module
<< "' is shadowed by a definition in module '"
<< old_symbol.module << "'" << eom;
debug() << "function '" << old_symbol.name << "' in module '"
<< new_symbol.module
<< "' is shadowed by a definition in module '"
<< old_symbol.module << "'" << eom;
}
}
else
link_error(
Expand Down