Index: docs/UsersManual.rst =================================================================== --- docs/UsersManual.rst +++ docs/UsersManual.rst @@ -1115,6 +1115,14 @@ This flag is enabled by default for sanitizers in the ``cfi`` group. +**-fsanitize-trap-function=[name]** + + Instruct code generator to emit a function call to the specified + function name instead of a trap instruction for checks configured to trap. + + If this flag is not specified, clang will use the value of ``-ftrap-function`` + if specified. + **-f[no-]sanitize-coverage=[type,features,...]** Enable simple code coverage in addition to certain sanitizers. Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -605,6 +605,11 @@ def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group, Flags<[CoreOption]>, HelpText<"Disable trapping for specified sanitizers">; +def fsanitize_trap_function_EQ + : Joined<["-"], "fsanitize-trap-function=">, + Group, Flags<[CC1Option, CoreOption]>, + HelpText<"Make trapping sanitizers issue a call to specified function " + "rather than a trap instruction">; def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">, Group; def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">, Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -201,6 +201,10 @@ /// Set of sanitizer checks that trap rather than diagnose. SanitizerSet SanitizeTrap; + /// If not an empty string, trapping sanitizers will issue calls to this + /// function instead of trap instructions. + std::string SanitizeTrapFuncName; + public: // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -2301,7 +2301,7 @@ } if (TrapCond) - EmitTrapCheck(TrapCond); + EmitSanitizeTrapCheck(TrapCond); if (!FatalCond && !RecoverableCond) return; @@ -2381,7 +2381,18 @@ EmitBlock(Cont); } +void CodeGenFunction::EmitSanitizeTrapCheck(llvm::Value *Checked) { + if (!CGM.getCodeGenOpts().SanitizeTrapFuncName.empty()) { + return EmitTrapCheck(Checked, CGM.getCodeGenOpts().SanitizeTrapFuncName); + } + return EmitTrapCheck(Checked); +} + void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) { + return EmitTrapCheck(Checked, CGM.getCodeGenOpts().TrapFuncName); +} + +void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, const std::string &TrapFuncName) { llvm::BasicBlock *Cont = createBasicBlock("cont"); // If we're optimizing, collapse all calls to trap down to just one per @@ -2390,7 +2401,7 @@ TrapBB = createBasicBlock("trap"); Builder.CreateCondBr(Checked, Cont, TrapBB); EmitBlock(TrapBB); - llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap); + llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap, TrapFuncName); TrapCall->setDoesNotReturn(); TrapCall->setDoesNotThrow(); Builder.CreateUnreachable(); @@ -2402,12 +2413,16 @@ } llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) { + return EmitTrapCall(IntrID, CGM.getCodeGenOpts().TrapFuncName); +} + +llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID, const std::string &TrapFuncName) { llvm::CallInst *TrapCall = Builder.CreateCall(CGM.getIntrinsic(IntrID)); - if (!CGM.getCodeGenOpts().TrapFuncName.empty()) + if (!TrapFuncName.empty()) TrapCall->addAttribute(llvm::AttributeSet::FunctionIndex, "trap-func-name", - CGM.getCodeGenOpts().TrapFuncName); + TrapFuncName); return TrapCall; } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2885,13 +2885,26 @@ ArrayRef DynamicArgs); /// \brief Create a basic block that will call the trap intrinsic, and emit a + /// conditional branch to it, for the -fsanitize checks. + void EmitSanitizeTrapCheck(llvm::Value *Checked); + + /// \brief Create a basic block that will call the trap intrinsic, and emit a /// conditional branch to it, for the -ftrapv checks. void EmitTrapCheck(llvm::Value *Checked); + /// \brief Create a basic block that will call the specified trap function, + /// and emit a conditional branch to it. + void EmitTrapCheck(llvm::Value *Checked, const std::string &TrapFuncName); + /// \brief Emit a call to trap or debugtrap and attach function attribute - /// "trap-func-name" if specified. + /// "trap-func-name" if -ftrap-function is specified. llvm::CallInst *EmitTrapCall(llvm::Intrinsic::ID IntrID); + /// \brief Emit a call to trap or debugtrap and attach function attribute + /// "trap-func-name" if nonempty. + llvm::CallInst *EmitTrapCall(llvm::Intrinsic::ID IntrID, + const std::string &TrapFuncName); + /// \brief Create a check for a function parameter that may potentially be /// declared as non-null. void EmitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc, Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -681,6 +681,7 @@ parseSanitizerKinds("-fsanitize-trap=", Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags, Opts.SanitizeTrap); + Opts.SanitizeTrapFuncName = Args.getLastArgValue(OPT_fsanitize_trap_function_EQ); Opts.CudaGpuBinaryFileNames = Args.getAllArgValues(OPT_fcuda_include_gpubinary); Index: test/CodeGen/sanitize-trap-function.c =================================================================== --- /dev/null +++ test/CodeGen/sanitize-trap-function.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=integer-divide-by-zero -fsanitize-trap=integer-divide-by-zero | FileCheck %s -check-prefix=NONE -check-prefix=CHECK +// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=integer-divide-by-zero -fsanitize-trap=integer-divide-by-zero -ftrap-function=foo | FileCheck %s -check-prefix=TRAP -check-prefix=CHECK +// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=integer-divide-by-zero -fsanitize-trap=integer-divide-by-zero -fsanitize-trap-function=bar | FileCheck %s -check-prefix=SANITIZE -check-prefix=CHECK +// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=integer-divide-by-zero -fsanitize-trap=integer-divide-by-zero -ftrap-function=foo -fsanitize-trap-function=bar | FileCheck %s -check-prefix=SANITIZE -check-prefix=CHECK + +int f(int x, int y) { + // CHECK: call void @llvm.trap() #[[N:[0-9]+]], + // CHECK-NEXT: unreachable + + // NONE-NOT: trap-func-name + // TRAP: attributes #[[N]] {{.+}} "trap-func-name"="foo" + // SANITIZE: attributes #[[N]] {{.+}} "trap-func-name"="bar" + return x / y; +}