]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ipa/122798: Adjust local and address_taken flags for callback clones.
authorJosef Melcr <josef.melcr@suse.com>
Mon, 8 Dec 2025 08:21:38 +0000 (09:21 +0100)
committerJosef Melcr <josef.melcr@suse.com>
Mon, 8 Dec 2025 09:40:15 +0000 (10:40 +0100)
Hi,
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.  Additionally, this
patch fixes a check in redirect_callee for clearing the address_taken
flag.

PR ipa/122798

gcc/ChangeLog:

* cgraph.cc (cgraph_edge::redirect_callee): Use
iterate_referring instead of referred_to_p.
* cgraphclones.cc (set_new_clone_decl_and_node_flags): Set local
to true iff the node does not have its address taken.

Signed-off-by: Josef Melcr <josef.melcr@suse.com>
gcc/cgraph.cc
gcc/cgraphclones.cc

index 3c21e174943039868a2913bcfa9513377f4b92db..1a7d49922e0979c1be15fc5202f1fd883fe1f6ab 100644 (file)
@@ -1696,8 +1696,12 @@ cgraph_edge::redirect_callee (cgraph_node *n)
       old_ref->remove_reference ();
       ipa_ref *new_ref = caller->create_reference (n, IPA_REF_ADDR, call_stmt);
       new_ref->lto_stmt_uid = lto_stmt_uid;
-      if (!old_callee->referred_to_p ())
+      /* If the last reference to OLD_CALLEE has been redirected, unset
+        address_taken.  old_ref is only used as a placeholder when looking for
+        a different reference.  */
+      if (!old_callee->iterate_referring (0, old_ref))
        old_callee->address_taken = 0;
+      n->mark_address_taken ();
     }
 
   if (!inline_failed)
index 49f0e58fa1ef5b5e64138f02e9ed9b821d7e41fc..816fc53c28a10f5ba481a7473be66f0348c2b302 100644 (file)
@@ -176,7 +176,9 @@ set_new_clone_decl_and_node_flags (cgraph_node *new_node)
   DECL_IS_REPLACEABLE_OPERATOR (new_node->decl) = 0;
 
   new_node->externally_visible = 0;
-  new_node->local = 1;
+  /* Clones of callbacks might have their address taken, and thus cannot be
+     local.  */
+  new_node->local = !new_node->address_taken;
   new_node->lowered = true;
   new_node->semantic_interposition = 0;
 }