1 //===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 #include "clang/Driver/SanitizerArgs.h" 10 #include "ToolChains/CommonArgs.h" 11 #include "clang/Basic/Sanitizers.h" 12 #include "clang/Driver/Driver.h" 13 #include "clang/Driver/DriverDiagnostic.h" 14 #include "clang/Driver/Options.h" 15 #include "clang/Driver/ToolChain.h" 16 #include "llvm/ADT/StringExtras.h" 17 #include "llvm/ADT/StringSwitch.h" 18 #include "llvm/Support/FileSystem.h" 19 #include "llvm/Support/Path.h" 20 #include "llvm/Support/SpecialCaseList.h" 21 #include "llvm/Support/TargetParser.h" 22 #include <memory> 23 24 using namespace clang; 25 using namespace clang::SanitizerKind; 26 using namespace clang::driver; 27 using namespace llvm::opt; 28 29 enum : SanitizerMask { 30 NeedsUbsanRt = Undefined | Integer | ImplicitConversion | Nullability | CFI, 31 NeedsUbsanCxxRt = Vptr | CFI, 32 NotAllowedWithTrap = Vptr, 33 NotAllowedWithMinimalRuntime = Vptr, 34 RequiresPIE = DataFlow | HWAddress | Scudo, 35 NeedsUnwindTables = Address | HWAddress | Thread | Memory | DataFlow, 36 SupportsCoverage = Address | HWAddress | KernelAddress | KernelHWAddress | 37 Memory | KernelMemory | Leak | Undefined | Integer | 38 ImplicitConversion | Nullability | DataFlow | Fuzzer | 39 FuzzerNoLink, 40 RecoverableByDefault = Undefined | Integer | ImplicitConversion | Nullability, 41 Unrecoverable = Unreachable | Return, 42 AlwaysRecoverable = KernelAddress | KernelHWAddress, 43 LegacyFsanitizeRecoverMask = Undefined | Integer, 44 NeedsLTO = CFI, 45 TrappingSupported = (Undefined & ~Vptr) | UnsignedIntegerOverflow | 46 ImplicitConversion | Nullability | LocalBounds | CFI, 47 TrappingDefault = CFI, 48 CFIClasses = 49 CFIVCall | CFINVCall | CFIMFCall | CFIDerivedCast | CFIUnrelatedCast, 50 CompatibleWithMinimalRuntime = TrappingSupported | Scudo | ShadowCallStack, 51 }; 52 53 enum CoverageFeature { 54 CoverageFunc = 1 << 0, 55 CoverageBB = 1 << 1, 56 CoverageEdge = 1 << 2, 57 CoverageIndirCall = 1 << 3, 58 CoverageTraceBB = 1 << 4, // Deprecated. 59 CoverageTraceCmp = 1 << 5, 60 CoverageTraceDiv = 1 << 6, 61 CoverageTraceGep = 1 << 7, 62 Coverage8bitCounters = 1 << 8, // Deprecated. 63 CoverageTracePC = 1 << 9, 64 CoverageTracePCGuard = 1 << 10, 65 CoverageNoPrune = 1 << 11, 66 CoverageInline8bitCounters = 1 << 12, 67 CoveragePCTable = 1 << 13, 68 CoverageStackDepth = 1 << 14, 69 }; 70 71 /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any 72 /// invalid components. Returns a SanitizerMask. 73 static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, 74 bool DiagnoseErrors); 75 76 /// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid 77 /// components. Returns OR of members of \c CoverageFeature enumeration. 78 static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A); 79 80 /// Produce an argument string from ArgList \p Args, which shows how it 81 /// provides some sanitizer kind from \p Mask. For example, the argument list 82 /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt 83 /// would produce "-fsanitize=vptr". 84 static std::string lastArgumentForMask(const Driver &D, 85 const llvm::opt::ArgList &Args, 86 SanitizerMask Mask); 87 88 /// Produce an argument string from argument \p A, which shows how it provides 89 /// a value in \p Mask. For instance, the argument 90 /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce 91 /// "-fsanitize=alignment". 92 static std::string describeSanitizeArg(const llvm::opt::Arg *A, 93 SanitizerMask Mask); 94 95 /// Produce a string containing comma-separated names of sanitizers in \p 96 /// Sanitizers set. 97 static std::string toString(const clang::SanitizerSet &Sanitizers); 98 99 static void addDefaultBlacklists(const Driver &D, SanitizerMask Kinds, 100 std::vector<std::string> &BlacklistFiles) { 101 struct Blacklist { 102 const char *File; 103 SanitizerMask Mask; 104 } Blacklists[] = {{"asan_blacklist.txt", Address}, 105 {"hwasan_blacklist.txt", HWAddress}, 106 {"msan_blacklist.txt", Memory}, 107 {"tsan_blacklist.txt", Thread}, 108 {"dfsan_abilist.txt", DataFlow}, 109 {"cfi_blacklist.txt", CFI}, 110 {"ubsan_blacklist.txt", Undefined | Integer | Nullability}}; 111 112 for (auto BL : Blacklists) { 113 if (!(Kinds & BL.Mask)) 114 continue; 115 116 clang::SmallString<64> Path(D.ResourceDir); 117 llvm::sys::path::append(Path, "share", BL.File); 118 if (llvm::sys::fs::exists(Path)) 119 BlacklistFiles.push_back(Path.str()); 120 else if (BL.Mask == CFI) 121 // If cfi_blacklist.txt cannot be found in the resource dir, driver 122 // should fail. 123 D.Diag(clang::diag::err_drv_no_such_file) << Path; 124 } 125 } 126 127 /// Sets group bits for every group that has at least one representative already 128 /// enabled in \p Kinds. 129 static SanitizerMask setGroupBits(SanitizerMask Kinds) { 130 #define SANITIZER(NAME, ID) 131 #define SANITIZER_GROUP(NAME, ID, ALIAS) \ 132 if (Kinds & SanitizerKind::ID) \ 133 Kinds |= SanitizerKind::ID##Group; 134 #include "clang/Basic/Sanitizers.def" 135 return Kinds; 136 } 137 138 static SanitizerMask parseSanitizeTrapArgs(const Driver &D, 139 const llvm::opt::ArgList &Args) { 140 SanitizerMask TrapRemove = 0; // During the loop below, the accumulated set of 141 // sanitizers disabled by the current sanitizer 142 // argument or any argument after it. 143 SanitizerMask TrappingKinds = 0; 144 SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported); 145 146 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); 147 I != E; ++I) { 148 const auto *Arg = *I; 149 if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) { 150 Arg->claim(); 151 SanitizerMask Add = parseArgValues(D, Arg, true); 152 Add &= ~TrapRemove; 153 if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) { 154 SanitizerSet S; 155 S.Mask = InvalidValues; 156 D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap" 157 << toString(S); 158 } 159 TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; 160 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { 161 Arg->claim(); 162 TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true)); 163 } else if (Arg->getOption().matches( 164 options::OPT_fsanitize_undefined_trap_on_error)) { 165 Arg->claim(); 166 TrappingKinds |= 167 expandSanitizerGroups(UndefinedGroup & ~TrapRemove) & ~TrapRemove; 168 } else if (Arg->getOption().matches( 169 options::OPT_fno_sanitize_undefined_trap_on_error)) { 170 Arg->claim(); 171 TrapRemove |= expandSanitizerGroups(UndefinedGroup); 172 } 173 } 174 175 // Apply default trapping behavior. 176 TrappingKinds |= TrappingDefault & ~TrapRemove; 177 178 return TrappingKinds; 179 } 180 181 bool SanitizerArgs::needsUbsanRt() const { 182 // All of these include ubsan. 183 if (needsAsanRt() || needsMsanRt() || needsHwasanRt() || needsTsanRt() || 184 needsDfsanRt() || needsLsanRt() || needsCfiDiagRt() || 185 (needsScudoRt() && !requiresMinimalRuntime())) 186 return false; 187 188 return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) || 189 CoverageFeatures; 190 } 191 192 bool SanitizerArgs::needsCfiRt() const { 193 return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso && 194 !ImplicitCfiRuntime; 195 } 196 197 bool SanitizerArgs::needsCfiDiagRt() const { 198 return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso && 199 !ImplicitCfiRuntime; 200 } 201 202 bool SanitizerArgs::requiresPIE() const { 203 return NeedPIE || (Sanitizers.Mask & RequiresPIE); 204 } 205 206 bool SanitizerArgs::needsUnwindTables() const { 207 return Sanitizers.Mask & NeedsUnwindTables; 208 } 209 210 SanitizerArgs::SanitizerArgs(const ToolChain &TC, 211 const llvm::opt::ArgList &Args) { 212 SanitizerMask AllRemove = 0; // During the loop below, the accumulated set of 213 // sanitizers disabled by the current sanitizer 214 // argument or any argument after it. 215 SanitizerMask AllAddedKinds = 0; // Mask of all sanitizers ever enabled by 216 // -fsanitize= flags (directly or via group 217 // expansion), some of which may be disabled 218 // later. Used to carefully prune 219 // unused-argument diagnostics. 220 SanitizerMask DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. 221 // Used to deduplicate diagnostics. 222 SanitizerMask Kinds = 0; 223 const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers()); 224 225 CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso, 226 options::OPT_fno_sanitize_cfi_cross_dso, false); 227 228 ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); 229 230 const Driver &D = TC.getDriver(); 231 SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); 232 SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap; 233 234 MinimalRuntime = 235 Args.hasFlag(options::OPT_fsanitize_minimal_runtime, 236 options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime); 237 238 // The object size sanitizer should not be enabled at -O0. 239 Arg *OptLevel = Args.getLastArg(options::OPT_O_Group); 240 bool RemoveObjectSizeAtO0 = 241 !OptLevel || OptLevel->getOption().matches(options::OPT_O0); 242 243 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); 244 I != E; ++I) { 245 const auto *Arg = *I; 246 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { 247 Arg->claim(); 248 SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true); 249 250 if (RemoveObjectSizeAtO0) { 251 AllRemove |= SanitizerKind::ObjectSize; 252 253 // The user explicitly enabled the object size sanitizer. Warn that 254 // that this does nothing at -O0. 255 if (Add & SanitizerKind::ObjectSize) 256 D.Diag(diag::warn_drv_object_size_disabled_O0) 257 << Arg->getAsString(Args); 258 } 259 260 AllAddedKinds |= expandSanitizerGroups(Add); 261 262 // Avoid diagnosing any sanitizer which is disabled later. 263 Add &= ~AllRemove; 264 // At this point we have not expanded groups, so any unsupported 265 // sanitizers in Add are those which have been explicitly enabled. 266 // Diagnose them. 267 if (SanitizerMask KindsToDiagnose = 268 Add & InvalidTrappingKinds & ~DiagnosedKinds) { 269 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); 270 D.Diag(diag::err_drv_argument_not_allowed_with) 271 << Desc << "-fsanitize-trap=undefined"; 272 DiagnosedKinds |= KindsToDiagnose; 273 } 274 Add &= ~InvalidTrappingKinds; 275 276 if (MinimalRuntime) { 277 if (SanitizerMask KindsToDiagnose = 278 Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) { 279 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); 280 D.Diag(diag::err_drv_argument_not_allowed_with) 281 << Desc << "-fsanitize-minimal-runtime"; 282 DiagnosedKinds |= KindsToDiagnose; 283 } 284 Add &= ~NotAllowedWithMinimalRuntime; 285 } 286 287 // FIXME: Make CFI on member function calls compatible with cross-DSO CFI. 288 // There are currently two problems: 289 // - Virtual function call checks need to pass a pointer to the function 290 // address to llvm.type.test and a pointer to the address point to the 291 // diagnostic function. Currently we pass the same pointer to both 292 // places. 293 // - Non-virtual function call checks may need to check multiple type 294 // identifiers. 295 // Fixing both of those may require changes to the cross-DSO CFI 296 // interface. 297 if (CfiCrossDso && (Add & CFIMFCall & ~DiagnosedKinds)) { 298 D.Diag(diag::err_drv_argument_not_allowed_with) 299 << "-fsanitize=cfi-mfcall" 300 << "-fsanitize-cfi-cross-dso"; 301 Add &= ~CFIMFCall; 302 DiagnosedKinds |= CFIMFCall; 303 } 304 305 if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) { 306 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); 307 D.Diag(diag::err_drv_unsupported_opt_for_target) 308 << Desc << TC.getTriple().str(); 309 DiagnosedKinds |= KindsToDiagnose; 310 } 311 Add &= Supported; 312 313 // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups 314 // so we don't error out if -fno-rtti and -fsanitize=undefined were 315 // passed. 316 if ((Add & Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { 317 if (const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg()) { 318 assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) && 319 "RTTI disabled without -fno-rtti option?"); 320 // The user explicitly passed -fno-rtti with -fsanitize=vptr, but 321 // the vptr sanitizer requires RTTI, so this is a user error. 322 D.Diag(diag::err_drv_argument_not_allowed_with) 323 << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args); 324 } else { 325 // The vptr sanitizer requires RTTI, but RTTI is disabled (by 326 // default). Warn that the vptr sanitizer is being disabled. 327 D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default); 328 } 329 330 // Take out the Vptr sanitizer from the enabled sanitizers 331 AllRemove |= Vptr; 332 } 333 334 Add = expandSanitizerGroups(Add); 335 // Group expansion may have enabled a sanitizer which is disabled later. 336 Add &= ~AllRemove; 337 // Silently discard any unsupported sanitizers implicitly enabled through 338 // group expansion. 339 Add &= ~InvalidTrappingKinds; 340 if (MinimalRuntime) { 341 Add &= ~NotAllowedWithMinimalRuntime; 342 } 343 if (CfiCrossDso) 344 Add &= ~CFIMFCall; 345 Add &= Supported; 346 347 if (Add & Fuzzer) 348 Add |= FuzzerNoLink; 349 350 // Enable coverage if the fuzzing flag is set. 351 if (Add & FuzzerNoLink) { 352 CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall | 353 CoverageTraceCmp | CoveragePCTable; 354 // Due to TLS differences, stack depth tracking is only enabled on Linux 355 if (TC.getTriple().isOSLinux()) 356 CoverageFeatures |= CoverageStackDepth; 357 } 358 359 Kinds |= Add; 360 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { 361 Arg->claim(); 362 SanitizerMask Remove = parseArgValues(D, Arg, true); 363 AllRemove |= expandSanitizerGroups(Remove); 364 } 365 } 366 367 std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = { 368 std::make_pair(Address, Thread | Memory), 369 std::make_pair(Thread, Memory), 370 std::make_pair(Leak, Thread | Memory), 371 std::make_pair(KernelAddress, Address | Leak | Thread | Memory), 372 std::make_pair(HWAddress, Address | Thread | Memory | KernelAddress), 373 std::make_pair(Efficiency, Address | HWAddress | Leak | Thread | Memory | 374 KernelAddress), 375 std::make_pair(Scudo, Address | HWAddress | Leak | Thread | Memory | 376 KernelAddress | Efficiency), 377 std::make_pair(SafeStack, Address | HWAddress | Leak | Thread | Memory | 378 KernelAddress | Efficiency), 379 std::make_pair(ShadowCallStack, Address | HWAddress | Leak | Thread | 380 Memory | KernelAddress | Efficiency | 381 SafeStack), 382 std::make_pair(KernelHWAddress, Address | HWAddress | Leak | Thread | 383 Memory | KernelAddress | Efficiency | 384 SafeStack | ShadowCallStack), 385 std::make_pair(KernelMemory, Address | HWAddress | Leak | Thread | 386 Memory | KernelAddress | Efficiency | 387 Scudo | SafeStack)}; 388 // Enable toolchain specific default sanitizers if not explicitly disabled. 389 SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove; 390 391 // Disable default sanitizers that are incompatible with explicitly requested 392 // ones. 393 for (auto G : IncompatibleGroups) { 394 SanitizerMask Group = G.first; 395 if ((Default & Group) && (Kinds & G.second)) 396 Default &= ~Group; 397 } 398 399 Kinds |= Default; 400 401 // We disable the vptr sanitizer if it was enabled by group expansion but RTTI 402 // is disabled. 403 if ((Kinds & Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { 404 Kinds &= ~Vptr; 405 } 406 407 // Check that LTO is enabled if we need it. 408 if ((Kinds & NeedsLTO) && !D.isUsingLTO()) { 409 D.Diag(diag::err_drv_argument_only_allowed_with) 410 << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; 411 } 412 413 if ((Kinds & ShadowCallStack) && 414 TC.getTriple().getArch() == llvm::Triple::aarch64 && 415 !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) && 416 !Args.hasArg(options::OPT_ffixed_x18)) { 417 D.Diag(diag::err_drv_argument_only_allowed_with) 418 << lastArgumentForMask(D, Args, Kinds & ShadowCallStack) 419 << "-ffixed-x18"; 420 } 421 422 // Report error if there are non-trapping sanitizers that require 423 // c++abi-specific parts of UBSan runtime, and they are not provided by the 424 // toolchain. We don't have a good way to check the latter, so we just 425 // check if the toolchan supports vptr. 426 if (~Supported & Vptr) { 427 SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt; 428 // The runtime library supports the Microsoft C++ ABI, but only well enough 429 // for CFI. FIXME: Remove this once we support vptr on Windows. 430 if (TC.getTriple().isOSWindows()) 431 KindsToDiagnose &= ~CFI; 432 if (KindsToDiagnose) { 433 SanitizerSet S; 434 S.Mask = KindsToDiagnose; 435 D.Diag(diag::err_drv_unsupported_opt_for_target) 436 << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str(); 437 Kinds &= ~KindsToDiagnose; 438 } 439 } 440 441 // Warn about incompatible groups of sanitizers. 442 for (auto G : IncompatibleGroups) { 443 SanitizerMask Group = G.first; 444 if (Kinds & Group) { 445 if (SanitizerMask Incompatible = Kinds & G.second) { 446 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 447 << lastArgumentForMask(D, Args, Group) 448 << lastArgumentForMask(D, Args, Incompatible); 449 Kinds &= ~Incompatible; 450 } 451 } 452 } 453 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of 454 // -fsanitize=address. Perhaps it should print an error, or perhaps 455 // -f(-no)sanitize=leak should change whether leak detection is enabled by 456 // default in ASan? 457 458 // Parse -f(no-)?sanitize-recover flags. 459 SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable; 460 SanitizerMask DiagnosedUnrecoverableKinds = 0; 461 SanitizerMask DiagnosedAlwaysRecoverableKinds = 0; 462 for (const auto *Arg : Args) { 463 const char *DeprecatedReplacement = nullptr; 464 if (Arg->getOption().matches(options::OPT_fsanitize_recover)) { 465 DeprecatedReplacement = 466 "-fsanitize-recover=undefined,integer' or '-fsanitize-recover=all"; 467 RecoverableKinds |= expandSanitizerGroups(LegacyFsanitizeRecoverMask); 468 Arg->claim(); 469 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) { 470 DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer' or " 471 "'-fno-sanitize-recover=all"; 472 RecoverableKinds &= ~expandSanitizerGroups(LegacyFsanitizeRecoverMask); 473 Arg->claim(); 474 } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) { 475 SanitizerMask Add = parseArgValues(D, Arg, true); 476 // Report error if user explicitly tries to recover from unrecoverable 477 // sanitizer. 478 if (SanitizerMask KindsToDiagnose = 479 Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { 480 SanitizerSet SetToDiagnose; 481 SetToDiagnose.Mask |= KindsToDiagnose; 482 D.Diag(diag::err_drv_unsupported_option_argument) 483 << Arg->getOption().getName() << toString(SetToDiagnose); 484 DiagnosedUnrecoverableKinds |= KindsToDiagnose; 485 } 486 RecoverableKinds |= expandSanitizerGroups(Add); 487 Arg->claim(); 488 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) { 489 SanitizerMask Remove = parseArgValues(D, Arg, true); 490 // Report error if user explicitly tries to disable recovery from 491 // always recoverable sanitizer. 492 if (SanitizerMask KindsToDiagnose = 493 Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) { 494 SanitizerSet SetToDiagnose; 495 SetToDiagnose.Mask |= KindsToDiagnose; 496 D.Diag(diag::err_drv_unsupported_option_argument) 497 << Arg->getOption().getName() << toString(SetToDiagnose); 498 DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose; 499 } 500 RecoverableKinds &= ~expandSanitizerGroups(Remove); 501 Arg->claim(); 502 } 503 if (DeprecatedReplacement) { 504 D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) 505 << DeprecatedReplacement; 506 } 507 } 508 RecoverableKinds &= Kinds; 509 RecoverableKinds &= ~Unrecoverable; 510 511 TrappingKinds &= Kinds; 512 RecoverableKinds &= ~TrappingKinds; 513 514 // Setup blacklist files. 515 // Add default blacklist from resource directory. 516 addDefaultBlacklists(D, Kinds, BlacklistFiles); 517 // Parse -f(no-)sanitize-blacklist options. 518 for (const auto *Arg : Args) { 519 if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { 520 Arg->claim(); 521 std::string BLPath = Arg->getValue(); 522 if (llvm::sys::fs::exists(BLPath)) { 523 BlacklistFiles.push_back(BLPath); 524 ExtraDeps.push_back(BLPath); 525 } else { 526 D.Diag(clang::diag::err_drv_no_such_file) << BLPath; 527 } 528 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { 529 Arg->claim(); 530 BlacklistFiles.clear(); 531 ExtraDeps.clear(); 532 } 533 } 534 // Validate blacklists format. 535 { 536 std::string BLError; 537 std::unique_ptr<llvm::SpecialCaseList> SCL( 538 llvm::SpecialCaseList::create(BlacklistFiles, BLError)); 539 if (!SCL.get()) 540 D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; 541 } 542 543 // Parse -f[no-]sanitize-memory-track-origins[=level] options. 544 if (AllAddedKinds & Memory) { 545 if (Arg *A = 546 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, 547 options::OPT_fsanitize_memory_track_origins, 548 options::OPT_fno_sanitize_memory_track_origins)) { 549 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { 550 MsanTrackOrigins = 2; 551 } else if (A->getOption().matches( 552 options::OPT_fno_sanitize_memory_track_origins)) { 553 MsanTrackOrigins = 0; 554 } else { 555 StringRef S = A->getValue(); 556 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || 557 MsanTrackOrigins > 2) { 558 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 559 } 560 } 561 } 562 MsanUseAfterDtor = 563 Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor, 564 options::OPT_fno_sanitize_memory_use_after_dtor, 565 MsanUseAfterDtor); 566 NeedPIE |= !(TC.getTriple().isOSLinux() && 567 TC.getTriple().getArch() == llvm::Triple::x86_64); 568 } else { 569 MsanUseAfterDtor = false; 570 } 571 572 if (AllAddedKinds & Thread) { 573 TsanMemoryAccess = Args.hasFlag(options::OPT_fsanitize_thread_memory_access, 574 options::OPT_fno_sanitize_thread_memory_access, 575 TsanMemoryAccess); 576 TsanFuncEntryExit = Args.hasFlag(options::OPT_fsanitize_thread_func_entry_exit, 577 options::OPT_fno_sanitize_thread_func_entry_exit, 578 TsanFuncEntryExit); 579 TsanAtomics = Args.hasFlag(options::OPT_fsanitize_thread_atomics, 580 options::OPT_fno_sanitize_thread_atomics, 581 TsanAtomics); 582 } 583 584 if (AllAddedKinds & CFI) { 585 // Without PIE, external function address may resolve to a PLT record, which 586 // can not be verified by the target module. 587 NeedPIE |= CfiCrossDso; 588 CfiICallGeneralizePointers = 589 Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers); 590 591 if (CfiCrossDso && CfiICallGeneralizePointers) 592 D.Diag(diag::err_drv_argument_not_allowed_with) 593 << "-fsanitize-cfi-cross-dso" 594 << "-fsanitize-cfi-icall-generalize-pointers"; 595 } 596 597 Stats = Args.hasFlag(options::OPT_fsanitize_stats, 598 options::OPT_fno_sanitize_stats, false); 599 600 if (MinimalRuntime) { 601 SanitizerMask IncompatibleMask = 602 Kinds & ~setGroupBits(CompatibleWithMinimalRuntime); 603 if (IncompatibleMask) 604 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 605 << "-fsanitize-minimal-runtime" 606 << lastArgumentForMask(D, Args, IncompatibleMask); 607 608 SanitizerMask NonTrappingCfi = Kinds & CFI & ~TrappingKinds; 609 if (NonTrappingCfi) 610 D.Diag(clang::diag::err_drv_argument_only_allowed_with) 611 << "fsanitize-minimal-runtime" 612 << "fsanitize-trap=cfi"; 613 } 614 615 // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the 616 // enabled sanitizers. 617 for (const auto *Arg : Args) { 618 if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { 619 int LegacySanitizeCoverage; 620 if (Arg->getNumValues() == 1 && 621 !StringRef(Arg->getValue(0)) 622 .getAsInteger(0, LegacySanitizeCoverage)) { 623 CoverageFeatures = 0; 624 Arg->claim(); 625 if (LegacySanitizeCoverage != 0) { 626 D.Diag(diag::warn_drv_deprecated_arg) 627 << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard"; 628 } 629 continue; 630 } 631 CoverageFeatures |= parseCoverageFeatures(D, Arg); 632 633 // Disable coverage and not claim the flags if there is at least one 634 // non-supporting sanitizer. 635 if (!(AllAddedKinds & ~AllRemove & ~setGroupBits(SupportsCoverage))) { 636 Arg->claim(); 637 } else { 638 CoverageFeatures = 0; 639 } 640 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { 641 Arg->claim(); 642 CoverageFeatures &= ~parseCoverageFeatures(D, Arg); 643 } 644 } 645 // Choose at most one coverage type: function, bb, or edge. 646 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB)) 647 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 648 << "-fsanitize-coverage=func" 649 << "-fsanitize-coverage=bb"; 650 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge)) 651 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 652 << "-fsanitize-coverage=func" 653 << "-fsanitize-coverage=edge"; 654 if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge)) 655 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 656 << "-fsanitize-coverage=bb" 657 << "-fsanitize-coverage=edge"; 658 // Basic block tracing and 8-bit counters require some type of coverage 659 // enabled. 660 if (CoverageFeatures & CoverageTraceBB) 661 D.Diag(clang::diag::warn_drv_deprecated_arg) 662 << "-fsanitize-coverage=trace-bb" 663 << "-fsanitize-coverage=trace-pc-guard"; 664 if (CoverageFeatures & Coverage8bitCounters) 665 D.Diag(clang::diag::warn_drv_deprecated_arg) 666 << "-fsanitize-coverage=8bit-counters" 667 << "-fsanitize-coverage=trace-pc-guard"; 668 669 int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; 670 int InstrumentationTypes = 671 CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters; 672 if ((CoverageFeatures & InsertionPointTypes) && 673 !(CoverageFeatures & InstrumentationTypes)) { 674 D.Diag(clang::diag::warn_drv_deprecated_arg) 675 << "-fsanitize-coverage=[func|bb|edge]" 676 << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; 677 } 678 679 // trace-pc w/o func/bb/edge implies edge. 680 if (!(CoverageFeatures & InsertionPointTypes)) { 681 if (CoverageFeatures & 682 (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) 683 CoverageFeatures |= CoverageEdge; 684 685 if (CoverageFeatures & CoverageStackDepth) 686 CoverageFeatures |= CoverageFunc; 687 } 688 689 SharedRuntime = 690 Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan, 691 TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() || 692 TC.getTriple().isOSDarwin()); 693 694 ImplicitCfiRuntime = TC.getTriple().isAndroid(); 695 696 if (AllAddedKinds & Address) { 697 NeedPIE |= TC.getTriple().isOSFuchsia(); 698 if (Arg *A = 699 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { 700 StringRef S = A->getValue(); 701 // Legal values are 0 and 1, 2, but in future we may add more levels. 702 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || 703 AsanFieldPadding > 2) { 704 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 705 } 706 } 707 708 if (Arg *WindowsDebugRTArg = 709 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT, 710 options::OPT__SLASH_MDd, options::OPT__SLASH_MD, 711 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) { 712 switch (WindowsDebugRTArg->getOption().getID()) { 713 case options::OPT__SLASH_MTd: 714 case options::OPT__SLASH_MDd: 715 case options::OPT__SLASH_LDd: 716 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 717 << WindowsDebugRTArg->getAsString(Args) 718 << lastArgumentForMask(D, Args, Address); 719 D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); 720 } 721 } 722 723 AsanUseAfterScope = Args.hasFlag( 724 options::OPT_fsanitize_address_use_after_scope, 725 options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope); 726 727 AsanPoisonCustomArrayCookie = Args.hasFlag( 728 options::OPT_fsanitize_address_poison_custom_array_cookie, 729 options::OPT_fno_sanitize_address_poison_custom_array_cookie, 730 AsanPoisonCustomArrayCookie); 731 732 // As a workaround for a bug in gold 2.26 and earlier, dead stripping of 733 // globals in ASan is disabled by default on ELF targets. 734 // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002 735 AsanGlobalsDeadStripping = 736 !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || 737 Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping); 738 } else { 739 AsanUseAfterScope = false; 740 } 741 742 if (AllAddedKinds & SafeStack) { 743 // SafeStack runtime is built into the system on Fuchsia. 744 SafeStackRuntime = !TC.getTriple().isOSFuchsia(); 745 } 746 747 // Parse -link-cxx-sanitizer flag. 748 LinkCXXRuntimes = 749 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); 750 751 // Finally, initialize the set of available and recoverable sanitizers. 752 Sanitizers.Mask |= Kinds; 753 RecoverableSanitizers.Mask |= RecoverableKinds; 754 TrapSanitizers.Mask |= TrappingKinds; 755 assert(!(RecoverableKinds & TrappingKinds) && 756 "Overlap between recoverable and trapping sanitizers"); 757 } 758 759 static std::string toString(const clang::SanitizerSet &Sanitizers) { 760 std::string Res; 761 #define SANITIZER(NAME, ID) \ 762 if (Sanitizers.has(ID)) { \ 763 if (!Res.empty()) \ 764 Res += ","; \ 765 Res += NAME; \ 766 } 767 #include "clang/Basic/Sanitizers.def" 768 return Res; 769 } 770 771 static void addIncludeLinkerOption(const ToolChain &TC, 772 const llvm::opt::ArgList &Args, 773 llvm::opt::ArgStringList &CmdArgs, 774 StringRef SymbolName) { 775 SmallString<64> LinkerOptionFlag; 776 LinkerOptionFlag = "--linker-option=/include:"; 777 if (TC.getTriple().getArch() == llvm::Triple::x86) { 778 // Win32 mangles C function names with a '_' prefix. 779 LinkerOptionFlag += '_'; 780 } 781 LinkerOptionFlag += SymbolName; 782 CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag)); 783 } 784 785 void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, 786 llvm::opt::ArgStringList &CmdArgs, 787 types::ID InputType) const { 788 // NVPTX doesn't currently support sanitizers. Bailing out here means that 789 // e.g. -fsanitize=address applies only to host code, which is what we want 790 // for now. 791 if (TC.getTriple().isNVPTX()) 792 return; 793 794 // Translate available CoverageFeatures to corresponding clang-cc1 flags. 795 // Do it even if Sanitizers.empty() since some forms of coverage don't require 796 // sanitizers. 797 std::pair<int, const char *> CoverageFlags[] = { 798 std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"), 799 std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"), 800 std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"), 801 std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"), 802 std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"), 803 std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), 804 std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"), 805 std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"), 806 std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), 807 std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"), 808 std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"), 809 std::make_pair(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"), 810 std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"), 811 std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), 812 std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")}; 813 for (auto F : CoverageFlags) { 814 if (CoverageFeatures & F.first) 815 CmdArgs.push_back(F.second); 816 } 817 818 if (TC.getTriple().isOSWindows() && needsUbsanRt()) { 819 // Instruct the code generator to embed linker directives in the object file 820 // that cause the required runtime libraries to be linked. 821 CmdArgs.push_back(Args.MakeArgString( 822 "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone"))); 823 if (types::isCXX(InputType)) 824 CmdArgs.push_back(Args.MakeArgString( 825 "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx"))); 826 } 827 if (TC.getTriple().isOSWindows() && needsStatsRt()) { 828 CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + 829 TC.getCompilerRT(Args, "stats_client"))); 830 831 // The main executable must export the stats runtime. 832 // FIXME: Only exporting from the main executable (e.g. based on whether the 833 // translation unit defines main()) would save a little space, but having 834 // multiple copies of the runtime shouldn't hurt. 835 CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + 836 TC.getCompilerRT(Args, "stats"))); 837 addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register"); 838 } 839 840 if (Sanitizers.empty()) 841 return; 842 CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers))); 843 844 if (!RecoverableSanitizers.empty()) 845 CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" + 846 toString(RecoverableSanitizers))); 847 848 if (!TrapSanitizers.empty()) 849 CmdArgs.push_back( 850 Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); 851 852 for (const auto &BLPath : BlacklistFiles) { 853 SmallString<64> BlacklistOpt("-fsanitize-blacklist="); 854 BlacklistOpt += BLPath; 855 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); 856 } 857 for (const auto &Dep : ExtraDeps) { 858 SmallString<64> ExtraDepOpt("-fdepfile-entry="); 859 ExtraDepOpt += Dep; 860 CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); 861 } 862 863 if (MsanTrackOrigins) 864 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + 865 Twine(MsanTrackOrigins))); 866 867 if (MsanUseAfterDtor) 868 CmdArgs.push_back("-fsanitize-memory-use-after-dtor"); 869 870 // FIXME: Pass these parameters as function attributes, not as -llvm flags. 871 if (!TsanMemoryAccess) { 872 CmdArgs.push_back("-mllvm"); 873 CmdArgs.push_back("-tsan-instrument-memory-accesses=0"); 874 CmdArgs.push_back("-mllvm"); 875 CmdArgs.push_back("-tsan-instrument-memintrinsics=0"); 876 } 877 if (!TsanFuncEntryExit) { 878 CmdArgs.push_back("-mllvm"); 879 CmdArgs.push_back("-tsan-instrument-func-entry-exit=0"); 880 } 881 if (!TsanAtomics) { 882 CmdArgs.push_back("-mllvm"); 883 CmdArgs.push_back("-tsan-instrument-atomics=0"); 884 } 885 886 if (CfiCrossDso) 887 CmdArgs.push_back("-fsanitize-cfi-cross-dso"); 888 889 if (CfiICallGeneralizePointers) 890 CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers"); 891 892 if (Stats) 893 CmdArgs.push_back("-fsanitize-stats"); 894 895 if (MinimalRuntime) 896 CmdArgs.push_back("-fsanitize-minimal-runtime"); 897 898 if (AsanFieldPadding) 899 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + 900 Twine(AsanFieldPadding))); 901 902 if (AsanUseAfterScope) 903 CmdArgs.push_back("-fsanitize-address-use-after-scope"); 904 905 if (AsanPoisonCustomArrayCookie) 906 CmdArgs.push_back("-fsanitize-address-poison-custom-array-cookie"); 907 908 if (AsanGlobalsDeadStripping) 909 CmdArgs.push_back("-fsanitize-address-globals-dead-stripping"); 910 911 // MSan: Workaround for PR16386. 912 // ASan: This is mainly to help LSan with cases such as 913 // https://github.com/google/sanitizers/issues/373 914 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't 915 // affect compilation. 916 if (Sanitizers.has(Memory) || Sanitizers.has(Address)) 917 CmdArgs.push_back("-fno-assume-sane-operator-new"); 918 919 // Require -fvisibility= flag on non-Windows when compiling if vptr CFI is 920 // enabled. 921 if (Sanitizers.hasOneOf(CFIClasses) && !TC.getTriple().isOSWindows() && 922 !Args.hasArg(options::OPT_fvisibility_EQ)) { 923 TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with) 924 << lastArgumentForMask(TC.getDriver(), Args, 925 Sanitizers.Mask & CFIClasses) 926 << "-fvisibility="; 927 } 928 } 929 930 SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, 931 bool DiagnoseErrors) { 932 assert((A->getOption().matches(options::OPT_fsanitize_EQ) || 933 A->getOption().matches(options::OPT_fno_sanitize_EQ) || 934 A->getOption().matches(options::OPT_fsanitize_recover_EQ) || 935 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) || 936 A->getOption().matches(options::OPT_fsanitize_trap_EQ) || 937 A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) && 938 "Invalid argument in parseArgValues!"); 939 SanitizerMask Kinds = 0; 940 for (int i = 0, n = A->getNumValues(); i != n; ++i) { 941 const char *Value = A->getValue(i); 942 SanitizerMask Kind; 943 // Special case: don't accept -fsanitize=all. 944 if (A->getOption().matches(options::OPT_fsanitize_EQ) && 945 0 == strcmp("all", Value)) 946 Kind = 0; 947 // Similarly, don't accept -fsanitize=efficiency-all. 948 else if (A->getOption().matches(options::OPT_fsanitize_EQ) && 949 0 == strcmp("efficiency-all", Value)) 950 Kind = 0; 951 else 952 Kind = parseSanitizerValue(Value, /*AllowGroups=*/true); 953 954 if (Kind) 955 Kinds |= Kind; 956 else if (DiagnoseErrors) 957 D.Diag(clang::diag::err_drv_unsupported_option_argument) 958 << A->getOption().getName() << Value; 959 } 960 return Kinds; 961 } 962 963 int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { 964 assert(A->getOption().matches(options::OPT_fsanitize_coverage) || 965 A->getOption().matches(options::OPT_fno_sanitize_coverage)); 966 int Features = 0; 967 for (int i = 0, n = A->getNumValues(); i != n; ++i) { 968 const char *Value = A->getValue(i); 969 int F = llvm::StringSwitch<int>(Value) 970 .Case("func", CoverageFunc) 971 .Case("bb", CoverageBB) 972 .Case("edge", CoverageEdge) 973 .Case("indirect-calls", CoverageIndirCall) 974 .Case("trace-bb", CoverageTraceBB) 975 .Case("trace-cmp", CoverageTraceCmp) 976 .Case("trace-div", CoverageTraceDiv) 977 .Case("trace-gep", CoverageTraceGep) 978 .Case("8bit-counters", Coverage8bitCounters) 979 .Case("trace-pc", CoverageTracePC) 980 .Case("trace-pc-guard", CoverageTracePCGuard) 981 .Case("no-prune", CoverageNoPrune) 982 .Case("inline-8bit-counters", CoverageInline8bitCounters) 983 .Case("pc-table", CoveragePCTable) 984 .Case("stack-depth", CoverageStackDepth) 985 .Default(0); 986 if (F == 0) 987 D.Diag(clang::diag::err_drv_unsupported_option_argument) 988 << A->getOption().getName() << Value; 989 Features |= F; 990 } 991 return Features; 992 } 993 994 std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, 995 SanitizerMask Mask) { 996 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), 997 E = Args.rend(); 998 I != E; ++I) { 999 const auto *Arg = *I; 1000 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { 1001 SanitizerMask AddKinds = 1002 expandSanitizerGroups(parseArgValues(D, Arg, false)); 1003 if (AddKinds & Mask) 1004 return describeSanitizeArg(Arg, Mask); 1005 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { 1006 SanitizerMask RemoveKinds = 1007 expandSanitizerGroups(parseArgValues(D, Arg, false)); 1008 Mask &= ~RemoveKinds; 1009 } 1010 } 1011 llvm_unreachable("arg list didn't provide expected value"); 1012 } 1013 1014 std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) { 1015 assert(A->getOption().matches(options::OPT_fsanitize_EQ) 1016 && "Invalid argument in describeSanitizerArg!"); 1017 1018 std::string Sanitizers; 1019 for (int i = 0, n = A->getNumValues(); i != n; ++i) { 1020 if (expandSanitizerGroups( 1021 parseSanitizerValue(A->getValue(i), /*AllowGroups=*/true)) & 1022 Mask) { 1023 if (!Sanitizers.empty()) 1024 Sanitizers += ","; 1025 Sanitizers += A->getValue(i); 1026 } 1027 } 1028 1029 assert(!Sanitizers.empty() && "arg didn't provide expected value"); 1030 return "-fsanitize=" + Sanitizers; 1031 } 1032