diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index cd204e5d7c150fb829ee6d4783abb88a1f209a63..5e12e15a1a93cb5ec7979e537c6af8a0dd41ae1e 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 670ba4ffb390d4285b1bab933074d738d0c50aba..ac89e170da94596e58a70f7e92e3a0d8dbc307ce 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 9df9776504bc4ec847e87653827f66bf3007d437..dd940827b34d2ae39e676c22c689dc40576bc5c7 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 dcd86ddf1fa1a7ef7e6abb5d05ccc26cb28821b6..93001072a32a104d94042c701585238607febfbd 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 0000000000000000000000000000000000000000..10eeb401aa65f97dbb2ea7fee86dabe3a13ec4ef --- /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 0000000000000000000000000000000000000000..52e10ce22b1a086c1c69ddfc7122b56ebec0fe62 --- /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" }