Index: include/clang/Basic/Sanitizers.h =================================================================== --- include/clang/Basic/Sanitizers.h +++ include/clang/Basic/Sanitizers.h @@ -15,31 +15,51 @@ #ifndef LLVM_CLANG_BASIC_SANITIZERS_H #define LLVM_CLANG_BASIC_SANITIZERS_H +#include + namespace clang { -enum class SanitizerKind { -#define SANITIZER(NAME, ID) ID, +typedef uint64_t SanitizerMask; + +namespace SanitizerKind { + +// Assign ordinals to possible values of -fsanitize= flag, which we will use as +// bit positions. +enum : uint64_t { +#define SANITIZER(NAME, ID) SO_##ID, +#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, #include "clang/Basic/Sanitizers.def" - Unknown + SO_Count }; -class SanitizerSet { - /// \brief Bitmask of enabled sanitizers. - unsigned Kinds; -public: +// Define the set of sanitizer kinds, as well as the set of sanitizers each +// sanitizer group expands into. +#define SANITIZER(NAME, ID) \ + const SanitizerMask ID = 1ULL << SO_##ID; +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + const SanitizerMask ID = ALIAS; \ + const SanitizerMask ID##Group = 1ULL << SO_##ID##Group; +#include "clang/Basic/Sanitizers.def" + +} + +struct SanitizerSet { SanitizerSet(); /// \brief Check if a certain sanitizer is enabled. - bool has(SanitizerKind K) const; + bool has(SanitizerMask K) const; /// \brief Enable or disable a certain sanitizer. - void set(SanitizerKind K, bool Value); + void set(SanitizerMask K, bool Value); /// \brief Disable all sanitizers. void clear(); /// \brief Returns true if at least one sanitizer is enabled. bool empty() const; + + /// \brief Bitmask of enabled sanitizers. + SanitizerMask Mask; }; } // end namespace clang Index: lib/Basic/Sanitizers.cpp =================================================================== --- lib/Basic/Sanitizers.cpp +++ lib/Basic/Sanitizers.cpp @@ -14,22 +14,20 @@ using namespace clang; -SanitizerSet::SanitizerSet() : Kinds(0) {} +SanitizerSet::SanitizerSet() : Mask(0) {} -bool SanitizerSet::has(SanitizerKind K) const { - unsigned Bit = static_cast(K); - return Kinds & (1 << Bit); +bool SanitizerSet::has(SanitizerMask K) const { + return Mask & K; } -void SanitizerSet::set(SanitizerKind K, bool Value) { - unsigned Bit = static_cast(K); - Kinds = Value ? (Kinds | (1 << Bit)) : (Kinds & ~(1 << Bit)); +void SanitizerSet::set(SanitizerMask K, bool Value) { + Mask = Value ? (Mask | K) : (Mask & ~K); } void SanitizerSet::clear() { - Kinds = 0; + Mask = 0; } bool SanitizerSet::empty() const { - return Kinds == 0; + return Mask == 0; } Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -499,7 +499,7 @@ SanitizerScope SanScope(this); - SmallVector, 3> Checks; + SmallVector, 3> Checks; llvm::BasicBlock *Done = nullptr; bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast || @@ -1204,7 +1204,7 @@ EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty) }; - SanitizerKind Kind = NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool; + SanitizerMask Kind = NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool; EmitCheck(std::make_pair(Check, Kind), "load_invalid_value", StaticArgs, EmitCheckValue(Load)); } @@ -2243,7 +2243,7 @@ }; } -static CheckRecoverableKind getRecoverableKind(SanitizerKind Kind) { +static CheckRecoverableKind getRecoverableKind(SanitizerMask Kind) { switch (Kind) { case SanitizerKind::Vptr: return CheckRecoverableKind::AlwaysRecoverable; @@ -2290,7 +2290,7 @@ } void CodeGenFunction::EmitCheck( - ArrayRef> Checked, + ArrayRef> Checked, StringRef CheckName, ArrayRef StaticArgs, ArrayRef DynamicArgs) { assert(IsSanitizerScope); @@ -3385,7 +3385,8 @@ EmitCheckSourceLocation(E->getLocStart()), EmitCheckTypeDescriptor(CalleeType) }; - EmitCheck(std::make_pair(CalleeRTTIMatch, SanitizerKind::Function), + EmitCheck(std::make_pair(CalleeRTTIMatch, + SanitizerMask(SanitizerKind::Function)), "function_type_mismatch", StaticData, Callee); Builder.CreateBr(Cont); Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -85,7 +85,7 @@ return CGF.EmitCheckedLValue(E, TCK); } - void EmitBinOpCheck(ArrayRef> Checks, + void EmitBinOpCheck(ArrayRef> Checks, const BinOpInfo &Info); Value *EmitLoadOfLValue(LValue LV, SourceLocation Loc) { @@ -916,7 +916,7 @@ /// operation). The check passes if all values in \p Checks (which are \c i1), /// are \c true. void ScalarExprEmitter::EmitBinOpCheck( - ArrayRef> Checks, const BinOpInfo &Info) { + ArrayRef> Checks, const BinOpInfo &Info) { assert(CGF.IsSanitizerScope); StringRef CheckName; SmallVector StaticData; @@ -2231,7 +2231,7 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) { - SmallVector, 2> Checks; + SmallVector, 2> Checks; if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) { Checks.push_back(std::make_pair(Builder.CreateICmpNE(Ops.RHS, Zero), @@ -2356,7 +2356,7 @@ if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) { CodeGenFunction::SanitizerScope SanScope(&CGF); llvm::Value *NotOverflow = Builder.CreateNot(overflow); - SanitizerKind Kind = isSigned ? SanitizerKind::SignedIntegerOverflow + SanitizerMask Kind = isSigned ? SanitizerKind::SignedIntegerOverflow : SanitizerKind::UnsignedIntegerOverflow; EmitBinOpCheck(std::make_pair(NotOverflow, Kind), Ops); } else @@ -2721,7 +2721,7 @@ else if ((SanitizeBase || SanitizeExponent) && isa(Ops.LHS->getType())) { CodeGenFunction::SanitizerScope SanScope(&CGF); - SmallVector, 2> Checks; + SmallVector, 2> Checks; llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS); llvm::Value *ValidExponent = Builder.CreateICmpULE(RHS, WidthMinusOne); Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2835,7 +2835,7 @@ /// \brief Create a basic block that will call a handler function in a /// sanitizer runtime with the provided arguments, and create a conditional /// branch to it. - void EmitCheck(ArrayRef> Checked, + void EmitCheck(ArrayRef> Checked, StringRef CheckName, ArrayRef StaticArgs, ArrayRef DynamicArgs); Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -18,28 +18,12 @@ #include "llvm/Support/SpecialCaseList.h" #include +using namespace clang; +using namespace clang::SanitizerKind; using namespace clang::driver; using namespace llvm::opt; -namespace { -/// Assign ordinals to possible values of -fsanitize= flag. -/// We use the ordinal values as bit positions within \c SanitizeKind. -enum SanitizeOrdinal : uint64_t { -#define SANITIZER(NAME, ID) SO_##ID, -#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, -#include "clang/Basic/Sanitizers.def" - SO_Count -}; - -/// Represents a set of sanitizer kinds. It is also used to define: -/// 1) set of sanitizers each sanitizer group expands into. -/// 2) set of sanitizers sharing a specific property (e.g. -/// all sanitizers with zero-base shadow). -enum SanitizeKind : uint64_t { -#define SANITIZER(NAME, ID) ID = 1ULL << SO_##ID, -#define SANITIZER_GROUP(NAME, ID, ALIAS) \ - ID = ALIAS, ID##Group = 1ULL << SO_##ID##Group, -#include "clang/Basic/Sanitizers.def" +enum : uint64_t { NeedsUbsanRt = Undefined | Integer, NotAllowedWithTrap = Vptr, RequiresPIE = Memory | DataFlow, @@ -50,43 +34,15 @@ LegacyFsanitizeRecoverMask = Undefined | Integer, NeedsLTO = CFI, }; -} - -/// Returns true if set of \p Sanitizers contain at least one sanitizer from -/// \p Kinds. -static bool hasOneOf(const clang::SanitizerSet &Sanitizers, uint64_t Kinds) { -#define SANITIZER(NAME, ID) \ - if (Sanitizers.has(clang::SanitizerKind::ID) && (Kinds & ID)) \ - return true; -#include "clang/Basic/Sanitizers.def" - return false; -} - -/// Adds all sanitizers from \p Kinds to \p Sanitizers. -static void addAllOf(clang::SanitizerSet &Sanitizers, uint64_t Kinds) { -#define SANITIZER(NAME, ID) \ - if (Kinds & ID) \ - Sanitizers.set(clang::SanitizerKind::ID, true); -#include "clang/Basic/Sanitizers.def" -} - -static uint64_t toSanitizeKind(clang::SanitizerKind K) { -#define SANITIZER(NAME, ID) \ - if (K == clang::SanitizerKind::ID) \ - return ID; -#include "clang/Basic/Sanitizers.def" - llvm_unreachable("Invalid SanitizerKind!"); -} /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. -/// Returns a member of the \c SanitizeKind enumeration, or \c 0 -/// if \p Value is not known. -static uint64_t parseValue(const char *Value); +/// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known. +static SanitizerMask parseValue(const char *Value); /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any -/// invalid components. Returns OR of members of \c SanitizeKind enumeration. -static uint64_t parseArgValues(const Driver &D, const llvm::opt::Arg *A, - bool DiagnoseErrors); +/// invalid components. Returns a SanitizerMask. +static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors); /// Produce an argument string from ArgList \p Args, which shows how it /// provides some sanitizer kind from \p Mask. For example, the argument list @@ -94,19 +50,14 @@ /// would produce "-fsanitize=vptr". static std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, - uint64_t Mask); - -static std::string lastArgumentForKind(const Driver &D, - const llvm::opt::ArgList &Args, - clang::SanitizerKind K) { - return lastArgumentForMask(D, Args, toSanitizeKind(K)); -} + SanitizerMask Mask); /// Produce an argument string from argument \p A, which shows how it provides /// a value in \p Mask. For instance, the argument /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce /// "-fsanitize=alignment". -static std::string describeSanitizeArg(const llvm::opt::Arg *A, uint64_t Mask); +static std::string describeSanitizeArg(const llvm::opt::Arg *A, + SanitizerMask Mask); /// Produce a string containing comma-separated names of sanitizers in \p /// Sanitizers set. @@ -114,7 +65,7 @@ /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers /// this group enables. -static uint64_t expandGroups(uint64_t Kinds); +static SanitizerMask expandGroups(SanitizerMask Kinds); static uint64_t getToolchainUnsupportedKinds(const ToolChain &TC) { bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD; @@ -140,13 +91,13 @@ static bool getDefaultBlacklist(const Driver &D, uint64_t Kinds, std::string &BLPath) { const char *BlacklistFile = nullptr; - if (Kinds & SanitizeKind::Address) + if (Kinds & Address) BlacklistFile = "asan_blacklist.txt"; - else if (Kinds & SanitizeKind::Memory) + else if (Kinds & Memory) BlacklistFile = "msan_blacklist.txt"; - else if (Kinds & SanitizeKind::Thread) + else if (Kinds & Thread) BlacklistFile = "tsan_blacklist.txt"; - else if (Kinds & SanitizeKind::DataFlow) + else if (Kinds & DataFlow) BlacklistFile = "dfsan_abilist.txt"; if (BlacklistFile) { @@ -159,22 +110,22 @@ } bool SanitizerArgs::needsUbsanRt() const { - return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt) && - !Sanitizers.has(SanitizerKind::Address) && - !Sanitizers.has(SanitizerKind::Memory) && - !Sanitizers.has(SanitizerKind::Thread); + return !UbsanTrapOnError && Sanitizers.Mask & NeedsUbsanRt && + !Sanitizers.has(Address) && + !Sanitizers.has(Memory) && + !Sanitizers.has(Thread); } bool SanitizerArgs::requiresPIE() const { - return AsanZeroBaseShadow || hasOneOf(Sanitizers, RequiresPIE); + return AsanZeroBaseShadow || Sanitizers.Mask & RequiresPIE; } bool SanitizerArgs::needsUnwindTables() const { - return hasOneOf(Sanitizers, NeedsUnwindTables); + return Sanitizers.Mask & NeedsUnwindTables; } bool SanitizerArgs::needsLTO() const { - return hasOneOf(Sanitizers, NeedsLTO); + return Sanitizers.Mask & NeedsLTO; } void SanitizerArgs::clear() { @@ -227,7 +178,7 @@ // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups // so we don't error out if -fno-rtti and -fsanitize=undefined were // passed. - if (Add & SanitizeKind::Vptr && + if (Add & Vptr && (RTTIMode == ToolChain::RM_DisabledImplicitly || RTTIMode == ToolChain::RM_DisabledExplicitly)) { if (RTTIMode == ToolChain::RM_DisabledImplicitly) @@ -243,7 +194,7 @@ } // Take out the Vptr sanitizer from the enabled sanitizers - AllRemove |= SanitizeKind::Vptr; + AllRemove |= Vptr; } Add = expandGroups(Add); @@ -263,30 +214,30 @@ // We disable the vptr sanitizer if it was enabled by group expansion but RTTI // is disabled. - if ((Kinds & SanitizeKind::Vptr) && + if ((Kinds & Vptr) && (RTTIMode == ToolChain::RM_DisabledImplicitly || RTTIMode == ToolChain::RM_DisabledExplicitly)) { - Kinds &= ~SanitizeKind::Vptr; + 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 & SanitizeKind::NotAllowedWithTrap)) { + if (UbsanTrapOnError && (Kinds & NotAllowedWithTrap)) { D.Diag(clang::diag::err_drv_argument_not_allowed_with) << lastArgumentForMask(D, Args, NotAllowedWithTrap) << "-fsanitize-undefined-trap-on-error"; - Kinds &= ~SanitizeKind::NotAllowedWithTrap; + Kinds &= ~NotAllowedWithTrap; } // Warn about incompatible groups of sanitizers. std::pair IncompatibleGroups[] = { - std::make_pair(SanitizeKind::Address, SanitizeKind::Thread), - std::make_pair(SanitizeKind::Address, SanitizeKind::Memory), - std::make_pair(SanitizeKind::Thread, SanitizeKind::Memory), - std::make_pair(SanitizeKind::Leak, SanitizeKind::Thread), - std::make_pair(SanitizeKind::Leak, SanitizeKind::Memory)}; + std::make_pair(Address, Thread), + std::make_pair(Address, Memory), + std::make_pair(Thread, Memory), + std::make_pair(Leak, Thread), + std::make_pair(Leak, Memory)}; for (auto G : IncompatibleGroups) { uint64_t Group = G.first; if (Kinds & Group) { @@ -323,7 +274,7 @@ if (uint64_t KindsToDiagnose = Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { SanitizerSet SetToDiagnose; - addAllOf(SetToDiagnose, KindsToDiagnose); + SetToDiagnose.Mask |= KindsToDiagnose; D.Diag(diag::err_drv_unsupported_option_argument) << Arg->getOption().getName() << toString(SetToDiagnose); DiagnosedUnrecoverableKinds |= KindsToDiagnose; @@ -373,7 +324,7 @@ } // Parse -f[no-]sanitize-memory-track-origins[=level] options. - if (Kinds & SanitizeKind::Memory) { + if (Kinds & Memory) { if (Arg *A = Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, options::OPT_fsanitize_memory_track_origins, @@ -394,7 +345,7 @@ } // Parse -fsanitize-coverage=N. Currently one of asan/msan/lsan is required. - if (Kinds & SanitizeKind::SupportsCoverage) { + if (Kinds & SupportsCoverage) { if (Arg *A = Args.getLastArg(options::OPT_fsanitize_coverage)) { StringRef S = A->getValue(); // Legal values are 0..4. @@ -404,7 +355,7 @@ } } - if (Kinds & SanitizeKind::Address) { + if (Kinds & Address) { AsanSharedRuntime = Args.hasArg(options::OPT_shared_libasan) || (TC.getTriple().getEnvironment() == llvm::Triple::Android); @@ -430,7 +381,7 @@ case options::OPT__SLASH_LDd: D.Diag(clang::diag::err_drv_argument_not_allowed_with) << WindowsDebugRTArg->getAsString(Args) - << lastArgumentForKind(D, Args, SanitizerKind::Address); + << lastArgumentForMask(D, Args, Address); D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); } } @@ -441,14 +392,14 @@ Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); // Finally, initialize the set of available and recoverable sanitizers. - addAllOf(Sanitizers, Kinds); - addAllOf(RecoverableSanitizers, RecoverableKinds); + Sanitizers.Mask |= Kinds; + RecoverableSanitizers.Mask |= RecoverableKinds; } static std::string toString(const clang::SanitizerSet &Sanitizers) { std::string Res; #define SANITIZER(NAME, ID) \ - if (Sanitizers.has(clang::SanitizerKind::ID)) { \ + if (Sanitizers.has(ID)) { \ if (!Res.empty()) \ Res += ","; \ Res += NAME; \ @@ -490,21 +441,21 @@ // https://code.google.com/p/address-sanitizer/issues/detail?id=373 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't // affect compilation. - if (Sanitizers.has(SanitizerKind::Memory) || - Sanitizers.has(SanitizerKind::Address)) + if (Sanitizers.has(Memory) || + Sanitizers.has(Address)) CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); } -uint64_t parseValue(const char *Value) { - uint64_t ParsedKind = llvm::StringSwitch(Value) +SanitizerMask parseValue(const char *Value) { + uint64_t ParsedKind = llvm::StringSwitch(Value) #define SANITIZER(NAME, ID) .Case(NAME, ID) #define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group) #include "clang/Basic/Sanitizers.def" - .Default(SanitizeKind()); + .Default(0); return ParsedKind; } -uint64_t expandGroups(uint64_t Kinds) { +SanitizerMask expandGroups(SanitizerMask Kinds) { #define SANITIZER(NAME, ID) #define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID; #include "clang/Basic/Sanitizers.def" Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -329,11 +329,11 @@ const std::vector &Sanitizers, DiagnosticsEngine &Diags, SanitizerSet &S) { for (const auto &Sanitizer : Sanitizers) { - SanitizerKind K = llvm::StringSwitch(Sanitizer) + SanitizerMask K = llvm::StringSwitch(Sanitizer) #define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID) #include "clang/Basic/Sanitizers.def" - .Default(SanitizerKind::Unknown); - if (K == SanitizerKind::Unknown) + .Default(0); + if (K == 0) Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer; else S.set(K, true);