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 "Tools.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 <memory>
22 
23 using namespace clang;
24 using namespace clang::SanitizerKind;
25 using namespace clang::driver;
26 using namespace llvm::opt;
27 
28 enum : SanitizerMask {
29   NeedsUbsanRt = Undefined | Integer | CFI,
30   NeedsUbsanCxxRt = Vptr | CFI,
31   NotAllowedWithTrap = Vptr,
32   RequiresPIE = DataFlow,
33   NeedsUnwindTables = Address | Thread | Memory | DataFlow,
34   SupportsCoverage = Address | Memory | Leak | Undefined | Integer | DataFlow,
35   RecoverableByDefault = Undefined | Integer,
36   Unrecoverable = Unreachable | Return,
37   LegacyFsanitizeRecoverMask = Undefined | Integer,
38   NeedsLTO = CFI,
39   TrappingSupported =
40       (Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI,
41   TrappingDefault = CFI,
42 };
43 
44 enum CoverageFeature {
45   CoverageFunc = 1 << 0,
46   CoverageBB = 1 << 1,
47   CoverageEdge = 1 << 2,
48   CoverageIndirCall = 1 << 3,
49   CoverageTraceBB = 1 << 4,
50   CoverageTraceCmp = 1 << 5,
51   Coverage8bitCounters = 1 << 6,
52 };
53 
54 /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
55 /// invalid components. Returns a SanitizerMask.
56 static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
57                                     bool DiagnoseErrors);
58 
59 /// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
60 /// components. Returns OR of members of \c CoverageFeature enumeration.
61 static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A);
62 
63 /// Produce an argument string from ArgList \p Args, which shows how it
64 /// provides some sanitizer kind from \p Mask. For example, the argument list
65 /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
66 /// would produce "-fsanitize=vptr".
67 static std::string lastArgumentForMask(const Driver &D,
68                                        const llvm::opt::ArgList &Args,
69                                        SanitizerMask Mask);
70 
71 /// Produce an argument string from argument \p A, which shows how it provides
72 /// a value in \p Mask. For instance, the argument
73 /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
74 /// "-fsanitize=alignment".
75 static std::string describeSanitizeArg(const llvm::opt::Arg *A,
76                                        SanitizerMask Mask);
77 
78 /// Produce a string containing comma-separated names of sanitizers in \p
79 /// Sanitizers set.
80 static std::string toString(const clang::SanitizerSet &Sanitizers);
81 
getDefaultBlacklist(const Driver & D,SanitizerMask Kinds,std::string & BLPath)82 static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds,
83                                 std::string &BLPath) {
84   const char *BlacklistFile = nullptr;
85   if (Kinds & Address)
86     BlacklistFile = "asan_blacklist.txt";
87   else if (Kinds & Memory)
88     BlacklistFile = "msan_blacklist.txt";
89   else if (Kinds & Thread)
90     BlacklistFile = "tsan_blacklist.txt";
91   else if (Kinds & DataFlow)
92     BlacklistFile = "dfsan_abilist.txt";
93   else if (Kinds & CFI)
94     BlacklistFile = "cfi_blacklist.txt";
95 
96   if (BlacklistFile) {
97     clang::SmallString<64> Path(D.ResourceDir);
98     llvm::sys::path::append(Path, BlacklistFile);
99     BLPath = Path.str();
100     return true;
101   }
102   return false;
103 }
104 
105 /// Sets group bits for every group that has at least one representative already
106 /// enabled in \p Kinds.
setGroupBits(SanitizerMask Kinds)107 static SanitizerMask setGroupBits(SanitizerMask Kinds) {
108 #define SANITIZER(NAME, ID)
109 #define SANITIZER_GROUP(NAME, ID, ALIAS)                                       \
110   if (Kinds & SanitizerKind::ID)                                               \
111     Kinds |= SanitizerKind::ID##Group;
112 #include "clang/Basic/Sanitizers.def"
113   return Kinds;
114 }
115 
parseSanitizeTrapArgs(const Driver & D,const llvm::opt::ArgList & Args)116 static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
117                                            const llvm::opt::ArgList &Args) {
118   SanitizerMask TrapRemove = 0; // During the loop below, the accumulated set of
119                                 // sanitizers disabled by the current sanitizer
120                                 // argument or any argument after it.
121   SanitizerMask TrappingKinds = 0;
122   SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported);
123 
124   for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
125        I != E; ++I) {
126     const auto *Arg = *I;
127     if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
128       Arg->claim();
129       SanitizerMask Add = parseArgValues(D, Arg, true);
130       Add &= ~TrapRemove;
131       if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) {
132         SanitizerSet S;
133         S.Mask = InvalidValues;
134         D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap"
135                                                           << toString(S);
136       }
137       TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove;
138     } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
139       Arg->claim();
140       TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true));
141     } else if (Arg->getOption().matches(
142                    options::OPT_fsanitize_undefined_trap_on_error)) {
143       Arg->claim();
144       TrappingKinds |=
145           expandSanitizerGroups(UndefinedGroup & ~TrapRemove) & ~TrapRemove;
146     } else if (Arg->getOption().matches(
147                    options::OPT_fno_sanitize_undefined_trap_on_error)) {
148       Arg->claim();
149       TrapRemove |= expandSanitizerGroups(UndefinedGroup);
150     }
151   }
152 
153   // Apply default trapping behavior.
154   TrappingKinds |= TrappingDefault & ~TrapRemove;
155 
156   return TrappingKinds;
157 }
158 
needsUbsanRt() const159 bool SanitizerArgs::needsUbsanRt() const {
160   return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) &&
161          !Sanitizers.has(Address) &&
162          !Sanitizers.has(Memory) &&
163          !Sanitizers.has(Thread) &&
164          !CfiCrossDso;
165 }
166 
needsCfiRt() const167 bool SanitizerArgs::needsCfiRt() const {
168   return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
169 }
170 
needsCfiDiagRt() const171 bool SanitizerArgs::needsCfiDiagRt() const {
172   return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
173 }
174 
requiresPIE() const175 bool SanitizerArgs::requiresPIE() const {
176   return NeedPIE || (Sanitizers.Mask & RequiresPIE);
177 }
178 
needsUnwindTables() const179 bool SanitizerArgs::needsUnwindTables() const {
180   return Sanitizers.Mask & NeedsUnwindTables;
181 }
182 
clear()183 void SanitizerArgs::clear() {
184   Sanitizers.clear();
185   RecoverableSanitizers.clear();
186   TrapSanitizers.clear();
187   BlacklistFiles.clear();
188   ExtraDeps.clear();
189   CoverageFeatures = 0;
190   MsanTrackOrigins = 0;
191   MsanUseAfterDtor = false;
192   NeedPIE = false;
193   AsanFieldPadding = 0;
194   AsanSharedRuntime = false;
195   LinkCXXRuntimes = false;
196   CfiCrossDso = false;
197 }
198 
SanitizerArgs(const ToolChain & TC,const llvm::opt::ArgList & Args)199 SanitizerArgs::SanitizerArgs(const ToolChain &TC,
200                              const llvm::opt::ArgList &Args) {
201   clear();
202   SanitizerMask AllRemove = 0;  // During the loop below, the accumulated set of
203                                 // sanitizers disabled by the current sanitizer
204                                 // argument or any argument after it.
205   SanitizerMask AllAddedKinds = 0;  // Mask of all sanitizers ever enabled by
206                                     // -fsanitize= flags (directly or via group
207                                     // expansion), some of which may be disabled
208                                     // later. Used to carefully prune
209                                     // unused-argument diagnostics.
210   SanitizerMask DiagnosedKinds = 0;  // All Kinds we have diagnosed up to now.
211                                      // Used to deduplicate diagnostics.
212   SanitizerMask Kinds = 0;
213   const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
214   ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
215 
216   const Driver &D = TC.getDriver();
217   SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args);
218   SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
219 
220   for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
221        I != E; ++I) {
222     const auto *Arg = *I;
223     if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
224       Arg->claim();
225       SanitizerMask Add = parseArgValues(D, Arg, true);
226       AllAddedKinds |= expandSanitizerGroups(Add);
227 
228       // Avoid diagnosing any sanitizer which is disabled later.
229       Add &= ~AllRemove;
230       // At this point we have not expanded groups, so any unsupported
231       // sanitizers in Add are those which have been explicitly enabled.
232       // Diagnose them.
233       if (SanitizerMask KindsToDiagnose =
234               Add & InvalidTrappingKinds & ~DiagnosedKinds) {
235         std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
236         D.Diag(diag::err_drv_argument_not_allowed_with)
237             << Desc << "-fsanitize-trap=undefined";
238         DiagnosedKinds |= KindsToDiagnose;
239       }
240       Add &= ~InvalidTrappingKinds;
241       if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
242         std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
243         D.Diag(diag::err_drv_unsupported_opt_for_target)
244             << Desc << TC.getTriple().str();
245         DiagnosedKinds |= KindsToDiagnose;
246       }
247       Add &= Supported;
248 
249       // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups
250       // so we don't error out if -fno-rtti and -fsanitize=undefined were
251       // passed.
252       if (Add & Vptr &&
253           (RTTIMode == ToolChain::RM_DisabledImplicitly ||
254            RTTIMode == ToolChain::RM_DisabledExplicitly)) {
255         if (RTTIMode == ToolChain::RM_DisabledImplicitly)
256           // Warn about not having rtti enabled if the vptr sanitizer is
257           // explicitly enabled
258           D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
259         else {
260           const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg();
261           assert(NoRTTIArg &&
262                  "RTTI disabled explicitly but we have no argument!");
263           D.Diag(diag::err_drv_argument_not_allowed_with)
264               << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
265         }
266 
267         // Take out the Vptr sanitizer from the enabled sanitizers
268         AllRemove |= Vptr;
269       }
270 
271       Add = expandSanitizerGroups(Add);
272       // Group expansion may have enabled a sanitizer which is disabled later.
273       Add &= ~AllRemove;
274       // Silently discard any unsupported sanitizers implicitly enabled through
275       // group expansion.
276       Add &= ~InvalidTrappingKinds;
277       Add &= Supported;
278 
279       Kinds |= Add;
280     } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
281       Arg->claim();
282       SanitizerMask Remove = parseArgValues(D, Arg, true);
283       AllRemove |= expandSanitizerGroups(Remove);
284     }
285   }
286 
287   // We disable the vptr sanitizer if it was enabled by group expansion but RTTI
288   // is disabled.
289   if ((Kinds & Vptr) &&
290       (RTTIMode == ToolChain::RM_DisabledImplicitly ||
291        RTTIMode == ToolChain::RM_DisabledExplicitly)) {
292     Kinds &= ~Vptr;
293   }
294 
295   // Check that LTO is enabled if we need it.
296   if ((Kinds & NeedsLTO) && !D.isUsingLTO()) {
297     D.Diag(diag::err_drv_argument_only_allowed_with)
298         << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
299   }
300 
301   // Report error if there are non-trapping sanitizers that require
302   // c++abi-specific  parts of UBSan runtime, and they are not provided by the
303   // toolchain. We don't have a good way to check the latter, so we just
304   // check if the toolchan supports vptr.
305   if (~Supported & Vptr) {
306     SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt;
307     // The runtime library supports the Microsoft C++ ABI, but only well enough
308     // for CFI. FIXME: Remove this once we support vptr on Windows.
309     if (TC.getTriple().isOSWindows())
310       KindsToDiagnose &= ~CFI;
311     if (KindsToDiagnose) {
312       SanitizerSet S;
313       S.Mask = KindsToDiagnose;
314       D.Diag(diag::err_drv_unsupported_opt_for_target)
315           << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str();
316       Kinds &= ~KindsToDiagnose;
317     }
318   }
319 
320   // Warn about incompatible groups of sanitizers.
321   std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
322       std::make_pair(Address, Thread), std::make_pair(Address, Memory),
323       std::make_pair(Thread, Memory), std::make_pair(Leak, Thread),
324       std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address),
325       std::make_pair(KernelAddress, Leak),
326       std::make_pair(KernelAddress, Thread),
327       std::make_pair(KernelAddress, Memory)};
328   for (auto G : IncompatibleGroups) {
329     SanitizerMask Group = G.first;
330     if (Kinds & Group) {
331       if (SanitizerMask Incompatible = Kinds & G.second) {
332         D.Diag(clang::diag::err_drv_argument_not_allowed_with)
333             << lastArgumentForMask(D, Args, Group)
334             << lastArgumentForMask(D, Args, Incompatible);
335         Kinds &= ~Incompatible;
336       }
337     }
338   }
339   // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
340   // -fsanitize=address. Perhaps it should print an error, or perhaps
341   // -f(-no)sanitize=leak should change whether leak detection is enabled by
342   // default in ASan?
343 
344   // Parse -f(no-)?sanitize-recover flags.
345   SanitizerMask RecoverableKinds = RecoverableByDefault;
346   SanitizerMask DiagnosedUnrecoverableKinds = 0;
347   for (const auto *Arg : Args) {
348     const char *DeprecatedReplacement = nullptr;
349     if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
350       DeprecatedReplacement = "-fsanitize-recover=undefined,integer";
351       RecoverableKinds |= expandSanitizerGroups(LegacyFsanitizeRecoverMask);
352       Arg->claim();
353     } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
354       DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer";
355       RecoverableKinds &= ~expandSanitizerGroups(LegacyFsanitizeRecoverMask);
356       Arg->claim();
357     } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
358       SanitizerMask Add = parseArgValues(D, Arg, true);
359       // Report error if user explicitly tries to recover from unrecoverable
360       // sanitizer.
361       if (SanitizerMask KindsToDiagnose =
362               Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
363         SanitizerSet SetToDiagnose;
364         SetToDiagnose.Mask |= KindsToDiagnose;
365         D.Diag(diag::err_drv_unsupported_option_argument)
366             << Arg->getOption().getName() << toString(SetToDiagnose);
367         DiagnosedUnrecoverableKinds |= KindsToDiagnose;
368       }
369       RecoverableKinds |= expandSanitizerGroups(Add);
370       Arg->claim();
371     } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
372       RecoverableKinds &= ~expandSanitizerGroups(parseArgValues(D, Arg, true));
373       Arg->claim();
374     }
375     if (DeprecatedReplacement) {
376       D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
377                                             << DeprecatedReplacement;
378     }
379   }
380   RecoverableKinds &= Kinds;
381   RecoverableKinds &= ~Unrecoverable;
382 
383   TrappingKinds &= Kinds;
384 
385   // Setup blacklist files.
386   // Add default blacklist from resource directory.
387   {
388     std::string BLPath;
389     if (getDefaultBlacklist(D, Kinds, BLPath) && llvm::sys::fs::exists(BLPath))
390       BlacklistFiles.push_back(BLPath);
391   }
392   // Parse -f(no-)sanitize-blacklist options.
393   for (const auto *Arg : Args) {
394     if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
395       Arg->claim();
396       std::string BLPath = Arg->getValue();
397       if (llvm::sys::fs::exists(BLPath)) {
398         BlacklistFiles.push_back(BLPath);
399         ExtraDeps.push_back(BLPath);
400       } else
401         D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
402 
403     } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
404       Arg->claim();
405       BlacklistFiles.clear();
406       ExtraDeps.clear();
407     }
408   }
409   // Validate blacklists format.
410   {
411     std::string BLError;
412     std::unique_ptr<llvm::SpecialCaseList> SCL(
413         llvm::SpecialCaseList::create(BlacklistFiles, BLError));
414     if (!SCL.get())
415       D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
416   }
417 
418   // Parse -f[no-]sanitize-memory-track-origins[=level] options.
419   if (AllAddedKinds & Memory) {
420     if (Arg *A =
421             Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
422                             options::OPT_fsanitize_memory_track_origins,
423                             options::OPT_fno_sanitize_memory_track_origins)) {
424       if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
425         MsanTrackOrigins = 2;
426       } else if (A->getOption().matches(
427                      options::OPT_fno_sanitize_memory_track_origins)) {
428         MsanTrackOrigins = 0;
429       } else {
430         StringRef S = A->getValue();
431         if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
432             MsanTrackOrigins > 2) {
433           D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
434         }
435       }
436     }
437     MsanUseAfterDtor =
438         Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor);
439     NeedPIE |= !(TC.getTriple().isOSLinux() &&
440                  TC.getTriple().getArch() == llvm::Triple::x86_64);
441   }
442 
443   if (AllAddedKinds & CFI) {
444     CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
445                                options::OPT_fno_sanitize_cfi_cross_dso, false);
446     // Without PIE, external function address may resolve to a PLT record, which
447     // can not be verified by the target module.
448     NeedPIE |= CfiCrossDso;
449   }
450 
451   // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
452   // enabled sanitizers.
453   if (AllAddedKinds & SupportsCoverage) {
454     for (const auto *Arg : Args) {
455       if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
456         Arg->claim();
457         int LegacySanitizeCoverage;
458         if (Arg->getNumValues() == 1 &&
459             !StringRef(Arg->getValue(0))
460                  .getAsInteger(0, LegacySanitizeCoverage) &&
461             LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) {
462           // TODO: Add deprecation notice for this form.
463           switch (LegacySanitizeCoverage) {
464           case 0:
465             CoverageFeatures = 0;
466             break;
467           case 1:
468             CoverageFeatures = CoverageFunc;
469             break;
470           case 2:
471             CoverageFeatures = CoverageBB;
472             break;
473           case 3:
474             CoverageFeatures = CoverageEdge;
475             break;
476           case 4:
477             CoverageFeatures = CoverageEdge | CoverageIndirCall;
478             break;
479           }
480           continue;
481         }
482         CoverageFeatures |= parseCoverageFeatures(D, Arg);
483       } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
484         Arg->claim();
485         CoverageFeatures &= ~parseCoverageFeatures(D, Arg);
486       }
487     }
488   }
489   // Choose at most one coverage type: function, bb, or edge.
490   if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB))
491     D.Diag(clang::diag::err_drv_argument_not_allowed_with)
492         << "-fsanitize-coverage=func"
493         << "-fsanitize-coverage=bb";
494   if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge))
495     D.Diag(clang::diag::err_drv_argument_not_allowed_with)
496         << "-fsanitize-coverage=func"
497         << "-fsanitize-coverage=edge";
498   if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
499     D.Diag(clang::diag::err_drv_argument_not_allowed_with)
500         << "-fsanitize-coverage=bb"
501         << "-fsanitize-coverage=edge";
502   // Basic block tracing and 8-bit counters require some type of coverage
503   // enabled.
504   int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge;
505   if ((CoverageFeatures & CoverageTraceBB) &&
506       !(CoverageFeatures & CoverageTypes))
507     D.Diag(clang::diag::err_drv_argument_only_allowed_with)
508         << "-fsanitize-coverage=trace-bb"
509         << "-fsanitize-coverage=(func|bb|edge)";
510   if ((CoverageFeatures & Coverage8bitCounters) &&
511       !(CoverageFeatures & CoverageTypes))
512     D.Diag(clang::diag::err_drv_argument_only_allowed_with)
513         << "-fsanitize-coverage=8bit-counters"
514         << "-fsanitize-coverage=(func|bb|edge)";
515 
516   if (AllAddedKinds & Address) {
517     AsanSharedRuntime =
518         Args.hasArg(options::OPT_shared_libasan) || TC.getTriple().isAndroid();
519     NeedPIE |= TC.getTriple().isAndroid();
520     if (Arg *A =
521             Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
522         StringRef S = A->getValue();
523         // Legal values are 0 and 1, 2, but in future we may add more levels.
524         if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
525             AsanFieldPadding > 2) {
526           D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
527         }
528     }
529 
530     if (Arg *WindowsDebugRTArg =
531             Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
532                             options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
533                             options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
534       switch (WindowsDebugRTArg->getOption().getID()) {
535       case options::OPT__SLASH_MTd:
536       case options::OPT__SLASH_MDd:
537       case options::OPT__SLASH_LDd:
538         D.Diag(clang::diag::err_drv_argument_not_allowed_with)
539             << WindowsDebugRTArg->getAsString(Args)
540             << lastArgumentForMask(D, Args, Address);
541         D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
542       }
543     }
544   }
545 
546   // Parse -link-cxx-sanitizer flag.
547   LinkCXXRuntimes =
548       Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
549 
550   // Finally, initialize the set of available and recoverable sanitizers.
551   Sanitizers.Mask |= Kinds;
552   RecoverableSanitizers.Mask |= RecoverableKinds;
553   TrapSanitizers.Mask |= TrappingKinds;
554 }
555 
toString(const clang::SanitizerSet & Sanitizers)556 static std::string toString(const clang::SanitizerSet &Sanitizers) {
557   std::string Res;
558 #define SANITIZER(NAME, ID)                                                    \
559   if (Sanitizers.has(ID)) {                                                    \
560     if (!Res.empty())                                                          \
561       Res += ",";                                                              \
562     Res += NAME;                                                               \
563   }
564 #include "clang/Basic/Sanitizers.def"
565   return Res;
566 }
567 
addArgs(const ToolChain & TC,const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs,types::ID InputType) const568 void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
569                             llvm::opt::ArgStringList &CmdArgs,
570                             types::ID InputType) const {
571   if (Sanitizers.empty())
572     return;
573   CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
574 
575   if (!RecoverableSanitizers.empty())
576     CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
577                                          toString(RecoverableSanitizers)));
578 
579   if (!TrapSanitizers.empty())
580     CmdArgs.push_back(
581         Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
582 
583   for (const auto &BLPath : BlacklistFiles) {
584     SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
585     BlacklistOpt += BLPath;
586     CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
587   }
588   for (const auto &Dep : ExtraDeps) {
589     SmallString<64> ExtraDepOpt("-fdepfile-entry=");
590     ExtraDepOpt += Dep;
591     CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
592   }
593 
594   if (MsanTrackOrigins)
595     CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
596                                          llvm::utostr(MsanTrackOrigins)));
597 
598   if (MsanUseAfterDtor)
599     CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor"));
600 
601   if (CfiCrossDso)
602     CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso"));
603 
604   if (AsanFieldPadding)
605     CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
606                                          llvm::utostr(AsanFieldPadding)));
607   // Translate available CoverageFeatures to corresponding clang-cc1 flags.
608   std::pair<int, const char *> CoverageFlags[] = {
609     std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"),
610     std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"),
611     std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"),
612     std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"),
613     std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"),
614     std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"),
615     std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters")};
616   for (auto F : CoverageFlags) {
617     if (CoverageFeatures & F.first)
618       CmdArgs.push_back(Args.MakeArgString(F.second));
619   }
620 
621 
622   // MSan: Workaround for PR16386.
623   // ASan: This is mainly to help LSan with cases such as
624   // https://code.google.com/p/address-sanitizer/issues/detail?id=373
625   // We can't make this conditional on -fsanitize=leak, as that flag shouldn't
626   // affect compilation.
627   if (Sanitizers.has(Memory) || Sanitizers.has(Address))
628     CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
629 
630   if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
631     // Instruct the code generator to embed linker directives in the object file
632     // that cause the required runtime libraries to be linked.
633     CmdArgs.push_back(Args.MakeArgString(
634         "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone")));
635     if (types::isCXX(InputType))
636       CmdArgs.push_back(Args.MakeArgString(
637           "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx")));
638   }
639 }
640 
parseArgValues(const Driver & D,const llvm::opt::Arg * A,bool DiagnoseErrors)641 SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
642                              bool DiagnoseErrors) {
643   assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
644           A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
645           A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
646           A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
647           A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
648           A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
649          "Invalid argument in parseArgValues!");
650   SanitizerMask Kinds = 0;
651   for (int i = 0, n = A->getNumValues(); i != n; ++i) {
652     const char *Value = A->getValue(i);
653     SanitizerMask Kind;
654     // Special case: don't accept -fsanitize=all.
655     if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
656         0 == strcmp("all", Value))
657       Kind = 0;
658     else
659       Kind = parseSanitizerValue(Value, /*AllowGroups=*/true);
660 
661     if (Kind)
662       Kinds |= Kind;
663     else if (DiagnoseErrors)
664       D.Diag(clang::diag::err_drv_unsupported_option_argument)
665           << A->getOption().getName() << Value;
666   }
667   return Kinds;
668 }
669 
parseCoverageFeatures(const Driver & D,const llvm::opt::Arg * A)670 int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) {
671   assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
672          A->getOption().matches(options::OPT_fno_sanitize_coverage));
673   int Features = 0;
674   for (int i = 0, n = A->getNumValues(); i != n; ++i) {
675     const char *Value = A->getValue(i);
676     int F = llvm::StringSwitch<int>(Value)
677         .Case("func", CoverageFunc)
678         .Case("bb", CoverageBB)
679         .Case("edge", CoverageEdge)
680         .Case("indirect-calls", CoverageIndirCall)
681         .Case("trace-bb", CoverageTraceBB)
682         .Case("trace-cmp", CoverageTraceCmp)
683         .Case("8bit-counters", Coverage8bitCounters)
684         .Default(0);
685     if (F == 0)
686       D.Diag(clang::diag::err_drv_unsupported_option_argument)
687           << A->getOption().getName() << Value;
688     Features |= F;
689   }
690   return Features;
691 }
692 
lastArgumentForMask(const Driver & D,const llvm::opt::ArgList & Args,SanitizerMask Mask)693 std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
694                                 SanitizerMask Mask) {
695   for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
696                                                   E = Args.rend();
697        I != E; ++I) {
698     const auto *Arg = *I;
699     if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
700       SanitizerMask AddKinds =
701           expandSanitizerGroups(parseArgValues(D, Arg, false));
702       if (AddKinds & Mask)
703         return describeSanitizeArg(Arg, Mask);
704     } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
705       SanitizerMask RemoveKinds =
706           expandSanitizerGroups(parseArgValues(D, Arg, false));
707       Mask &= ~RemoveKinds;
708     }
709   }
710   llvm_unreachable("arg list didn't provide expected value");
711 }
712 
describeSanitizeArg(const llvm::opt::Arg * A,SanitizerMask Mask)713 std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) {
714   assert(A->getOption().matches(options::OPT_fsanitize_EQ)
715          && "Invalid argument in describeSanitizerArg!");
716 
717   std::string Sanitizers;
718   for (int i = 0, n = A->getNumValues(); i != n; ++i) {
719     if (expandSanitizerGroups(
720             parseSanitizerValue(A->getValue(i), /*AllowGroups=*/true)) &
721         Mask) {
722       if (!Sanitizers.empty())
723         Sanitizers += ",";
724       Sanitizers += A->getValue(i);
725     }
726   }
727 
728   assert(!Sanitizers.empty() && "arg didn't provide expected value");
729   return "-fsanitize=" + Sanitizers;
730 }
731