From 48a399f2a1c2ec912ab52c6b5266d2008d9c1276 Mon Sep 17 00:00:00 2001 From: Nikolai Kholiavin Date: Wed, 3 Jul 2024 15:16:16 +0300 Subject: [PATCH] [CFI][clang][CodeGen] Introduce option to replace cfi-specific trapping function Adds `-fcfi-trap-function=` option to replace only the cfi-specific trapping function, as opposed to `-ftrap-function=` specifying the trapping function to call for all traps. Please note that this is a temporary solution and should be reverted in the future. Issue: https://gitee.com/openharmony/third_party_llvm-project/issues/IA9OQO Change-Id: I55158ddbf76a65f51d11087bccac02b72427843c Signed-off-by: Nikolai Kholiavin --- clang/include/clang/Basic/CodeGenOptions.h | 8 +++++ clang/include/clang/Driver/Options.td | 5 +++ clang/lib/CodeGen/CGExpr.cpp | 19 ++++++++-- clang/lib/Driver/ToolChains/Clang.cpp | 2 ++ .../cfi-cross-dso-trap-function.cpp | 15 ++++++++ clang/test/CodeGenCXX/cfi-trap-function.cpp | 35 +++++++++++++++++++ 6 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGenCXX/cfi-cross-dso-trap-function.cpp create mode 100644 clang/test/CodeGenCXX/cfi-trap-function.cpp diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index cd204e5d7c15..5e12e15a1a93 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -237,6 +237,14 @@ public: /// function instead of to trap instructions. std::string TrapFuncName; + // OHOS_LOCAL begin + + /// If not an empty string, cfi check fail trap intrinsics are lowered to + /// calls to this function instead of to trap instructions. + std::string CfiTrapFuncName; + + // OHOS_LOCAL end + /// A list of dependent libraries. std::vector DependentLibraries; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 670ba4ffb390..ac89e170da94 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2909,6 +2909,11 @@ def ftrapv_handler : Separate<["-"], "ftrapv-handler">, Group, Flags<[C def ftrap_function_EQ : Joined<["-"], "ftrap-function=">, Group, Flags<[CC1Option]>, HelpText<"Issue call to specified function rather than a trap instruction">, MarshallingInfoString>; +// OHOS_LOCAL begin +def fcfi_trap_function_EQ : Joined<["-"], "fcfi-trap-function=">, Group, Flags<[CC1Option]>, + HelpText<"Issue call to specified function rather than a trap instruction for failed cfi checks">, + MarshallingInfoString>; +// OHOS_LOCAL end def funroll_loops : Flag<["-"], "funroll-loops">, Group, HelpText<"Turn on loop unroller">, Flags<[CC1Option]>; def fno_unroll_loops : Flag<["-"], "fno-unroll-loops">, Group, diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 9df9776504bc..dd940827b34d 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3592,6 +3592,18 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID) { llvm::BasicBlock *Cont = createBasicBlock("cont"); + // OHOS_LOCAL begin + std::string TrapFuncName = CGM.getCodeGenOpts().TrapFuncName; + switch (CheckHandlerID) { + case SanitizerHandler::CFICheckFail: + if (!CGM.getCodeGenOpts().CfiTrapFuncName.empty()) + TrapFuncName = CGM.getCodeGenOpts().CfiTrapFuncName; + break; + default: + break; + } + // OHOS_LOCAL end + // If we're optimizing, collapse all calls to trap down to just one per // check-type per function to save on code size. if (TrapBBs.size() <= CheckHandlerID) @@ -3606,12 +3618,13 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, llvm::CallInst *TrapCall = Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap), llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID)); - - if (!CGM.getCodeGenOpts().TrapFuncName.empty()) { + // OHOS_LOCAL begin + if (!TrapFuncName.empty()) { auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name", - CGM.getCodeGenOpts().TrapFuncName); + TrapFuncName); TrapCall->addFnAttr(A); } + // OHOS_LOCAL end TrapCall->setDoesNotReturn(); TrapCall->setDoesNotThrow(); Builder.CreateUnreachable(); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index dcd86ddf1fa1..93001072a32a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6305,6 +6305,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fcfi_trap_function_EQ); // OHOS_LOCAL + // -fno-strict-overflow implies -fwrapv if it isn't disabled, but // -fstrict-overflow won't turn off an explicitly enabled -fwrapv. if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) { diff --git a/clang/test/CodeGenCXX/cfi-cross-dso-trap-function.cpp b/clang/test/CodeGenCXX/cfi-cross-dso-trap-function.cpp new file mode 100644 index 000000000000..10eeb401aa65 --- /dev/null +++ b/clang/test/CodeGenCXX/cfi-cross-dso-trap-function.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux -O0 -fsanitize-cfi-cross-dso \ +// RUN: -fsanitize=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast \ +// RUN: -fsanitize-trap=cfi-icall,cfi-nvcall -fsanitize-recover=cfi-vcall,cfi-unrelated-cast \ +// RUN: -fcfi-trap-function=cfi_trap_function \ +// RUN: -emit-llvm -o - %s | FileCheck %s + +void caller(void (*f)(void)) { + f(); +} + +// CHECK: define weak_odr hidden void @__cfi_check_fail(ptr noundef %0, ptr noundef %1) +// CHECK: call void @llvm.ubsantrap({{.*}}) #[[#CFIATTR:]] +// CHECK-NEXT: unreachable + +// CHECK: attributes #[[#CFIATTR]] = { {{.*}}"trap-func-name"="cfi_trap_function" } diff --git a/clang/test/CodeGenCXX/cfi-trap-function.cpp b/clang/test/CodeGenCXX/cfi-trap-function.cpp new file mode 100644 index 000000000000..52e10ce22b1a --- /dev/null +++ b/clang/test/CodeGenCXX/cfi-trap-function.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fcfi-trap-function=cfi_trap_function -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,CHECK-NTF %s +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fcfi-trap-function=cfi_trap_function -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,CHECK-NTF %s + +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fcfi-trap-function=cfi_trap_function -ftrap-function=trap_function -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,CHECK-TF %s +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fcfi-trap-function=cfi_trap_function -ftrap-function=trap_function -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,CHECK-TF %s + +namespace { + +struct S {}; + +void f(S s) { +} + +} + +// CHECK: define{{.*}}g_func +void g_func() { + struct S s; + void (*fp)(S) = f; + // CHECK: call i1 @llvm.type.test( + fp(s); + // CHECK: call void @llvm.ubsantrap({{.*}}) #[[#CFIATTR:]] + // CHECK-NEXT: unreachable +} + +// CHECK: define{{.*}}h_func +void h_func() { + __builtin_trap(); +// CHECK-NTF-NOT: call void @llvm.trap() # +// CHECK-NTF: call void @llvm.trap() +// CHECK-TF: call void @llvm.trap() #[[#ATTR:]] +} + +// CHECK: attributes #[[#CFIATTR]] = { {{.*}}"trap-func-name"="cfi_trap_function" } +// CHECK-TF: attributes #[[#ATTR]] = { {{.*}}"trap-func-name"="trap_function" } -- Gitee