From 9881b78b53dd295f7ee63bf33c99d68b73c2f289 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 18 Jun 2015 23:59:22 +0000 Subject: [PATCH] Introduce -fsanitize-trap= flag. This flag controls whether a given sanitizer traps upon detecting an error. It currently only supports UBSan. The existing flag -fsanitize-undefined-trap-on-error has been made an alias of -fsanitize-trap=undefined. This change also cleans up some awkward behavior around the combination of -fsanitize-trap=undefined and -fsanitize=undefined. Previously we would reject command lines containing the combination of these two flags, as -fsanitize=vptr is not compatible with trapping. This required the creation of -fsanitize=undefined-trap, which excluded -fsanitize=vptr (and -fsanitize=function, but this seems like an oversight). Now, -fsanitize=undefined is an alias for -fsanitize=undefined-trap, and if -fsanitize-trap=undefined is specified, we treat -fsanitize=vptr as an "unsupported" flag, which means that we error out if the flag is specified explicitly, but implicitly disable it if the flag was implied by -fsanitize=undefined. Differential Revision: http://reviews.llvm.org/D10464 llvm-svn: 240105 --- clang/docs/UsersManual.rst | 46 +++++++++---- clang/include/clang/Basic/Sanitizers.def | 15 ++-- clang/include/clang/Driver/Options.td | 7 +- clang/include/clang/Driver/SanitizerArgs.h | 2 +- clang/include/clang/Frontend/CodeGenOptions.def | 2 - clang/include/clang/Frontend/CodeGenOptions.h | 3 + clang/lib/CodeGen/CGExpr.cpp | 24 +++---- clang/lib/Driver/SanitizerArgs.cpp | 92 ++++++++++++++++++++----- clang/lib/Frontend/CompilerInvocation.cpp | 5 +- clang/test/CodeGen/bounds-checking.c | 2 +- clang/test/CodeGen/catch-undef-behavior.c | 2 +- clang/test/CodeGen/sanitize-trap.c | 25 +++++++ clang/test/Driver/fsanitize.c | 19 +++-- 13 files changed, 177 insertions(+), 67 deletions(-) create mode 100644 clang/test/CodeGen/sanitize-trap.c diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index fdc52f8..ccf15e9 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -970,12 +970,9 @@ are listed below. includes all of the checks listed below other than ``unsigned-integer-overflow``. - - ``-fsanitize=undefined-trap``: This includes all sanitizers - included by ``-fsanitize=undefined``, except those that require - runtime support. This group of sanitizers is intended to be - used in conjunction with the ``-fsanitize-undefined-trap-on-error`` - flag. This includes all of the checks listed below other than - ``unsigned-integer-overflow`` and ``vptr``. + - ``-fsanitize=undefined-trap``: This is a deprecated alias for + ``-fsanitize=undefined``. + - ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data flow analysis. - ``-fsanitize=cfi``: :doc:`control flow integrity ` @@ -1069,15 +1066,6 @@ are listed below. through. This mode may use extra memory in programs that copy uninitialized memory a lot. - Extra features of UndefinedBehaviorSanitizer: - - - ``-fsanitize-undefined-trap-on-error``: Causes traps to be emitted - rather than calls to runtime libraries when a problem is detected. - This option is intended for use in cases where the sanitizer runtime - cannot be used (for instance, when building libc or a kernel module). - This is only compatible with the sanitizers in the ``undefined-trap`` - group. - The ``-fsanitize=`` argument must also be provided when linking, in order to link to the appropriate runtime library. When using ``-fsanitize=vptr`` (or a group that includes it, such as @@ -1101,11 +1089,39 @@ are listed below. sanitizers (e.g. :doc:`AddressSanitizer`) may not support recovery, and always crash the program after the issue is detected. + Note that the ``-fsanitize-trap`` flag has precedence over this flag. + This means that if a check has been configured to trap elsewhere on the + command line, or if the check traps by default, this flag will not have + any effect unless that sanitizer's trapping behavior is disabled with + ``-fno-sanitize-trap``. + + For example, if a command line contains the flags ``-fsanitize=undefined + -fsanitize-trap=undefined``, the flag ``-fsanitize-recover=alignment`` + will have no effect on its own; it will need to be accompanied by + ``-fno-sanitize-trap=alignment``. + +**-f[no-]sanitize-trap=check1,check2,...** + + Controls which checks enabled by the ``-fsanitize=`` flag trap. This + option is intended for use in cases where the sanitizer runtime cannot + be used (for instance, when building libc or a kernel module), or where + the binary size increase caused by the sanitizer runtime is a concern. + + This flag is only compatible with ``local-bounds``, + ``unsigned-integer-overflow`` and sanitizers in the ``undefined`` + group other than ``vptr``. If this flag is supplied together with + ``-fsanitize=undefined``, the ``vptr`` sanitizer will be implicitly + disabled. + **-f[no-]sanitize-coverage=[type,features,...]** Enable simple code coverage in addition to certain sanitizers. See :doc:`SanitizerCoverage` for more details. +.. option:: -fsanitize-undefined-trap-on-error + + Deprecated alias for ``-fsanitize-trap=undefined``. + .. option:: -fno-assume-sane-operator-new Don't assume that the C++'s new operator is sane. diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index c50f3e1..9e341ae 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -90,18 +90,17 @@ SANITIZER_GROUP("cfi", CFI, // Safe Stack SANITIZER("safe-stack", SafeStack) -// -fsanitize=undefined-trap includes sanitizers from -fsanitize=undefined -// that can be used without runtime support, generally by providing extra -// -fsanitize-undefined-trap-on-error flag. -SANITIZER_GROUP("undefined-trap", UndefinedTrap, +// -fsanitize=undefined includes all the sanitizers which have low overhead, no +// ABI or address space layout implications, and only catch undefined behavior. +SANITIZER_GROUP("undefined", Undefined, Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow | FloatDivideByZero | IntegerDivideByZero | NonnullAttribute | Null | ObjectSize | Return | ReturnsNonnullAttribute | - Shift | SignedIntegerOverflow | Unreachable | VLABound) + Shift | SignedIntegerOverflow | Unreachable | VLABound | + Function | Vptr) -// -fsanitize=undefined includes all the sanitizers which have low overhead, no -// ABI or address space layout implications, and only catch undefined behavior. -SANITIZER_GROUP("undefined", Undefined, UndefinedTrap | Function | Vptr) +// -fsanitize=undefined-trap is an alias for -fsanitize=undefined. +SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined) SANITIZER_GROUP("integer", Integer, SignedIntegerOverflow | UnsignedIntegerOverflow | Shift | diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index d5f316b..aae37769 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -561,8 +561,13 @@ def fno_sanitize_recover_EQ : CommaJoined<["-"], "fno-sanitize-recover=">, Group, HelpText<"Disable recovery for specified sanitizers">; +def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group, + Flags<[CC1Option, CoreOption]>, + HelpText<"Enable trapping for specified sanitizers">; +def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group, + HelpText<"Disable trapping for specified sanitizers">; def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">, - Group, Flags<[CC1Option]>; + Group; def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">, Group; def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">, diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 5edd230..aca43ec 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -23,13 +23,13 @@ class ToolChain; class SanitizerArgs { SanitizerSet Sanitizers; SanitizerSet RecoverableSanitizers; + SanitizerSet TrapSanitizers; std::vector BlacklistFiles; int CoverageFeatures; int MsanTrackOrigins; int AsanFieldPadding; bool AsanZeroBaseShadow; - bool UbsanTrapOnError; bool AsanSharedRuntime; bool LinkCXXRuntimes; diff --git a/clang/include/clang/Frontend/CodeGenOptions.def b/clang/include/clang/Frontend/CodeGenOptions.def index adf1c87..d34cf0c 100644 --- a/clang/include/clang/Frontend/CodeGenOptions.def +++ b/clang/include/clang/Frontend/CodeGenOptions.def @@ -120,8 +120,6 @@ CODEGENOPT(SanitizeCoverageTraceCmp, 1, 0) ///< Enable cmp instruction tracing ///< in sanitizer coverage. CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters ///< in sanitizer coverage. -CODEGENOPT(SanitizeUndefinedTrapOnError, 1, 0) ///< Set on - /// -fsanitize-undefined-trap-on-error CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled. CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float. CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition. diff --git a/clang/include/clang/Frontend/CodeGenOptions.h b/clang/include/clang/Frontend/CodeGenOptions.h index 0c5ce58..66597bd 100644 --- a/clang/include/clang/Frontend/CodeGenOptions.h +++ b/clang/include/clang/Frontend/CodeGenOptions.h @@ -197,6 +197,9 @@ public: /// continued when possible). SanitizerSet SanitizeRecover; + /// Set of sanitizer checks that trap rather than diagnose. + SanitizerSet SanitizeTrap; + public: // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 1ed45a3..85746ae 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2300,15 +2300,24 @@ void CodeGenFunction::EmitCheck( llvm::Value *FatalCond = nullptr; llvm::Value *RecoverableCond = nullptr; + llvm::Value *TrapCond = nullptr; for (int i = 0, n = Checked.size(); i < n; ++i) { llvm::Value *Check = Checked[i].first; + // -fsanitize-trap= overrides -fsanitize-recover=. llvm::Value *&Cond = - CGM.getCodeGenOpts().SanitizeRecover.has(Checked[i].second) - ? RecoverableCond - : FatalCond; + CGM.getCodeGenOpts().SanitizeTrap.has(Checked[i].second) + ? TrapCond + : CGM.getCodeGenOpts().SanitizeRecover.has(Checked[i].second) + ? RecoverableCond + : FatalCond; Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check; } + if (TrapCond) + EmitTrapCheck(TrapCond); + if (!FatalCond && !RecoverableCond) + return; + llvm::Value *JointCond; if (FatalCond && RecoverableCond) JointCond = Builder.CreateAnd(FatalCond, RecoverableCond); @@ -2326,15 +2335,6 @@ void CodeGenFunction::EmitCheck( } #endif - if (CGM.getCodeGenOpts().SanitizeUndefinedTrapOnError) { - assert(RecoverKind != CheckRecoverableKind::AlwaysRecoverable && - "Runtime call required for AlwaysRecoverable kind!"); - // Assume that -fsanitize-undefined-trap-on-error overrides - // -fsanitize-recover= options, as we can only print meaningful error - // message and recover if we have a runtime support. - return EmitTrapCheck(JointCond); - } - llvm::BasicBlock *Cont = createBasicBlock("cont"); llvm::BasicBlock *Handlers = createBasicBlock("handler." + CheckName); llvm::Instruction *Branch = Builder.CreateCondBr(JointCond, Cont, Handlers); diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 72530b4..fee6e8f 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -34,6 +34,8 @@ enum : SanitizerMask { Unrecoverable = Address | Unreachable | Return, LegacyFsanitizeRecoverMask = Undefined | Integer, NeedsLTO = CFI, + TrappingSupported = + (Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds, }; enum CoverageFeature { @@ -116,8 +118,59 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds, return false; } +/// Sets group bits for every group that has at least one representative already +/// enabled in \p Kinds. +static SanitizerMask setGroupBits(SanitizerMask Kinds) { +#define SANITIZER(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + if (Kinds & SanitizerKind::ID) \ + Kinds |= SanitizerKind::ID##Group; +#include "clang/Basic/Sanitizers.def" + return Kinds; +} + +static SanitizerMask parseSanitizeTrapArgs(const Driver &D, + const llvm::opt::ArgList &Args) { + SanitizerMask TrapRemove = 0; // During the loop below, the accumulated set of + // sanitizers disabled by the current sanitizer + // argument or any argument after it. + SanitizerMask TrappingKinds = 0; + SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported); + + for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); + I != E; ++I) { + const auto *Arg = *I; + if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) { + Arg->claim(); + SanitizerMask Add = parseArgValues(D, Arg, true); + Add &= ~TrapRemove; + if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) { + SanitizerSet S; + S.Mask = InvalidValues; + D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap" + << toString(S); + } + TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; + } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { + Arg->claim(); + TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true)); + } else if (Arg->getOption().matches( + options::OPT_fsanitize_undefined_trap_on_error)) { + Arg->claim(); + TrappingKinds |= + expandSanitizerGroups(UndefinedGroup & ~TrapRemove) & ~TrapRemove; + } else if (Arg->getOption().matches( + options::OPT_fno_sanitize_undefined_trap_on_error)) { + Arg->claim(); + TrapRemove |= expandSanitizerGroups(UndefinedGroup); + } + } + + return TrappingKinds; +} + bool SanitizerArgs::needsUbsanRt() const { - return !UbsanTrapOnError && (Sanitizers.Mask & NeedsUbsanRt) && + return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) && !Sanitizers.has(Address) && !Sanitizers.has(Memory) && !Sanitizers.has(Thread); @@ -138,12 +191,12 @@ bool SanitizerArgs::needsLTO() const { void SanitizerArgs::clear() { Sanitizers.clear(); RecoverableSanitizers.clear(); + TrapSanitizers.clear(); BlacklistFiles.clear(); CoverageFeatures = 0; MsanTrackOrigins = 0; AsanFieldPadding = 0; AsanZeroBaseShadow = false; - UbsanTrapOnError = false; AsanSharedRuntime = false; LinkCXXRuntimes = false; } @@ -166,6 +219,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); const Driver &D = TC.getDriver(); + SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); + NotSupported |= TrappingKinds & NotAllowedWithTrap; + for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); I != E; ++I) { const auto *Arg = *I; @@ -180,7 +236,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // sanitizers in Add are those which have been explicitly enabled. // Diagnose them. if (SanitizerMask KindsToDiagnose = - Add & NotSupported & ~DiagnosedKinds) { + Add & TrappingKinds & NotAllowedWithTrap & ~DiagnosedKinds) { + std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); + D.Diag(diag::err_drv_argument_not_allowed_with) + << Desc << "-fsanitize-trap=undefined"; + DiagnosedKinds |= KindsToDiagnose; + Add &= ~KindsToDiagnose; + } + if (SanitizerMask KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) { // Only diagnose the new kinds. std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); D.Diag(diag::err_drv_unsupported_opt_for_target) @@ -234,17 +297,6 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Kinds &= ~Vptr; } - // Warn about undefined sanitizer options that require runtime support. - UbsanTrapOnError = - Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, false); - if (UbsanTrapOnError && (Kinds & NotAllowedWithTrap)) { - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << lastArgumentForMask(D, Args, NotAllowedWithTrap) - << "-fsanitize-undefined-trap-on-error"; - Kinds &= ~NotAllowedWithTrap; - } - // Warn about incompatible groups of sanitizers. std::pair IncompatibleGroups[] = { std::make_pair(Address, Thread), std::make_pair(Address, Memory), @@ -305,6 +357,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, RecoverableKinds &= Kinds; RecoverableKinds &= ~Unrecoverable; + TrappingKinds &= Kinds; + // Setup blacklist files. // Add default blacklist from resource directory. { @@ -460,6 +514,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Finally, initialize the set of available and recoverable sanitizers. Sanitizers.Mask |= Kinds; RecoverableSanitizers.Mask |= RecoverableKinds; + TrapSanitizers.Mask |= TrappingKinds; } static std::string toString(const clang::SanitizerSet &Sanitizers) { @@ -484,8 +539,9 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" + toString(RecoverableSanitizers))); - if (UbsanTrapOnError) - CmdArgs.push_back("-fsanitize-undefined-trap-on-error"); + if (!TrapSanitizers.empty()) + CmdArgs.push_back( + Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); for (const auto &BLPath : BlacklistFiles) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); @@ -528,7 +584,9 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, assert((A->getOption().matches(options::OPT_fsanitize_EQ) || A->getOption().matches(options::OPT_fno_sanitize_EQ) || A->getOption().matches(options::OPT_fsanitize_recover_EQ) || - A->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) && + A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) || + A->getOption().matches(options::OPT_fsanitize_trap_EQ) || + A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) && "Invalid argument in parseArgValues!"); SanitizerMask Kinds = 0; for (int i = 0, n = A->getNumValues(); i != n; ++i) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 9c09ff5..8546763 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -555,8 +555,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_fsanitize_coverage_8bit_counters); Opts.SanitizeMemoryTrackOrigins = getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); - Opts.SanitizeUndefinedTrapOnError = - Args.hasArg(OPT_fsanitize_undefined_trap_on_error); Opts.SSPBufferSize = getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); @@ -666,6 +664,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, parseSanitizerKinds("-fsanitize-recover=", Args.getAllArgValues(OPT_fsanitize_recover_EQ), Diags, Opts.SanitizeRecover); + parseSanitizerKinds("-fsanitize-trap=", + Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags, + Opts.SanitizeTrap); Opts.CudaGpuBinaryFileNames = Args.getAllArgValues(OPT_fcuda_include_gpubinary); diff --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c index d93cd3e..90b7f0f6 100644 --- a/clang/test/CodeGen/bounds-checking.c +++ b/clang/test/CodeGen/bounds-checking.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsanitize=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s -// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-undefined-trap-on-error -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s +// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s // CHECK-LABEL: @f double f(int b, int i) { diff --git a/clang/test/CodeGen/catch-undef-behavior.c b/clang/test/CodeGen/catch-undef-behavior.c index 6695419..7875536 100644 --- a/clang/test/CodeGen/catch-undef-behavior.c +++ b/clang/test/CodeGen/catch-undef-behavior.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift-base,shift-exponent,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift-base,shift-exponent,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-UBSAN -// RUN: %clang_cc1 -fsanitize-undefined-trap-on-error -fsanitize=alignment,null,object-size,shift-base,shift-exponent,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift-base,shift-exponent,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-TRAP +// RUN: %clang_cc1 -fsanitize-trap=alignment,null,object-size,shift-base,shift-exponent,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift-base,shift-exponent,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize=alignment,null,object-size,shift-base,shift-exponent,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift-base,shift-exponent,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-TRAP // RUN: %clang_cc1 -fsanitize=null -fsanitize-recover=null -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-NULL // RUN: %clang_cc1 -fsanitize=signed-integer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-OVERFLOW // REQUIRES: asserts diff --git a/clang/test/CodeGen/sanitize-trap.c b/clang/test/CodeGen/sanitize-trap.c new file mode 100644 index 0000000..a9fcd82 --- /dev/null +++ b/clang/test/CodeGen/sanitize-trap.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero -fsanitize-trap=integer-divide-by-zero | FileCheck %s + +int f(int x, int y) { + // CHECK: %[[B1:.*]] = icmp ne i32 %[[D:.*]], 0 + // CHECK: %[[B2:.*]] = icmp ne i32 %[[N:.*]], -2147483648 + // CHECK: %[[B3:.*]] = icmp ne i32 %[[D]], -1 + // CHECK: %[[B4:.*]] = or i1 %[[B2]], %[[B3]] + // CHECK: br i1 %[[B1]], label %[[L1:[0-9a-z_.]*]], label %[[L2:[0-9a-z_.]*]] + + // CHECK: [[L2]] + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: unreachable + + // CHECK: [[L1]] + // CHECK-NEXT: br i1 %[[B4]], label %[[L3:[0-9a-z_.]*]], label %[[L4:[0-9a-z_.]*]] + + // CHECK: [[L4]] + // CHECK-NEXT: zext + // CHECK-NEXT: zext + // CHECK-NEXT: __ubsan_handle_divrem_overflow + + // CHECK: [[L3]] + // CHECK-NEXT: sdiv i32 %[[N]], %[[D]] + return x / y; +} diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 964ad2b..5c30dc1 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1,7 +1,11 @@ +// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP +// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-trap=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP2 +// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP // RUN: %clang -target x86_64-linux-gnu -fsanitize-undefined-trap-on-error -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP -// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){17}"}} -// CHECK-UNDEFINED-TRAP: "-fsanitize-undefined-trap-on-error" +// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}} +// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound" +// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound" // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED // CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){19}"}} @@ -27,11 +31,9 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=shift -fno-sanitize=shift-base %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSANITIZE-SHIFT-PARTIAL // CHECK-FSANITIZE-SHIFT-PARTIAL: "-fsanitize=shift-exponent" -// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP-ON-ERROR-UNDEF -// CHECK-UNDEFINED-TRAP-ON-ERROR-UNDEF: '-fsanitize=undefined' not allowed with '-fsanitize-undefined-trap-on-error' - -// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP-ON-ERROR-VPTR -// CHECK-UNDEFINED-TRAP-ON-ERROR-VPTR: '-fsanitize=vptr' not allowed with '-fsanitize-undefined-trap-on-error' +// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fsanitize-trap=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-TRAP-UNDEF +// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-TRAP-UNDEF +// CHECK-VPTR-TRAP-UNDEF: error: invalid argument '-fsanitize=vptr' not allowed with '-fsanitize-trap=undefined' // RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI // CHECK-VPTR-NO-RTTI: '-fsanitize=vptr' not allowed with '-fno-rtti' @@ -199,6 +201,9 @@ // CHECK-CFI-NVCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-nvcall // CHECK-CFI-VCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-vcall +// RUN: %clang -target x86_64-linux-gnu -fsanitize-trap=address -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TRAP +// CHECK-ASAN-TRAP: error: unsupported argument 'address' to option '-fsanitize-trap' + // RUN: %clang_cl -fsanitize=address -c -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL // RUN: %clang_cl -fsanitize=address -c -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL // RUN: %clang_cl -fsanitize=address -c -LDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL -- 2.7.4