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 "clang/Driver/Driver.h" 11 #include "clang/Driver/DriverDiagnostic.h" 12 #include "clang/Driver/Options.h" 13 #include "clang/Driver/ToolChain.h" 14 #include "llvm/ADT/StringExtras.h" 15 #include "llvm/ADT/StringSwitch.h" 16 #include "llvm/Support/FileSystem.h" 17 #include "llvm/Support/Path.h" 18 #include "llvm/Support/SpecialCaseList.h" 19 #include <memory> 20 21 using namespace clang::driver; 22 using namespace llvm::opt; 23 24 namespace { 25 /// Assign ordinals to possible values of -fsanitize= flag. 26 /// We use the ordinal values as bit positions within \c SanitizeKind. 27 enum SanitizeOrdinal : uint64_t { 28 #define SANITIZER(NAME, ID) SO_##ID, 29 #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, 30 #include "clang/Basic/Sanitizers.def" 31 SO_Count 32 }; 33 34 /// Represents a set of sanitizer kinds. It is also used to define: 35 /// 1) set of sanitizers each sanitizer group expands into. 36 /// 2) set of sanitizers sharing a specific property (e.g. 37 /// all sanitizers with zero-base shadow). 38 enum SanitizeKind : uint64_t { 39 #define SANITIZER(NAME, ID) ID = 1ULL << SO_##ID, 40 #define SANITIZER_GROUP(NAME, ID, ALIAS) \ 41 ID = ALIAS, ID##Group = 1ULL << SO_##ID##Group, 42 #include "clang/Basic/Sanitizers.def" 43 NeedsUbsanRt = Undefined | Integer, 44 NotAllowedWithTrap = Vptr, 45 RequiresPIE = Memory | DataFlow, 46 NeedsUnwindTables = Address | Thread | Memory | DataFlow, 47 SupportsCoverage = Address | Memory | Leak | Undefined | Integer | DataFlow, 48 RecoverableByDefault = Undefined | Integer, 49 Unrecoverable = Address | Unreachable | Return, 50 LegacyFsanitizeRecoverMask = Undefined | Integer, 51 NeedsLTO = CFI, 52 }; 53 } 54 55 /// Returns true if set of \p Sanitizers contain at least one sanitizer from 56 /// \p Kinds. 57 static bool hasOneOf(const clang::SanitizerSet &Sanitizers, uint64_t Kinds) { 58 #define SANITIZER(NAME, ID) \ 59 if (Sanitizers.has(clang::SanitizerKind::ID) && (Kinds & ID)) \ 60 return true; 61 #include "clang/Basic/Sanitizers.def" 62 return false; 63 } 64 65 /// Adds all sanitizers from \p Kinds to \p Sanitizers. 66 static void addAllOf(clang::SanitizerSet &Sanitizers, uint64_t Kinds) { 67 #define SANITIZER(NAME, ID) \ 68 if (Kinds & ID) \ 69 Sanitizers.set(clang::SanitizerKind::ID, true); 70 #include "clang/Basic/Sanitizers.def" 71 } 72 73 static uint64_t toSanitizeKind(clang::SanitizerKind K) { 74 #define SANITIZER(NAME, ID) \ 75 if (K == clang::SanitizerKind::ID) \ 76 return ID; 77 #include "clang/Basic/Sanitizers.def" 78 llvm_unreachable("Invalid SanitizerKind!"); 79 } 80 81 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. 82 /// Returns a member of the \c SanitizeKind enumeration, or \c 0 83 /// if \p Value is not known. 84 static uint64_t parseValue(const char *Value); 85 86 /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any 87 /// invalid components. Returns OR of members of \c SanitizeKind enumeration. 88 static uint64_t parseArgValues(const Driver &D, const llvm::opt::Arg *A, 89 bool DiagnoseErrors); 90 91 /// Produce an argument string from ArgList \p Args, which shows how it 92 /// provides some sanitizer kind from \p Mask. For example, the argument list 93 /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt 94 /// would produce "-fsanitize=vptr". 95 static std::string lastArgumentForMask(const Driver &D, 96 const llvm::opt::ArgList &Args, 97 uint64_t Mask); 98 99 static std::string lastArgumentForKind(const Driver &D, 100 const llvm::opt::ArgList &Args, 101 clang::SanitizerKind K) { 102 return lastArgumentForMask(D, Args, toSanitizeKind(K)); 103 } 104 105 /// Produce an argument string from argument \p A, which shows how it provides 106 /// a value in \p Mask. For instance, the argument 107 /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce 108 /// "-fsanitize=alignment". 109 static std::string describeSanitizeArg(const llvm::opt::Arg *A, uint64_t Mask); 110 111 /// Produce a string containing comma-separated names of sanitizers in \p 112 /// Sanitizers set. 113 static std::string toString(const clang::SanitizerSet &Sanitizers); 114 115 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers 116 /// this group enables. 117 static uint64_t expandGroups(uint64_t Kinds); 118 119 static uint64_t getToolchainUnsupportedKinds(const ToolChain &TC) { 120 bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD; 121 bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux; 122 bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86; 123 bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64; 124 bool IsMIPS64 = TC.getTriple().getArch() == llvm::Triple::mips64 || 125 TC.getTriple().getArch() == llvm::Triple::mips64el; 126 127 uint64_t Unsupported = 0; 128 if (!(IsLinux && (IsX86_64 || IsMIPS64))) { 129 Unsupported |= Memory | DataFlow; 130 } 131 if (!((IsLinux || IsFreeBSD) && (IsX86_64 || IsMIPS64))) { 132 Unsupported |= Thread; 133 } 134 if (!(IsLinux && (IsX86 || IsX86_64))) { 135 Unsupported |= Function; 136 } 137 return Unsupported; 138 } 139 140 static bool getDefaultBlacklist(const Driver &D, uint64_t Kinds, 141 std::string &BLPath) { 142 const char *BlacklistFile = nullptr; 143 if (Kinds & SanitizeKind::Address) 144 BlacklistFile = "asan_blacklist.txt"; 145 else if (Kinds & SanitizeKind::Memory) 146 BlacklistFile = "msan_blacklist.txt"; 147 else if (Kinds & SanitizeKind::Thread) 148 BlacklistFile = "tsan_blacklist.txt"; 149 else if (Kinds & SanitizeKind::DataFlow) 150 BlacklistFile = "dfsan_abilist.txt"; 151 152 if (BlacklistFile) { 153 clang::SmallString<64> Path(D.ResourceDir); 154 llvm::sys::path::append(Path, BlacklistFile); 155 BLPath = Path.str(); 156 return true; 157 } 158 return false; 159 } 160 161 bool SanitizerArgs::needsUbsanRt() const { 162 return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt) && 163 !Sanitizers.has(SanitizerKind::Address); 164 } 165 166 bool SanitizerArgs::requiresPIE() const { 167 return AsanZeroBaseShadow || hasOneOf(Sanitizers, RequiresPIE); 168 } 169 170 bool SanitizerArgs::needsUnwindTables() const { 171 return hasOneOf(Sanitizers, NeedsUnwindTables); 172 } 173 174 bool SanitizerArgs::needsLTO() const { 175 return hasOneOf(Sanitizers, NeedsLTO); 176 } 177 178 void SanitizerArgs::clear() { 179 Sanitizers.clear(); 180 RecoverableSanitizers.clear(); 181 BlacklistFiles.clear(); 182 SanitizeCoverage = 0; 183 MsanTrackOrigins = 0; 184 AsanFieldPadding = 0; 185 AsanZeroBaseShadow = false; 186 UbsanTrapOnError = false; 187 AsanSharedRuntime = false; 188 LinkCXXRuntimes = false; 189 } 190 191 SanitizerArgs::SanitizerArgs(const ToolChain &TC, 192 const llvm::opt::ArgList &Args) { 193 clear(); 194 uint64_t AllRemove = 0; // During the loop below, the accumulated set of 195 // sanitizers disabled by the current sanitizer 196 // argument or any argument after it. 197 uint64_t DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. 198 // Used to deduplicate diagnostics. 199 uint64_t Kinds = 0; 200 uint64_t NotSupported = getToolchainUnsupportedKinds(TC); 201 ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); 202 203 const Driver &D = TC.getDriver(); 204 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); 205 I != E; ++I) { 206 const auto *Arg = *I; 207 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { 208 Arg->claim(); 209 uint64_t Add = parseArgValues(D, Arg, true); 210 211 // Avoid diagnosing any sanitizer which is disabled later. 212 Add &= ~AllRemove; 213 // At this point we have not expanded groups, so any unsupported 214 // sanitizers in Add are those which have been explicitly enabled. 215 // Diagnose them. 216 if (uint64_t KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) { 217 // Only diagnose the new kinds. 218 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); 219 D.Diag(diag::err_drv_unsupported_opt_for_target) 220 << Desc << TC.getTriple().str(); 221 DiagnosedKinds |= KindsToDiagnose; 222 } 223 Add &= ~NotSupported; 224 225 // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups 226 // so we don't error out if -fno-rtti and -fsanitize=undefined were 227 // passed. 228 if (Add & SanitizeKind::Vptr && 229 (RTTIMode == ToolChain::RM_DisabledImplicitly || 230 RTTIMode == ToolChain::RM_DisabledExplicitly)) { 231 if (RTTIMode == ToolChain::RM_DisabledImplicitly) 232 // Warn about not having rtti enabled if the vptr sanitizer is 233 // explicitly enabled 234 D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default); 235 else { 236 const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg(); 237 assert(NoRTTIArg && 238 "RTTI disabled explicitly but we have no argument!"); 239 D.Diag(diag::err_drv_argument_not_allowed_with) 240 << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args); 241 } 242 243 // Take out the Vptr sanitizer from the enabled sanitizers 244 AllRemove |= SanitizeKind::Vptr; 245 } 246 247 Add = expandGroups(Add); 248 // Group expansion may have enabled a sanitizer which is disabled later. 249 Add &= ~AllRemove; 250 // Silently discard any unsupported sanitizers implicitly enabled through 251 // group expansion. 252 Add &= ~NotSupported; 253 254 Kinds |= Add; 255 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { 256 Arg->claim(); 257 uint64_t Remove = parseArgValues(D, Arg, true); 258 AllRemove |= expandGroups(Remove); 259 } 260 } 261 262 // We disable the vptr sanitizer if it was enabled by group expansion but RTTI 263 // is disabled. 264 if ((Kinds & SanitizeKind::Vptr) && 265 (RTTIMode == ToolChain::RM_DisabledImplicitly || 266 RTTIMode == ToolChain::RM_DisabledExplicitly)) { 267 Kinds &= ~SanitizeKind::Vptr; 268 } 269 270 // Warn about undefined sanitizer options that require runtime support. 271 UbsanTrapOnError = 272 Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, 273 options::OPT_fno_sanitize_undefined_trap_on_error, false); 274 if (UbsanTrapOnError && (Kinds & SanitizeKind::NotAllowedWithTrap)) { 275 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 276 << lastArgumentForMask(D, Args, NotAllowedWithTrap) 277 << "-fsanitize-undefined-trap-on-error"; 278 Kinds &= ~SanitizeKind::NotAllowedWithTrap; 279 } 280 281 // Warn about incompatible groups of sanitizers. 282 std::pair<uint64_t, uint64_t> IncompatibleGroups[] = { 283 std::make_pair(SanitizeKind::Address, SanitizeKind::Thread), 284 std::make_pair(SanitizeKind::Address, SanitizeKind::Memory), 285 std::make_pair(SanitizeKind::Thread, SanitizeKind::Memory), 286 std::make_pair(SanitizeKind::Leak, SanitizeKind::Thread), 287 std::make_pair(SanitizeKind::Leak, SanitizeKind::Memory), 288 std::make_pair(SanitizeKind::NeedsUbsanRt, SanitizeKind::Thread), 289 std::make_pair(SanitizeKind::NeedsUbsanRt, SanitizeKind::Memory)}; 290 for (auto G : IncompatibleGroups) { 291 uint64_t Group = G.first; 292 if (Kinds & Group) { 293 if (uint64_t Incompatible = Kinds & G.second) { 294 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 295 << lastArgumentForMask(D, Args, Group) 296 << lastArgumentForMask(D, Args, Incompatible); 297 Kinds &= ~Incompatible; 298 } 299 } 300 } 301 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of 302 // -fsanitize=address. Perhaps it should print an error, or perhaps 303 // -f(-no)sanitize=leak should change whether leak detection is enabled by 304 // default in ASan? 305 306 // Parse -f(no-)?sanitize-recover flags. 307 uint64_t RecoverableKinds = RecoverableByDefault; 308 uint64_t DiagnosedUnrecoverableKinds = 0; 309 for (const auto *Arg : Args) { 310 const char *DeprecatedReplacement = nullptr; 311 if (Arg->getOption().matches(options::OPT_fsanitize_recover)) { 312 DeprecatedReplacement = "-fsanitize-recover=undefined,integer"; 313 RecoverableKinds |= expandGroups(LegacyFsanitizeRecoverMask); 314 Arg->claim(); 315 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) { 316 DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer"; 317 RecoverableKinds &= ~expandGroups(LegacyFsanitizeRecoverMask); 318 Arg->claim(); 319 } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) { 320 uint64_t Add = parseArgValues(D, Arg, true); 321 // Report error if user explicitly tries to recover from unrecoverable 322 // sanitizer. 323 if (uint64_t KindsToDiagnose = 324 Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { 325 SanitizerSet SetToDiagnose; 326 addAllOf(SetToDiagnose, KindsToDiagnose); 327 D.Diag(diag::err_drv_unsupported_option_argument) 328 << Arg->getOption().getName() << toString(SetToDiagnose); 329 DiagnosedUnrecoverableKinds |= KindsToDiagnose; 330 } 331 RecoverableKinds |= expandGroups(Add); 332 Arg->claim(); 333 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) { 334 RecoverableKinds &= ~expandGroups(parseArgValues(D, Arg, true)); 335 Arg->claim(); 336 } 337 if (DeprecatedReplacement) { 338 D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) 339 << DeprecatedReplacement; 340 } 341 } 342 RecoverableKinds &= Kinds; 343 RecoverableKinds &= ~Unrecoverable; 344 345 // Setup blacklist files. 346 // Add default blacklist from resource directory. 347 { 348 std::string BLPath; 349 if (getDefaultBlacklist(D, Kinds, BLPath) && llvm::sys::fs::exists(BLPath)) 350 BlacklistFiles.push_back(BLPath); 351 } 352 // Parse -f(no-)sanitize-blacklist options. 353 for (const auto *Arg : Args) { 354 if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { 355 Arg->claim(); 356 std::string BLPath = Arg->getValue(); 357 if (llvm::sys::fs::exists(BLPath)) 358 BlacklistFiles.push_back(BLPath); 359 else 360 D.Diag(clang::diag::err_drv_no_such_file) << BLPath; 361 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { 362 Arg->claim(); 363 BlacklistFiles.clear(); 364 } 365 } 366 // Validate blacklists format. 367 { 368 std::string BLError; 369 std::unique_ptr<llvm::SpecialCaseList> SCL( 370 llvm::SpecialCaseList::create(BlacklistFiles, BLError)); 371 if (!SCL.get()) 372 D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; 373 } 374 375 // Parse -f[no-]sanitize-memory-track-origins[=level] options. 376 if (Kinds & SanitizeKind::Memory) { 377 if (Arg *A = 378 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, 379 options::OPT_fsanitize_memory_track_origins, 380 options::OPT_fno_sanitize_memory_track_origins)) { 381 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { 382 MsanTrackOrigins = 2; 383 } else if (A->getOption().matches( 384 options::OPT_fno_sanitize_memory_track_origins)) { 385 MsanTrackOrigins = 0; 386 } else { 387 StringRef S = A->getValue(); 388 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || 389 MsanTrackOrigins > 2) { 390 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 391 } 392 } 393 } 394 } 395 396 // Parse -fsanitize-coverage=N. Currently one of asan/msan/lsan is required. 397 if (Kinds & SanitizeKind::SupportsCoverage) { 398 if (Arg *A = Args.getLastArg(options::OPT_fsanitize_coverage)) { 399 StringRef S = A->getValue(); 400 // Legal values are 0..4. 401 if (S.getAsInteger(0, SanitizeCoverage) || SanitizeCoverage < 0 || 402 SanitizeCoverage > 4) 403 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 404 } 405 } 406 407 if (Kinds & SanitizeKind::Address) { 408 AsanSharedRuntime = 409 Args.hasArg(options::OPT_shared_libasan) || 410 (TC.getTriple().getEnvironment() == llvm::Triple::Android); 411 AsanZeroBaseShadow = 412 (TC.getTriple().getEnvironment() == llvm::Triple::Android); 413 if (Arg *A = 414 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { 415 StringRef S = A->getValue(); 416 // Legal values are 0 and 1, 2, but in future we may add more levels. 417 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || 418 AsanFieldPadding > 2) { 419 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 420 } 421 } 422 423 if (Arg *WindowsDebugRTArg = 424 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT, 425 options::OPT__SLASH_MDd, options::OPT__SLASH_MD, 426 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) { 427 switch (WindowsDebugRTArg->getOption().getID()) { 428 case options::OPT__SLASH_MTd: 429 case options::OPT__SLASH_MDd: 430 case options::OPT__SLASH_LDd: 431 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 432 << WindowsDebugRTArg->getAsString(Args) 433 << lastArgumentForKind(D, Args, SanitizerKind::Address); 434 D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); 435 } 436 } 437 } 438 439 // Parse -link-cxx-sanitizer flag. 440 LinkCXXRuntimes = 441 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); 442 443 // Finally, initialize the set of available and recoverable sanitizers. 444 addAllOf(Sanitizers, Kinds); 445 addAllOf(RecoverableSanitizers, RecoverableKinds); 446 } 447 448 static std::string toString(const clang::SanitizerSet &Sanitizers) { 449 std::string Res; 450 #define SANITIZER(NAME, ID) \ 451 if (Sanitizers.has(clang::SanitizerKind::ID)) { \ 452 if (!Res.empty()) \ 453 Res += ","; \ 454 Res += NAME; \ 455 } 456 #include "clang/Basic/Sanitizers.def" 457 return Res; 458 } 459 460 void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, 461 llvm::opt::ArgStringList &CmdArgs) const { 462 if (Sanitizers.empty()) 463 return; 464 CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers))); 465 466 if (!RecoverableSanitizers.empty()) 467 CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" + 468 toString(RecoverableSanitizers))); 469 470 if (UbsanTrapOnError) 471 CmdArgs.push_back("-fsanitize-undefined-trap-on-error"); 472 473 for (const auto &BLPath : BlacklistFiles) { 474 SmallString<64> BlacklistOpt("-fsanitize-blacklist="); 475 BlacklistOpt += BLPath; 476 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); 477 } 478 479 if (MsanTrackOrigins) 480 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + 481 llvm::utostr(MsanTrackOrigins))); 482 if (AsanFieldPadding) 483 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + 484 llvm::utostr(AsanFieldPadding))); 485 if (SanitizeCoverage) 486 CmdArgs.push_back(Args.MakeArgString("-fsanitize-coverage=" + 487 llvm::utostr(SanitizeCoverage))); 488 // MSan: Workaround for PR16386. 489 // ASan: This is mainly to help LSan with cases such as 490 // https://code.google.com/p/address-sanitizer/issues/detail?id=373 491 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't 492 // affect compilation. 493 if (Sanitizers.has(SanitizerKind::Memory) || 494 Sanitizers.has(SanitizerKind::Address)) 495 CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); 496 } 497 498 uint64_t parseValue(const char *Value) { 499 uint64_t ParsedKind = llvm::StringSwitch<SanitizeKind>(Value) 500 #define SANITIZER(NAME, ID) .Case(NAME, ID) 501 #define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group) 502 #include "clang/Basic/Sanitizers.def" 503 .Default(SanitizeKind()); 504 return ParsedKind; 505 } 506 507 uint64_t expandGroups(uint64_t Kinds) { 508 #define SANITIZER(NAME, ID) 509 #define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID; 510 #include "clang/Basic/Sanitizers.def" 511 return Kinds; 512 } 513 514 uint64_t parseArgValues(const Driver &D, const llvm::opt::Arg *A, 515 bool DiagnoseErrors) { 516 assert((A->getOption().matches(options::OPT_fsanitize_EQ) || 517 A->getOption().matches(options::OPT_fno_sanitize_EQ) || 518 A->getOption().matches(options::OPT_fsanitize_recover_EQ) || 519 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) && 520 "Invalid argument in parseArgValues!"); 521 uint64_t Kinds = 0; 522 for (int i = 0, n = A->getNumValues(); i != n; ++i) { 523 const char *Value = A->getValue(i); 524 uint64_t Kind; 525 // Special case: don't accept -fsanitize=all. 526 if (A->getOption().matches(options::OPT_fsanitize_EQ) && 527 0 == strcmp("all", Value)) 528 Kind = 0; 529 else 530 Kind = parseValue(Value); 531 532 if (Kind) 533 Kinds |= Kind; 534 else if (DiagnoseErrors) 535 D.Diag(clang::diag::err_drv_unsupported_option_argument) 536 << A->getOption().getName() << Value; 537 } 538 return Kinds; 539 } 540 541 std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, 542 uint64_t Mask) { 543 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), 544 E = Args.rend(); 545 I != E; ++I) { 546 const auto *Arg = *I; 547 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { 548 uint64_t AddKinds = expandGroups(parseArgValues(D, Arg, false)); 549 if (AddKinds & Mask) 550 return describeSanitizeArg(Arg, Mask); 551 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { 552 uint64_t RemoveKinds = expandGroups(parseArgValues(D, Arg, false)); 553 Mask &= ~RemoveKinds; 554 } 555 } 556 llvm_unreachable("arg list didn't provide expected value"); 557 } 558 559 std::string describeSanitizeArg(const llvm::opt::Arg *A, uint64_t Mask) { 560 assert(A->getOption().matches(options::OPT_fsanitize_EQ) 561 && "Invalid argument in describeSanitizerArg!"); 562 563 std::string Sanitizers; 564 for (int i = 0, n = A->getNumValues(); i != n; ++i) { 565 if (expandGroups(parseValue(A->getValue(i))) & Mask) { 566 if (!Sanitizers.empty()) 567 Sanitizers += ","; 568 Sanitizers += A->getValue(i); 569 } 570 } 571 572 assert(!Sanitizers.empty() && "arg didn't provide expected value"); 573 return "-fsanitize=" + Sanitizers; 574 } 575