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(KernelHWAddress, Address | HWAddress | Leak | Thread | 380 Memory | KernelAddress | Efficiency | 381 SafeStack), 382 std::make_pair(KernelMemory, Address | HWAddress | Leak | Thread | 383 Memory | KernelAddress | Efficiency | 384 Scudo | SafeStack)}; 385 // Enable toolchain specific default sanitizers if not explicitly disabled. 386 SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove; 387 388 // Disable default sanitizers that are incompatible with explicitly requested 389 // ones. 390 for (auto G : IncompatibleGroups) { 391 SanitizerMask Group = G.first; 392 if ((Default & Group) && (Kinds & G.second)) 393 Default &= ~Group; 394 } 395 396 Kinds |= Default; 397 398 // We disable the vptr sanitizer if it was enabled by group expansion but RTTI 399 // is disabled. 400 if ((Kinds & Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { 401 Kinds &= ~Vptr; 402 } 403 404 // Check that LTO is enabled if we need it. 405 if ((Kinds & NeedsLTO) && !D.isUsingLTO()) { 406 D.Diag(diag::err_drv_argument_only_allowed_with) 407 << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; 408 } 409 410 if ((Kinds & ShadowCallStack) && 411 TC.getTriple().getArch() == llvm::Triple::aarch64 && 412 !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) && 413 !Args.hasArg(options::OPT_ffixed_x18)) { 414 D.Diag(diag::err_drv_argument_only_allowed_with) 415 << lastArgumentForMask(D, Args, Kinds & ShadowCallStack) 416 << "-ffixed-x18"; 417 } 418 419 // Report error if there are non-trapping sanitizers that require 420 // c++abi-specific parts of UBSan runtime, and they are not provided by the 421 // toolchain. We don't have a good way to check the latter, so we just 422 // check if the toolchan supports vptr. 423 if (~Supported & Vptr) { 424 SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt; 425 // The runtime library supports the Microsoft C++ ABI, but only well enough 426 // for CFI. FIXME: Remove this once we support vptr on Windows. 427 if (TC.getTriple().isOSWindows()) 428 KindsToDiagnose &= ~CFI; 429 if (KindsToDiagnose) { 430 SanitizerSet S; 431 S.Mask = KindsToDiagnose; 432 D.Diag(diag::err_drv_unsupported_opt_for_target) 433 << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str(); 434 Kinds &= ~KindsToDiagnose; 435 } 436 } 437 438 // Warn about incompatible groups of sanitizers. 439 for (auto G : IncompatibleGroups) { 440 SanitizerMask Group = G.first; 441 if (Kinds & Group) { 442 if (SanitizerMask Incompatible = Kinds & G.second) { 443 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 444 << lastArgumentForMask(D, Args, Group) 445 << lastArgumentForMask(D, Args, Incompatible); 446 Kinds &= ~Incompatible; 447 } 448 } 449 } 450 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of 451 // -fsanitize=address. Perhaps it should print an error, or perhaps 452 // -f(-no)sanitize=leak should change whether leak detection is enabled by 453 // default in ASan? 454 455 // Parse -f(no-)?sanitize-recover flags. 456 SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable; 457 SanitizerMask DiagnosedUnrecoverableKinds = 0; 458 SanitizerMask DiagnosedAlwaysRecoverableKinds = 0; 459 for (const auto *Arg : Args) { 460 const char *DeprecatedReplacement = nullptr; 461 if (Arg->getOption().matches(options::OPT_fsanitize_recover)) { 462 DeprecatedReplacement = 463 "-fsanitize-recover=undefined,integer' or '-fsanitize-recover=all"; 464 RecoverableKinds |= expandSanitizerGroups(LegacyFsanitizeRecoverMask); 465 Arg->claim(); 466 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) { 467 DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer' or " 468 "'-fno-sanitize-recover=all"; 469 RecoverableKinds &= ~expandSanitizerGroups(LegacyFsanitizeRecoverMask); 470 Arg->claim(); 471 } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) { 472 SanitizerMask Add = parseArgValues(D, Arg, true); 473 // Report error if user explicitly tries to recover from unrecoverable 474 // sanitizer. 475 if (SanitizerMask KindsToDiagnose = 476 Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { 477 SanitizerSet SetToDiagnose; 478 SetToDiagnose.Mask |= KindsToDiagnose; 479 D.Diag(diag::err_drv_unsupported_option_argument) 480 << Arg->getOption().getName() << toString(SetToDiagnose); 481 DiagnosedUnrecoverableKinds |= KindsToDiagnose; 482 } 483 RecoverableKinds |= expandSanitizerGroups(Add); 484 Arg->claim(); 485 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) { 486 SanitizerMask Remove = parseArgValues(D, Arg, true); 487 // Report error if user explicitly tries to disable recovery from 488 // always recoverable sanitizer. 489 if (SanitizerMask KindsToDiagnose = 490 Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) { 491 SanitizerSet SetToDiagnose; 492 SetToDiagnose.Mask |= KindsToDiagnose; 493 D.Diag(diag::err_drv_unsupported_option_argument) 494 << Arg->getOption().getName() << toString(SetToDiagnose); 495 DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose; 496 } 497 RecoverableKinds &= ~expandSanitizerGroups(Remove); 498 Arg->claim(); 499 } 500 if (DeprecatedReplacement) { 501 D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) 502 << DeprecatedReplacement; 503 } 504 } 505 RecoverableKinds &= Kinds; 506 RecoverableKinds &= ~Unrecoverable; 507 508 TrappingKinds &= Kinds; 509 RecoverableKinds &= ~TrappingKinds; 510 511 // Setup blacklist files. 512 // Add default blacklist from resource directory. 513 addDefaultBlacklists(D, Kinds, BlacklistFiles); 514 // Parse -f(no-)sanitize-blacklist options. 515 for (const auto *Arg : Args) { 516 if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { 517 Arg->claim(); 518 std::string BLPath = Arg->getValue(); 519 if (llvm::sys::fs::exists(BLPath)) { 520 BlacklistFiles.push_back(BLPath); 521 ExtraDeps.push_back(BLPath); 522 } else { 523 D.Diag(clang::diag::err_drv_no_such_file) << BLPath; 524 } 525 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { 526 Arg->claim(); 527 BlacklistFiles.clear(); 528 ExtraDeps.clear(); 529 } 530 } 531 // Validate blacklists format. 532 { 533 std::string BLError; 534 std::unique_ptr<llvm::SpecialCaseList> SCL( 535 llvm::SpecialCaseList::create(BlacklistFiles, BLError)); 536 if (!SCL.get()) 537 D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; 538 } 539 540 // Parse -f[no-]sanitize-memory-track-origins[=level] options. 541 if (AllAddedKinds & Memory) { 542 if (Arg *A = 543 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, 544 options::OPT_fsanitize_memory_track_origins, 545 options::OPT_fno_sanitize_memory_track_origins)) { 546 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { 547 MsanTrackOrigins = 2; 548 } else if (A->getOption().matches( 549 options::OPT_fno_sanitize_memory_track_origins)) { 550 MsanTrackOrigins = 0; 551 } else { 552 StringRef S = A->getValue(); 553 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || 554 MsanTrackOrigins > 2) { 555 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 556 } 557 } 558 } 559 MsanUseAfterDtor = 560 Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor, 561 options::OPT_fno_sanitize_memory_use_after_dtor, 562 MsanUseAfterDtor); 563 NeedPIE |= !(TC.getTriple().isOSLinux() && 564 TC.getTriple().getArch() == llvm::Triple::x86_64); 565 } else { 566 MsanUseAfterDtor = false; 567 } 568 569 if (AllAddedKinds & Thread) { 570 TsanMemoryAccess = Args.hasFlag(options::OPT_fsanitize_thread_memory_access, 571 options::OPT_fno_sanitize_thread_memory_access, 572 TsanMemoryAccess); 573 TsanFuncEntryExit = Args.hasFlag(options::OPT_fsanitize_thread_func_entry_exit, 574 options::OPT_fno_sanitize_thread_func_entry_exit, 575 TsanFuncEntryExit); 576 TsanAtomics = Args.hasFlag(options::OPT_fsanitize_thread_atomics, 577 options::OPT_fno_sanitize_thread_atomics, 578 TsanAtomics); 579 } 580 581 if (AllAddedKinds & CFI) { 582 // Without PIE, external function address may resolve to a PLT record, which 583 // can not be verified by the target module. 584 NeedPIE |= CfiCrossDso; 585 CfiICallGeneralizePointers = 586 Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers); 587 588 if (CfiCrossDso && CfiICallGeneralizePointers) 589 D.Diag(diag::err_drv_argument_not_allowed_with) 590 << "-fsanitize-cfi-cross-dso" 591 << "-fsanitize-cfi-icall-generalize-pointers"; 592 } 593 594 Stats = Args.hasFlag(options::OPT_fsanitize_stats, 595 options::OPT_fno_sanitize_stats, false); 596 597 if (MinimalRuntime) { 598 SanitizerMask IncompatibleMask = 599 Kinds & ~setGroupBits(CompatibleWithMinimalRuntime); 600 if (IncompatibleMask) 601 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 602 << "-fsanitize-minimal-runtime" 603 << lastArgumentForMask(D, Args, IncompatibleMask); 604 605 SanitizerMask NonTrappingCfi = Kinds & CFI & ~TrappingKinds; 606 if (NonTrappingCfi) 607 D.Diag(clang::diag::err_drv_argument_only_allowed_with) 608 << "fsanitize-minimal-runtime" 609 << "fsanitize-trap=cfi"; 610 } 611 612 // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the 613 // enabled sanitizers. 614 for (const auto *Arg : Args) { 615 if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { 616 int LegacySanitizeCoverage; 617 if (Arg->getNumValues() == 1 && 618 !StringRef(Arg->getValue(0)) 619 .getAsInteger(0, LegacySanitizeCoverage)) { 620 CoverageFeatures = 0; 621 Arg->claim(); 622 if (LegacySanitizeCoverage != 0) { 623 D.Diag(diag::warn_drv_deprecated_arg) 624 << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard"; 625 } 626 continue; 627 } 628 CoverageFeatures |= parseCoverageFeatures(D, Arg); 629 630 // Disable coverage and not claim the flags if there is at least one 631 // non-supporting sanitizer. 632 if (!(AllAddedKinds & ~AllRemove & ~setGroupBits(SupportsCoverage))) { 633 Arg->claim(); 634 } else { 635 CoverageFeatures = 0; 636 } 637 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { 638 Arg->claim(); 639 CoverageFeatures &= ~parseCoverageFeatures(D, Arg); 640 } 641 } 642 // Choose at most one coverage type: function, bb, or edge. 643 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB)) 644 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 645 << "-fsanitize-coverage=func" 646 << "-fsanitize-coverage=bb"; 647 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge)) 648 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 649 << "-fsanitize-coverage=func" 650 << "-fsanitize-coverage=edge"; 651 if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge)) 652 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 653 << "-fsanitize-coverage=bb" 654 << "-fsanitize-coverage=edge"; 655 // Basic block tracing and 8-bit counters require some type of coverage 656 // enabled. 657 if (CoverageFeatures & CoverageTraceBB) 658 D.Diag(clang::diag::warn_drv_deprecated_arg) 659 << "-fsanitize-coverage=trace-bb" 660 << "-fsanitize-coverage=trace-pc-guard"; 661 if (CoverageFeatures & Coverage8bitCounters) 662 D.Diag(clang::diag::warn_drv_deprecated_arg) 663 << "-fsanitize-coverage=8bit-counters" 664 << "-fsanitize-coverage=trace-pc-guard"; 665 666 int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; 667 int InstrumentationTypes = 668 CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters; 669 if ((CoverageFeatures & InsertionPointTypes) && 670 !(CoverageFeatures & InstrumentationTypes)) { 671 D.Diag(clang::diag::warn_drv_deprecated_arg) 672 << "-fsanitize-coverage=[func|bb|edge]" 673 << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; 674 } 675 676 // trace-pc w/o func/bb/edge implies edge. 677 if (!(CoverageFeatures & InsertionPointTypes)) { 678 if (CoverageFeatures & 679 (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) 680 CoverageFeatures |= CoverageEdge; 681 682 if (CoverageFeatures & CoverageStackDepth) 683 CoverageFeatures |= CoverageFunc; 684 } 685 686 SharedRuntime = 687 Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan, 688 TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() || 689 TC.getTriple().isOSDarwin()); 690 691 ImplicitCfiRuntime = TC.getTriple().isAndroid(); 692 693 if (AllAddedKinds & Address) { 694 NeedPIE |= TC.getTriple().isOSFuchsia(); 695 if (Arg *A = 696 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { 697 StringRef S = A->getValue(); 698 // Legal values are 0 and 1, 2, but in future we may add more levels. 699 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || 700 AsanFieldPadding > 2) { 701 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 702 } 703 } 704 705 if (Arg *WindowsDebugRTArg = 706 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT, 707 options::OPT__SLASH_MDd, options::OPT__SLASH_MD, 708 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) { 709 switch (WindowsDebugRTArg->getOption().getID()) { 710 case options::OPT__SLASH_MTd: 711 case options::OPT__SLASH_MDd: 712 case options::OPT__SLASH_LDd: 713 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 714 << WindowsDebugRTArg->getAsString(Args) 715 << lastArgumentForMask(D, Args, Address); 716 D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); 717 } 718 } 719 720 AsanUseAfterScope = Args.hasFlag( 721 options::OPT_fsanitize_address_use_after_scope, 722 options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope); 723 724 AsanPoisonCustomArrayCookie = Args.hasFlag( 725 options::OPT_fsanitize_address_poison_custom_array_cookie, 726 options::OPT_fno_sanitize_address_poison_custom_array_cookie, 727 AsanPoisonCustomArrayCookie); 728 729 // As a workaround for a bug in gold 2.26 and earlier, dead stripping of 730 // globals in ASan is disabled by default on ELF targets. 731 // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002 732 AsanGlobalsDeadStripping = 733 !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || 734 Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping); 735 736 AsanUseOdrIndicator = 737 Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator, 738 options::OPT_fno_sanitize_address_use_odr_indicator, 739 AsanUseOdrIndicator); 740 } else { 741 AsanUseAfterScope = false; 742 } 743 744 if (AllAddedKinds & SafeStack) { 745 // SafeStack runtime is built into the system on Fuchsia. 746 SafeStackRuntime = !TC.getTriple().isOSFuchsia(); 747 } 748 749 // Parse -link-cxx-sanitizer flag. 750 LinkCXXRuntimes = 751 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); 752 753 // Finally, initialize the set of available and recoverable sanitizers. 754 Sanitizers.Mask |= Kinds; 755 RecoverableSanitizers.Mask |= RecoverableKinds; 756 TrapSanitizers.Mask |= TrappingKinds; 757 assert(!(RecoverableKinds & TrappingKinds) && 758 "Overlap between recoverable and trapping sanitizers"); 759 } 760 761 static std::string toString(const clang::SanitizerSet &Sanitizers) { 762 std::string Res; 763 #define SANITIZER(NAME, ID) \ 764 if (Sanitizers.has(ID)) { \ 765 if (!Res.empty()) \ 766 Res += ","; \ 767 Res += NAME; \ 768 } 769 #include "clang/Basic/Sanitizers.def" 770 return Res; 771 } 772 773 static void addIncludeLinkerOption(const ToolChain &TC, 774 const llvm::opt::ArgList &Args, 775 llvm::opt::ArgStringList &CmdArgs, 776 StringRef SymbolName) { 777 SmallString<64> LinkerOptionFlag; 778 LinkerOptionFlag = "--linker-option=/include:"; 779 if (TC.getTriple().getArch() == llvm::Triple::x86) { 780 // Win32 mangles C function names with a '_' prefix. 781 LinkerOptionFlag += '_'; 782 } 783 LinkerOptionFlag += SymbolName; 784 CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag)); 785 } 786 787 void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, 788 llvm::opt::ArgStringList &CmdArgs, 789 types::ID InputType) const { 790 // NVPTX doesn't currently support sanitizers. Bailing out here means that 791 // e.g. -fsanitize=address applies only to host code, which is what we want 792 // for now. 793 if (TC.getTriple().isNVPTX()) 794 return; 795 796 // Translate available CoverageFeatures to corresponding clang-cc1 flags. 797 // Do it even if Sanitizers.empty() since some forms of coverage don't require 798 // sanitizers. 799 std::pair<int, const char *> CoverageFlags[] = { 800 std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"), 801 std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"), 802 std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"), 803 std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"), 804 std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"), 805 std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), 806 std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"), 807 std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"), 808 std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), 809 std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"), 810 std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"), 811 std::make_pair(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"), 812 std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"), 813 std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), 814 std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")}; 815 for (auto F : CoverageFlags) { 816 if (CoverageFeatures & F.first) 817 CmdArgs.push_back(F.second); 818 } 819 820 if (TC.getTriple().isOSWindows() && needsUbsanRt()) { 821 // Instruct the code generator to embed linker directives in the object file 822 // that cause the required runtime libraries to be linked. 823 CmdArgs.push_back(Args.MakeArgString( 824 "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone"))); 825 if (types::isCXX(InputType)) 826 CmdArgs.push_back(Args.MakeArgString( 827 "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx"))); 828 } 829 if (TC.getTriple().isOSWindows() && needsStatsRt()) { 830 CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + 831 TC.getCompilerRT(Args, "stats_client"))); 832 833 // The main executable must export the stats runtime. 834 // FIXME: Only exporting from the main executable (e.g. based on whether the 835 // translation unit defines main()) would save a little space, but having 836 // multiple copies of the runtime shouldn't hurt. 837 CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + 838 TC.getCompilerRT(Args, "stats"))); 839 addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register"); 840 } 841 842 if (Sanitizers.empty()) 843 return; 844 CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers))); 845 846 if (!RecoverableSanitizers.empty()) 847 CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" + 848 toString(RecoverableSanitizers))); 849 850 if (!TrapSanitizers.empty()) 851 CmdArgs.push_back( 852 Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); 853 854 for (const auto &BLPath : BlacklistFiles) { 855 SmallString<64> BlacklistOpt("-fsanitize-blacklist="); 856 BlacklistOpt += BLPath; 857 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); 858 } 859 for (const auto &Dep : ExtraDeps) { 860 SmallString<64> ExtraDepOpt("-fdepfile-entry="); 861 ExtraDepOpt += Dep; 862 CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); 863 } 864 865 if (MsanTrackOrigins) 866 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + 867 Twine(MsanTrackOrigins))); 868 869 if (MsanUseAfterDtor) 870 CmdArgs.push_back("-fsanitize-memory-use-after-dtor"); 871 872 // FIXME: Pass these parameters as function attributes, not as -llvm flags. 873 if (!TsanMemoryAccess) { 874 CmdArgs.push_back("-mllvm"); 875 CmdArgs.push_back("-tsan-instrument-memory-accesses=0"); 876 CmdArgs.push_back("-mllvm"); 877 CmdArgs.push_back("-tsan-instrument-memintrinsics=0"); 878 } 879 if (!TsanFuncEntryExit) { 880 CmdArgs.push_back("-mllvm"); 881 CmdArgs.push_back("-tsan-instrument-func-entry-exit=0"); 882 } 883 if (!TsanAtomics) { 884 CmdArgs.push_back("-mllvm"); 885 CmdArgs.push_back("-tsan-instrument-atomics=0"); 886 } 887 888 if (CfiCrossDso) 889 CmdArgs.push_back("-fsanitize-cfi-cross-dso"); 890 891 if (CfiICallGeneralizePointers) 892 CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers"); 893 894 if (Stats) 895 CmdArgs.push_back("-fsanitize-stats"); 896 897 if (MinimalRuntime) 898 CmdArgs.push_back("-fsanitize-minimal-runtime"); 899 900 if (AsanFieldPadding) 901 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + 902 Twine(AsanFieldPadding))); 903 904 if (AsanUseAfterScope) 905 CmdArgs.push_back("-fsanitize-address-use-after-scope"); 906 907 if (AsanPoisonCustomArrayCookie) 908 CmdArgs.push_back("-fsanitize-address-poison-custom-array-cookie"); 909 910 if (AsanGlobalsDeadStripping) 911 CmdArgs.push_back("-fsanitize-address-globals-dead-stripping"); 912 913 if (AsanUseOdrIndicator) 914 CmdArgs.push_back("-fsanitize-address-use-odr-indicator"); 915 916 // MSan: Workaround for PR16386. 917 // ASan: This is mainly to help LSan with cases such as 918 // https://github.com/google/sanitizers/issues/373 919 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't 920 // affect compilation. 921 if (Sanitizers.has(Memory) || Sanitizers.has(Address)) 922 CmdArgs.push_back("-fno-assume-sane-operator-new"); 923 924 // Require -fvisibility= flag on non-Windows when compiling if vptr CFI is 925 // enabled. 926 if (Sanitizers.hasOneOf(CFIClasses) && !TC.getTriple().isOSWindows() && 927 !Args.hasArg(options::OPT_fvisibility_EQ)) { 928 TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with) 929 << lastArgumentForMask(TC.getDriver(), Args, 930 Sanitizers.Mask & CFIClasses) 931 << "-fvisibility="; 932 } 933 } 934 935 SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, 936 bool DiagnoseErrors) { 937 assert((A->getOption().matches(options::OPT_fsanitize_EQ) || 938 A->getOption().matches(options::OPT_fno_sanitize_EQ) || 939 A->getOption().matches(options::OPT_fsanitize_recover_EQ) || 940 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) || 941 A->getOption().matches(options::OPT_fsanitize_trap_EQ) || 942 A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) && 943 "Invalid argument in parseArgValues!"); 944 SanitizerMask Kinds = 0; 945 for (int i = 0, n = A->getNumValues(); i != n; ++i) { 946 const char *Value = A->getValue(i); 947 SanitizerMask Kind; 948 // Special case: don't accept -fsanitize=all. 949 if (A->getOption().matches(options::OPT_fsanitize_EQ) && 950 0 == strcmp("all", Value)) 951 Kind = 0; 952 // Similarly, don't accept -fsanitize=efficiency-all. 953 else if (A->getOption().matches(options::OPT_fsanitize_EQ) && 954 0 == strcmp("efficiency-all", Value)) 955 Kind = 0; 956 else 957 Kind = parseSanitizerValue(Value, /*AllowGroups=*/true); 958 959 if (Kind) 960 Kinds |= Kind; 961 else if (DiagnoseErrors) 962 D.Diag(clang::diag::err_drv_unsupported_option_argument) 963 << A->getOption().getName() << Value; 964 } 965 return Kinds; 966 } 967 968 int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { 969 assert(A->getOption().matches(options::OPT_fsanitize_coverage) || 970 A->getOption().matches(options::OPT_fno_sanitize_coverage)); 971 int Features = 0; 972 for (int i = 0, n = A->getNumValues(); i != n; ++i) { 973 const char *Value = A->getValue(i); 974 int F = llvm::StringSwitch<int>(Value) 975 .Case("func", CoverageFunc) 976 .Case("bb", CoverageBB) 977 .Case("edge", CoverageEdge) 978 .Case("indirect-calls", CoverageIndirCall) 979 .Case("trace-bb", CoverageTraceBB) 980 .Case("trace-cmp", CoverageTraceCmp) 981 .Case("trace-div", CoverageTraceDiv) 982 .Case("trace-gep", CoverageTraceGep) 983 .Case("8bit-counters", Coverage8bitCounters) 984 .Case("trace-pc", CoverageTracePC) 985 .Case("trace-pc-guard", CoverageTracePCGuard) 986 .Case("no-prune", CoverageNoPrune) 987 .Case("inline-8bit-counters", CoverageInline8bitCounters) 988 .Case("pc-table", CoveragePCTable) 989 .Case("stack-depth", CoverageStackDepth) 990 .Default(0); 991 if (F == 0) 992 D.Diag(clang::diag::err_drv_unsupported_option_argument) 993 << A->getOption().getName() << Value; 994 Features |= F; 995 } 996 return Features; 997 } 998 999 std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, 1000 SanitizerMask Mask) { 1001 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), 1002 E = Args.rend(); 1003 I != E; ++I) { 1004 const auto *Arg = *I; 1005 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { 1006 SanitizerMask AddKinds = 1007 expandSanitizerGroups(parseArgValues(D, Arg, false)); 1008 if (AddKinds & Mask) 1009 return describeSanitizeArg(Arg, Mask); 1010 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { 1011 SanitizerMask RemoveKinds = 1012 expandSanitizerGroups(parseArgValues(D, Arg, false)); 1013 Mask &= ~RemoveKinds; 1014 } 1015 } 1016 llvm_unreachable("arg list didn't provide expected value"); 1017 } 1018 1019 std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) { 1020 assert(A->getOption().matches(options::OPT_fsanitize_EQ) 1021 && "Invalid argument in describeSanitizerArg!"); 1022 1023 std::string Sanitizers; 1024 for (int i = 0, n = A->getNumValues(); i != n; ++i) { 1025 if (expandSanitizerGroups( 1026 parseSanitizerValue(A->getValue(i), /*AllowGroups=*/true)) & 1027 Mask) { 1028 if (!Sanitizers.empty()) 1029 Sanitizers += ","; 1030 Sanitizers += A->getValue(i); 1031 } 1032 } 1033 1034 assert(!Sanitizers.empty() && "arg didn't provide expected value"); 1035 return "-fsanitize=" + Sanitizers; 1036 } 1037