Index: tools/clang/include/clang/Driver/Options.td =================================================================== --- tools/clang/include/clang/Driver/Options.td +++ tools/clang/include/clang/Driver/Options.td @@ -605,6 +605,9 @@ 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<"Issue 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: tools/clang/include/clang/Frontend/CodeGenOptions.h =================================================================== --- tools/clang/include/clang/Frontend/CodeGenOptions.h +++ tools/clang/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, trap intrinsics are lowered to calls to this + /// function instead of to trap instructions. + std::string SanitizeTrapFuncName; + public: // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) Index: tools/clang/lib/CodeGen/CGExpr.cpp =================================================================== --- tools/clang/lib/CodeGen/CGExpr.cpp +++ tools/clang/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(); @@ -2401,13 +2412,24 @@ EmitBlock(Cont); } +llvm::CallInst *CodeGenFunction::EmitSanitizeTrapCall(llvm::Intrinsic::ID IntrID) { + if (!CGM.getCodeGenOpts().SanitizeTrapFuncName.empty()) { + return EmitTrapCall(IntrID, CGM.getCodeGenOpts().SanitizeTrapFuncName); + } + return EmitTrapCall(IntrID); +} + 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: tools/clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- tools/clang/lib/CodeGen/CGExprScalar.cpp +++ tools/clang/lib/CodeGen/CGExprScalar.cpp @@ -2383,7 +2383,7 @@ : SanitizerKind::UnsignedIntegerOverflow; EmitBinOpCheck(std::make_pair(NotOverflow, Kind), Ops); } else - CGF.EmitTrapCheck(Builder.CreateNot(overflow)); + CGF.EmitSanitizeTrapCheck(Builder.CreateNot(overflow)); return result; } Index: tools/clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- tools/clang/lib/CodeGen/CodeGenFunction.h +++ tools/clang/lib/CodeGen/CodeGenFunction.h @@ -2886,11 +2886,16 @@ /// \brief Create a basic block that will call the trap intrinsic, and emit a /// conditional branch to it, for the -ftrapv checks. + void EmitSanitizeTrapCheck(llvm::Value *Checked); void EmitTrapCheck(llvm::Value *Checked); + 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. + llvm::CallInst *EmitSanitizeTrapCall(llvm::Intrinsic::ID IntrID); llvm::CallInst *EmitTrapCall(llvm::Intrinsic::ID IntrID); + 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. Index: tools/clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- tools/clang/lib/Frontend/CompilerInvocation.cpp +++ tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -504,6 +504,7 @@ << Args.getLastArg(OPT_mthread_model)->getAsString(Args) << Opts.ThreadModel; Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ); + Opts.SanitizeTrapFuncName = Args.getLastArgValue(OPT_fsanitize_trap_function_EQ); Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array); Opts.FunctionSections = Args.hasFlag(OPT_ffunction_sections, Index: tools/clang/test/CodeGen/sanitize-trap-function.c =================================================================== --- /dev/null +++ tools/clang/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; +}