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
