previously, clones of callback functions had their local flag set.
Because callback edges are direct rather than indirect, GCC falsely
assumes that their callsites are available and that it can change their
ABI, leading to segfaults. This patch fixes that. Bootstrapped and
regtested on x86_64-pc-linux-gnu with
RUNTESTFLAGS="--target_board='unix{-m32}'". OK for master?
gcc/ChangeLog:
PR ipa/122798
* cgraph.cc (cgraph_edge::redirect_callee): Set address taken
for new callee.
(cgraph_node::callback_called_p): New function.
* cgraph.h (struct cgraph_node): Likewise.
* cgraphclones.cc (cgraph_node::create_virtual_clone): Set local
flag to false when cloning a function with a callback call.
Signed-off-by: Josef Melcr <[email protected]>
---
gcc/cgraph.cc | 10 ++++++++++
gcc/cgraph.h | 3 +++
gcc/cgraphclones.cc | 4 ++++
3 files changed, 17 insertions(+)
diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 3c21e174943..64b19b5e5ac 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -1698,6 +1698,7 @@ cgraph_edge::redirect_callee (cgraph_node *n)
new_ref->lto_stmt_uid = lto_stmt_uid;
if (!old_callee->referred_to_p ())
old_callee->address_taken = 0;
+ n->mark_address_taken();
+bool
+cgraph_node::callback_called_p () const
+{
+ cgraph_edge *e;
+ for (e = callers; e; e = e->next_caller)
+ if (e->callback)
+ return true;
+ return false;
+}
/* Collect all callers of NODE. Worker for collect_callers_of_node. */
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 313610fbe2c..b534a470b77 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1278,6 +1278,9 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node :
public symtab_node
it is not used in any other non-standard way. */
bool only_called_directly_p (void);
+ /* Return TRUE if the node has at least one callback edge pointing to it. */
+ bool callback_called_p (void) const;
+
/* Turn profile to global0. Walk into inlined functions. */
void make_profile_local ();
diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc
index 49f0e58fa1e..3cfbfec4c1a 100644
--- a/gcc/cgraphclones.cc
+++ b/gcc/cgraphclones.cc
@@ -687,6 +687,7 @@ cgraph_node::create_virtual_clone (const vec<cgraph_edge *>
&redirect_callers,
clone_function_name (old_decl, suffix, num_suffix));
SET_DECL_RTL (new_decl, NULL);
+ bool has_callback_call = callback_called_p ();
new_node = create_clone (new_decl, count, false,
redirect_callers, false, NULL, param_adjustments,
suffix);
@@ -697,6 +698,9 @@ cgraph_node::create_virtual_clone (const vec<cgraph_edge *>
&redirect_callers,
??? We cannot use COMDAT linkage because there is no
ABI support for this. */
set_new_clone_decl_and_node_flags (new_node);
+ if (has_callback_call)
+ /* Callback clone can never be local, since it has its address taken. */
+ new_node->local = false;
new_node->ipcp_clone = ipcp_clone;
if (tree_map)
clone_info::get_create (new_node)->tree_map = tree_map;