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