[llvm] 8228749 - [CFGuard] Consider function aliases as indirect call targets (#188223)

via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 24 10:55:52 PDT 2026


Author: Hans Wennborg
Date: 2026-03-24T18:55:46+01:00
New Revision: 82287496072bef952bd400c335459f4fa4c750c7

URL: https://github.com/llvm/llvm-project/commit/82287496072bef952bd400c335459f4fa4c750c7
DIFF: https://github.com/llvm/llvm-project/commit/82287496072bef952bd400c335459f4fa4c750c7.diff

LOG: [CFGuard] Consider function aliases as indirect call targets (#188223)

With vector deleting destructors, it's common to include function
aliases in vftables.

After #185653 it's become more likely that the alias gets overridden in
a different TU. It's therefore important that it's the alias itself that
goes in the control-flow guard table.

Added: 
    llvm/test/CodeGen/WinCFGuard/cfguard-alias.ll

Modified: 
    llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp b/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp
index d989659566355..4644a170d62a5 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp
@@ -42,14 +42,14 @@ void WinCFGuard::endFunction(const MachineFunction *MF) {
 /// it an indirect call target. Function::hasAddressTaken gives 
diff erent
 /// results when a function is called directly with a function prototype
 /// mismatch, which requires a cast.
-static bool isPossibleIndirectCallTarget(const Function *F) {
-  SmallVector<const Value *, 4> Users{F};
+static bool isPossibleIndirectCallTarget(const GlobalValue *GV) {
+  SmallVector<const Value *, 4> Users{GV};
   while (!Users.empty()) {
     const Value *FnOrCast = Users.pop_back_val();
     for (const Use &U : FnOrCast->uses()) {
       const User *FnUser = U.getUser();
       if (const auto *Call = dyn_cast<CallBase>(FnUser)) {
-        if ((!Call->isCallee(&U) || U.get() != F) &&
+        if ((!Call->isCallee(&U) || U.get() != GV) &&
             !Call->getFunction()->getName().ends_with("$exit_thunk")) {
           // Passing a function pointer to a call may lead to an indirect
           // call. As an exception, ignore ARM64EC exit thunks.
@@ -60,6 +60,10 @@ static bool isPossibleIndirectCallTarget(const Function *F) {
         // consequences like no-op intrinsics being an escape or a store *to* a
         // function address being an escape.
         return true;
+      } else if (isa<GlobalAlias>(FnUser)) {
+        // If the function is used via the alias, it's really the alias that's
+        // a possible call target. See "Consider aliases" in endModule().
+        continue;
       } else if (const auto *G = dyn_cast<GlobalValue>(FnUser)) {
         // Ignore llvm.arm64ec.symbolmap; it doesn't lower to an actual address.
         if (G->getName() == "llvm.arm64ec.symbolmap")
@@ -104,6 +108,13 @@ void WinCFGuard::endModule() {
     }
   }
 
+  for (const GlobalAlias &GA : M->aliases()) {
+    // Consider aliases to functions as possible call targets.
+    const GlobalObject *Aliasee = GA.getAliaseeObject();
+    if (Aliasee && isa<Function>(Aliasee) && isPossibleIndirectCallTarget(&GA))
+      GFIDsEntries.push_back(Asm->getSymbol(&GA));
+  }
+
   if (GFIDsEntries.empty() && GIATsEntries.empty() && LongjmpTargets.empty())
     return;
 

diff  --git a/llvm/test/CodeGen/WinCFGuard/cfguard-alias.ll b/llvm/test/CodeGen/WinCFGuard/cfguard-alias.ll
new file mode 100644
index 0000000000000..23d044800a44e
--- /dev/null
+++ b/llvm/test/CodeGen/WinCFGuard/cfguard-alias.ll
@@ -0,0 +1,28 @@
+; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc | FileCheck %s
+
+; CHECK:     .section .gfids$y
+; CHECK:     .symidx alias
+; CHECK-NOT: .symidx calledalias
+; CHECK-NOT: .symidx func
+
+
+define void @func() {
+  ret void
+}
+
+ at alias = alias ptr, ptr @func
+
+; This makes @alias a potential indirect call target.
+; The aliasee (@func) is not considered as such.
+ at ptrs = global [1 x ptr] [ptr @alias]
+
+ at calledalias = alias ptr, ptr @func
+
+define void @caller() {
+  ; A direct call does not make the alias an indirect call target.
+  call void @calledalias()
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"cfguard", i32 2}


        


More information about the llvm-commits mailing list