https://github.com/PiJoules created 
https://github.com/llvm/llvm-project/pull/170725

Allow the normal rules for preventing instrumentation on indirect calls to 
`cfi_unchecked_callee` function types and `cfi_unchecked_callee` functions when 
using `-fsanitize=function`. While it's technically separate from 
`-fsanitize=cfi`, this particular UBSan mode checks for similar control flow 
bugs so it makes sense to also prevent those control flow checks from being 
added onto `cfi_unchecked_callee` functions.

>From a595020651c2e9f139ed2ed55b5346e53916c01b Mon Sep 17 00:00:00 2001
From: Leonard Chan <[email protected]>
Date: Thu, 4 Dec 2025 11:20:16 -0800
Subject: [PATCH] [clang] Apply cfi_unchecked_callee rules to
 -fsanitize=function

Allow the normal rules for preventing instrumentation on indirect calls
to `cfi_unchecked_callee` function types and `cfi_unchecked_callee`
functions when using `-fsanitize=function`. While it's technically
separate from `-fsanitize=cfi`, this particular UBSan mode checks for
similar control flow bugs so it makes sense to also prevent those
control flow checks from being added onto `cfi_unchecked_callee`
functions.
---
 clang/docs/ReleaseNotes.rst           |  3 +++
 clang/include/clang/Basic/AttrDocs.td |  4 +++-
 clang/lib/CodeGen/CGExpr.cpp          |  8 ++++----
 clang/lib/CodeGen/CodeGenFunction.cpp |  3 ++-
 clang/test/CodeGen/ubsan-function.cpp | 17 +++++++++++++++++
 5 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 654a8e48cd104..b8734a8f311b6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -353,6 +353,9 @@ Attribute Changes in Clang
   attribute, allowing the attribute to only be attached to the declaration. 
Prior, this would be
   treated as an error where the definition and declaration would have 
differing types.
 
+- Instrumentation added by ``-fsanitize=function`` will also be omitted for 
indirect calls to function
+  pointers and function declarations marked with 
``[[clang::cfi_unchecked_callee]]``.
+
 - New format attributes ``gnu_printf``, ``gnu_scanf``, ``gnu_strftime`` and 
``gnu_strfmon`` are added
   as aliases for ``printf``, ``scanf``, ``strftime`` and ``strfmon``. 
(#GH16219)
 
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index ae929c7dea37d..60ea11504a04a 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -7065,7 +7065,9 @@ def CFIUncheckedCalleeDocs : Documentation {
   let Content = [{
 ``cfi_unchecked_callee`` is a function type attribute which prevents the 
compiler from instrumenting
 `Control Flow Integrity 
<https://clang.llvm.org/docs/ControlFlowIntegrity.html>`_ checks on indirect
-function calls. Specifically, the attribute has the following semantics:
+function calls. This also includes control flow checks added by
+`-fsanitize=function 
<https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks>`.
+Specifically, the attribute has the following semantics:
 
 1. Indirect calls to a function type with this attribute will not be 
instrumented with CFI. That is,
    the indirect call will not be checked. Note that this only changes the 
behavior for indirect calls
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index e842158236cd4..67944ab2e3929 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -6520,9 +6520,12 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
 
   CGCallee Callee = OrigCallee;
 
+  bool CFIUnchecked =
+      CalleeType->hasPointeeToToCFIUncheckedCalleeFunctionType();
+
   if (SanOpts.has(SanitizerKind::Function) &&
       (!TargetDecl || !isa<FunctionDecl>(TargetDecl)) &&
-      !isa<FunctionNoProtoType>(PointeeType)) {
+      !isa<FunctionNoProtoType>(PointeeType) && !CFIUnchecked) {
     if (llvm::Constant *PrefixSig =
             CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
       auto CheckOrdinal = SanitizerKind::SO_Function;
@@ -6601,9 +6604,6 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
       FD && 
DeviceKernelAttr::isOpenCLSpelling(FD->getAttr<DeviceKernelAttr>()))
     CGM.getTargetCodeGenInfo().setOCLKernelStubCallingConvention(FnType);
 
-  bool CFIUnchecked =
-      CalleeType->hasPointeeToToCFIUncheckedCalleeFunctionType();
-
   // If we are checking indirect calls and this call is indirect, check that 
the
   // function pointer is a member of the bit set for the function type.
   if (SanOpts.has(SanitizerKind::CFIICall) &&
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
index ac25bd95f0463..0e3e7b11c4a26 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1037,7 +1037,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, 
QualType RetTy,
 
   // If we are checking function types, emit a function type signature as
   // prologue data.
-  if (FD && SanOpts.has(SanitizerKind::Function)) {
+  if (FD && SanOpts.has(SanitizerKind::Function) &&
+      !FD->getType()->isCFIUncheckedCalleeFunctionType()) {
     if (llvm::Constant *PrologueSig = getPrologueSignature(CGM, FD)) {
       llvm::LLVMContext &Ctx = Fn->getContext();
       llvm::MDBuilder MDB(Ctx);
diff --git a/clang/test/CodeGen/ubsan-function.cpp 
b/clang/test/CodeGen/ubsan-function.cpp
index 76d4237383f83..bc43942635a7b 100644
--- a/clang/test/CodeGen/ubsan-function.cpp
+++ b/clang/test/CodeGen/ubsan-function.cpp
@@ -41,5 +41,22 @@ void fun() {}
 // CHECK-NEXT:   ret void
 void caller(void (*f)()) { f(); }
 
+// GNU:  define{{.*}} void @_Z4fun2v() #0 {
+// MSVC: define{{.*}} void @"?fun2@@YAXXZ"() #0 {
+[[clang::cfi_unchecked_callee]]
+void fun2() {}
+
+typedef void (*unchecked_t)() [[clang::cfi_unchecked_callee]];
+
+// GNU-LABEL:  define{{.*}} void @_Z7caller2PFvvE(ptr noundef %f)
+// MSVC-LABEL: define{{.*}} void @"?caller2@@YAXP6AXXZ@Z"(ptr noundef %f)
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   [[ADDR:%.*]] = alloca ptr
+// CHECK-NEXT:   store ptr %f, ptr [[ADDR]]
+// CHECK-NEXT:   [[FUNC:%.*]] = load ptr, ptr [[ADDR]]
+// CHECK-NEXT:   call void [[FUNC]]()
+// CHECK-NEXT:   ret void
+void caller2(unchecked_t f) { f(); }
+
 // GNU:  ![[FUNCSAN]] = !{i32 -1056584962, i32 905068220}
 // MSVC: ![[FUNCSAN]] = !{i32 -1056584962, i32 -1600339357}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to