1 //===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "clang/Driver/SanitizerArgs.h"
9 #include "ToolChains/CommonArgs.h"
10 #include "clang/Basic/Sanitizers.h"
11 #include "clang/Driver/Driver.h"
12 #include "clang/Driver/DriverDiagnostic.h"
13 #include "clang/Driver/Options.h"
14 #include "clang/Driver/ToolChain.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/ADT/StringSwitch.h"
17 #include "llvm/Support/AArch64TargetParser.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/SpecialCaseList.h"
20 #include "llvm/Support/TargetParser.h"
21 #include "llvm/Support/VirtualFileSystem.h"
22 #include "llvm/TargetParser/RISCVTargetParser.h"
23 #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
24 #include <memory>
25
26 using namespace clang;
27 using namespace clang::driver;
28 using namespace llvm::opt;
29
30 static const SanitizerMask NeedsUbsanRt =
31 SanitizerKind::Undefined | SanitizerKind::Integer |
32 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
33 SanitizerKind::CFI | SanitizerKind::FloatDivideByZero |
34 SanitizerKind::ObjCCast;
35 static const SanitizerMask NeedsUbsanCxxRt =
36 SanitizerKind::Vptr | SanitizerKind::CFI;
37 static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr;
38 static const SanitizerMask NotAllowedWithMinimalRuntime =
39 SanitizerKind::Function | SanitizerKind::Vptr;
40 static const SanitizerMask RequiresPIE =
41 SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo |
42 SanitizerKind::KCFI;
43 static const SanitizerMask NeedsUnwindTables =
44 SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
45 SanitizerKind::Memory | SanitizerKind::DataFlow;
46 static const SanitizerMask SupportsCoverage =
47 SanitizerKind::Address | SanitizerKind::HWAddress |
48 SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
49 SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
50 SanitizerKind::MemtagGlobals | SanitizerKind::Memory |
51 SanitizerKind::KernelMemory | SanitizerKind::Leak |
52 SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds |
53 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
54 SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
55 SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
56 SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack |
57 SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI;
58 static const SanitizerMask RecoverableByDefault =
59 SanitizerKind::Undefined | SanitizerKind::Integer |
60 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
61 SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
62 static const SanitizerMask Unrecoverable =
63 SanitizerKind::Unreachable | SanitizerKind::Return;
64 static const SanitizerMask AlwaysRecoverable = SanitizerKind::KernelAddress |
65 SanitizerKind::KernelHWAddress |
66 SanitizerKind::KCFI;
67 static const SanitizerMask NeedsLTO = SanitizerKind::CFI;
68 static const SanitizerMask TrappingSupported =
69 (SanitizerKind::Undefined & ~SanitizerKind::Vptr) | SanitizerKind::Integer |
70 SanitizerKind::Nullability | SanitizerKind::LocalBounds |
71 SanitizerKind::CFI | SanitizerKind::FloatDivideByZero |
72 SanitizerKind::ObjCCast;
73 static const SanitizerMask TrappingDefault = SanitizerKind::CFI;
74 static const SanitizerMask CFIClasses =
75 SanitizerKind::CFIVCall | SanitizerKind::CFINVCall |
76 SanitizerKind::CFIMFCall | SanitizerKind::CFIDerivedCast |
77 SanitizerKind::CFIUnrelatedCast;
78 static const SanitizerMask CompatibleWithMinimalRuntime =
79 TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack |
80 SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
81 SanitizerKind::MemtagGlobals;
82
83 enum CoverageFeature {
84 CoverageFunc = 1 << 0,
85 CoverageBB = 1 << 1,
86 CoverageEdge = 1 << 2,
87 CoverageIndirCall = 1 << 3,
88 CoverageTraceBB = 1 << 4, // Deprecated.
89 CoverageTraceCmp = 1 << 5,
90 CoverageTraceDiv = 1 << 6,
91 CoverageTraceGep = 1 << 7,
92 Coverage8bitCounters = 1 << 8, // Deprecated.
93 CoverageTracePC = 1 << 9,
94 CoverageTracePCGuard = 1 << 10,
95 CoverageNoPrune = 1 << 11,
96 CoverageInline8bitCounters = 1 << 12,
97 CoveragePCTable = 1 << 13,
98 CoverageStackDepth = 1 << 14,
99 CoverageInlineBoolFlag = 1 << 15,
100 CoverageTraceLoads = 1 << 16,
101 CoverageTraceStores = 1 << 17,
102 CoverageControlFlow = 1 << 18,
103 };
104
105 enum BinaryMetadataFeature {
106 BinaryMetadataCovered = 1 << 0,
107 BinaryMetadataAtomics = 1 << 1,
108 BinaryMetadataUAR = 1 << 2,
109 };
110
111 /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
112 /// invalid components. Returns a SanitizerMask.
113 static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
114 bool DiagnoseErrors);
115
116 /// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
117 /// components. Returns OR of members of \c CoverageFeature enumeration.
118 static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
119 bool DiagnoseErrors);
120
121 /// Parse -f(no-)?sanitize-metadata= flag values, diagnosing any invalid
122 /// components. Returns OR of members of \c BinaryMetadataFeature enumeration.
123 static int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
124 bool DiagnoseErrors);
125
126 /// Produce an argument string from ArgList \p Args, which shows how it
127 /// provides some sanitizer kind from \p Mask. For example, the argument list
128 /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
129 /// would produce "-fsanitize=vptr".
130 static std::string lastArgumentForMask(const Driver &D,
131 const llvm::opt::ArgList &Args,
132 SanitizerMask Mask);
133
134 /// Produce an argument string from argument \p A, which shows how it provides
135 /// a value in \p Mask. For instance, the argument
136 /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
137 /// "-fsanitize=alignment".
138 static std::string describeSanitizeArg(const llvm::opt::Arg *A,
139 SanitizerMask Mask);
140
141 /// Produce a string containing comma-separated names of sanitizers in \p
142 /// Sanitizers set.
143 static std::string toString(const clang::SanitizerSet &Sanitizers);
144
validateSpecialCaseListFormat(const Driver & D,std::vector<std::string> & SCLFiles,unsigned MalformedSCLErrorDiagID,bool DiagnoseErrors)145 static void validateSpecialCaseListFormat(const Driver &D,
146 std::vector<std::string> &SCLFiles,
147 unsigned MalformedSCLErrorDiagID,
148 bool DiagnoseErrors) {
149 if (SCLFiles.empty())
150 return;
151
152 std::string BLError;
153 std::unique_ptr<llvm::SpecialCaseList> SCL(
154 llvm::SpecialCaseList::create(SCLFiles, D.getVFS(), BLError));
155 if (!SCL.get() && DiagnoseErrors)
156 D.Diag(MalformedSCLErrorDiagID) << BLError;
157 }
158
addDefaultIgnorelists(const Driver & D,SanitizerMask Kinds,std::vector<std::string> & IgnorelistFiles,bool DiagnoseErrors)159 static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
160 std::vector<std::string> &IgnorelistFiles,
161 bool DiagnoseErrors) {
162 struct Ignorelist {
163 const char *File;
164 SanitizerMask Mask;
165 } Ignorelists[] = {{"asan_ignorelist.txt", SanitizerKind::Address},
166 {"hwasan_ignorelist.txt", SanitizerKind::HWAddress},
167 {"memtag_ignorelist.txt", SanitizerKind::MemTag},
168 {"msan_ignorelist.txt", SanitizerKind::Memory},
169 {"tsan_ignorelist.txt", SanitizerKind::Thread},
170 {"dfsan_abilist.txt", SanitizerKind::DataFlow},
171 {"cfi_ignorelist.txt", SanitizerKind::CFI},
172 {"ubsan_ignorelist.txt",
173 SanitizerKind::Undefined | SanitizerKind::Integer |
174 SanitizerKind::Nullability |
175 SanitizerKind::FloatDivideByZero}};
176
177 for (auto BL : Ignorelists) {
178 if (!(Kinds & BL.Mask))
179 continue;
180
181 clang::SmallString<64> Path(D.ResourceDir);
182 llvm::sys::path::append(Path, "share", BL.File);
183 if (D.getVFS().exists(Path))
184 IgnorelistFiles.push_back(std::string(Path.str()));
185 else if (BL.Mask == SanitizerKind::CFI && DiagnoseErrors)
186 // If cfi_ignorelist.txt cannot be found in the resource dir, driver
187 // should fail.
188 D.Diag(clang::diag::err_drv_missing_sanitizer_ignorelist) << Path;
189 }
190 validateSpecialCaseListFormat(
191 D, IgnorelistFiles, clang::diag::err_drv_malformed_sanitizer_ignorelist,
192 DiagnoseErrors);
193 }
194
195 /// Parse -f(no-)?sanitize-(coverage-)?(allow|ignore)list argument's values,
196 /// diagnosing any invalid file paths and validating special case list format.
parseSpecialCaseListArg(const Driver & D,const llvm::opt::ArgList & Args,std::vector<std::string> & SCLFiles,llvm::opt::OptSpecifier SCLOptionID,llvm::opt::OptSpecifier NoSCLOptionID,unsigned MalformedSCLErrorDiagID,bool DiagnoseErrors)197 static void parseSpecialCaseListArg(const Driver &D,
198 const llvm::opt::ArgList &Args,
199 std::vector<std::string> &SCLFiles,
200 llvm::opt::OptSpecifier SCLOptionID,
201 llvm::opt::OptSpecifier NoSCLOptionID,
202 unsigned MalformedSCLErrorDiagID,
203 bool DiagnoseErrors) {
204 for (const auto *Arg : Args) {
205 // Match -fsanitize-(coverage-)?(allow|ignore)list.
206 if (Arg->getOption().matches(SCLOptionID)) {
207 Arg->claim();
208 std::string SCLPath = Arg->getValue();
209 if (D.getVFS().exists(SCLPath)) {
210 SCLFiles.push_back(SCLPath);
211 } else if (DiagnoseErrors) {
212 D.Diag(clang::diag::err_drv_no_such_file) << SCLPath;
213 }
214 // Match -fno-sanitize-ignorelist.
215 } else if (Arg->getOption().matches(NoSCLOptionID)) {
216 Arg->claim();
217 SCLFiles.clear();
218 }
219 }
220 validateSpecialCaseListFormat(D, SCLFiles, MalformedSCLErrorDiagID,
221 DiagnoseErrors);
222 }
223
224 /// Sets group bits for every group that has at least one representative already
225 /// enabled in \p Kinds.
setGroupBits(SanitizerMask Kinds)226 static SanitizerMask setGroupBits(SanitizerMask Kinds) {
227 #define SANITIZER(NAME, ID)
228 #define SANITIZER_GROUP(NAME, ID, ALIAS) \
229 if (Kinds & SanitizerKind::ID) \
230 Kinds |= SanitizerKind::ID##Group;
231 #include "clang/Basic/Sanitizers.def"
232 return Kinds;
233 }
234
parseSanitizeTrapArgs(const Driver & D,const llvm::opt::ArgList & Args,bool DiagnoseErrors)235 static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
236 const llvm::opt::ArgList &Args,
237 bool DiagnoseErrors) {
238 SanitizerMask TrapRemove; // During the loop below, the accumulated set of
239 // sanitizers disabled by the current sanitizer
240 // argument or any argument after it.
241 SanitizerMask TrappingKinds;
242 SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported);
243
244 for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
245 if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
246 Arg->claim();
247 SanitizerMask Add = parseArgValues(D, Arg, true);
248 Add &= ~TrapRemove;
249 SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups;
250 if (InvalidValues && DiagnoseErrors) {
251 SanitizerSet S;
252 S.Mask = InvalidValues;
253 D.Diag(diag::err_drv_unsupported_option_argument)
254 << Arg->getSpelling() << toString(S);
255 }
256 TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove;
257 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
258 Arg->claim();
259 TrapRemove |=
260 expandSanitizerGroups(parseArgValues(D, Arg, DiagnoseErrors));
261 }
262 }
263
264 // Apply default trapping behavior.
265 TrappingKinds |= TrappingDefault & ~TrapRemove;
266
267 return TrappingKinds;
268 }
269
needsFuzzerInterceptors() const270 bool SanitizerArgs::needsFuzzerInterceptors() const {
271 return needsFuzzer() && !needsAsanRt() && !needsTsanRt() && !needsMsanRt();
272 }
273
needsUbsanRt() const274 bool SanitizerArgs::needsUbsanRt() const {
275 // All of these include ubsan.
276 if (needsAsanRt() || needsMsanRt() || needsHwasanRt() || needsTsanRt() ||
277 needsDfsanRt() || needsLsanRt() || needsCfiDiagRt() ||
278 (needsScudoRt() && !requiresMinimalRuntime()))
279 return false;
280
281 return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) ||
282 CoverageFeatures;
283 }
284
needsCfiRt() const285 bool SanitizerArgs::needsCfiRt() const {
286 return !(Sanitizers.Mask & SanitizerKind::CFI & ~TrapSanitizers.Mask) &&
287 CfiCrossDso && !ImplicitCfiRuntime;
288 }
289
needsCfiDiagRt() const290 bool SanitizerArgs::needsCfiDiagRt() const {
291 return (Sanitizers.Mask & SanitizerKind::CFI & ~TrapSanitizers.Mask) &&
292 CfiCrossDso && !ImplicitCfiRuntime;
293 }
294
requiresPIE() const295 bool SanitizerArgs::requiresPIE() const {
296 return NeedPIE || (Sanitizers.Mask & RequiresPIE);
297 }
298
needsUnwindTables() const299 bool SanitizerArgs::needsUnwindTables() const {
300 return static_cast<bool>(Sanitizers.Mask & NeedsUnwindTables);
301 }
302
needsLTO() const303 bool SanitizerArgs::needsLTO() const {
304 return static_cast<bool>(Sanitizers.Mask & NeedsLTO);
305 }
306
SanitizerArgs(const ToolChain & TC,const llvm::opt::ArgList & Args,bool DiagnoseErrors)307 SanitizerArgs::SanitizerArgs(const ToolChain &TC,
308 const llvm::opt::ArgList &Args,
309 bool DiagnoseErrors) {
310 SanitizerMask AllRemove; // During the loop below, the accumulated set of
311 // sanitizers disabled by the current sanitizer
312 // argument or any argument after it.
313 SanitizerMask AllAddedKinds; // Mask of all sanitizers ever enabled by
314 // -fsanitize= flags (directly or via group
315 // expansion), some of which may be disabled
316 // later. Used to carefully prune
317 // unused-argument diagnostics.
318 SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now.
319 // Used to deduplicate diagnostics.
320 SanitizerMask Kinds;
321 const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
322
323 CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
324 options::OPT_fno_sanitize_cfi_cross_dso, false);
325
326 ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
327
328 const Driver &D = TC.getDriver();
329 SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args, DiagnoseErrors);
330 SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
331
332 MinimalRuntime =
333 Args.hasFlag(options::OPT_fsanitize_minimal_runtime,
334 options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime);
335
336 // The object size sanitizer should not be enabled at -O0.
337 Arg *OptLevel = Args.getLastArg(options::OPT_O_Group);
338 bool RemoveObjectSizeAtO0 =
339 !OptLevel || OptLevel->getOption().matches(options::OPT_O0);
340
341 for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
342 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
343 Arg->claim();
344 SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
345
346 if (RemoveObjectSizeAtO0) {
347 AllRemove |= SanitizerKind::ObjectSize;
348
349 // The user explicitly enabled the object size sanitizer. Warn
350 // that this does nothing at -O0.
351 if ((Add & SanitizerKind::ObjectSize) && DiagnoseErrors)
352 D.Diag(diag::warn_drv_object_size_disabled_O0)
353 << Arg->getAsString(Args);
354 }
355
356 AllAddedKinds |= expandSanitizerGroups(Add);
357
358 // Avoid diagnosing any sanitizer which is disabled later.
359 Add &= ~AllRemove;
360 // At this point we have not expanded groups, so any unsupported
361 // sanitizers in Add are those which have been explicitly enabled.
362 // Diagnose them.
363 if (SanitizerMask KindsToDiagnose =
364 Add & InvalidTrappingKinds & ~DiagnosedKinds) {
365 if (DiagnoseErrors) {
366 std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose);
367 D.Diag(diag::err_drv_argument_not_allowed_with)
368 << Desc << "-fsanitize-trap=undefined";
369 }
370 DiagnosedKinds |= KindsToDiagnose;
371 }
372 Add &= ~InvalidTrappingKinds;
373
374 if (MinimalRuntime) {
375 if (SanitizerMask KindsToDiagnose =
376 Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) {
377 if (DiagnoseErrors) {
378 std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose);
379 D.Diag(diag::err_drv_argument_not_allowed_with)
380 << Desc << "-fsanitize-minimal-runtime";
381 }
382 DiagnosedKinds |= KindsToDiagnose;
383 }
384 Add &= ~NotAllowedWithMinimalRuntime;
385 }
386
387 if (llvm::opt::Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
388 StringRef CM = A->getValue();
389 if (CM != "small" &&
390 (Add & SanitizerKind::Function & ~DiagnosedKinds)) {
391 if (DiagnoseErrors)
392 D.Diag(diag::err_drv_argument_only_allowed_with)
393 << "-fsanitize=function"
394 << "-mcmodel=small";
395 Add &= ~SanitizerKind::Function;
396 DiagnosedKinds |= SanitizerKind::Function;
397 }
398 }
399
400 // FIXME: Make CFI on member function calls compatible with cross-DSO CFI.
401 // There are currently two problems:
402 // - Virtual function call checks need to pass a pointer to the function
403 // address to llvm.type.test and a pointer to the address point to the
404 // diagnostic function. Currently we pass the same pointer to both
405 // places.
406 // - Non-virtual function call checks may need to check multiple type
407 // identifiers.
408 // Fixing both of those may require changes to the cross-DSO CFI
409 // interface.
410 if (CfiCrossDso && (Add & SanitizerKind::CFIMFCall & ~DiagnosedKinds)) {
411 if (DiagnoseErrors)
412 D.Diag(diag::err_drv_argument_not_allowed_with)
413 << "-fsanitize=cfi-mfcall"
414 << "-fsanitize-cfi-cross-dso";
415 Add &= ~SanitizerKind::CFIMFCall;
416 DiagnosedKinds |= SanitizerKind::CFIMFCall;
417 }
418
419 if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
420 if (DiagnoseErrors) {
421 std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose);
422 D.Diag(diag::err_drv_unsupported_opt_for_target)
423 << Desc << TC.getTriple().str();
424 }
425 DiagnosedKinds |= KindsToDiagnose;
426 }
427 Add &= Supported;
428
429 // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups
430 // so we don't error out if -fno-rtti and -fsanitize=undefined were
431 // passed.
432 if ((Add & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) {
433 if (const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg()) {
434 assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) &&
435 "RTTI disabled without -fno-rtti option?");
436 // The user explicitly passed -fno-rtti with -fsanitize=vptr, but
437 // the vptr sanitizer requires RTTI, so this is a user error.
438 if (DiagnoseErrors)
439 D.Diag(diag::err_drv_argument_not_allowed_with)
440 << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
441 } else {
442 // The vptr sanitizer requires RTTI, but RTTI is disabled (by
443 // default). Warn that the vptr sanitizer is being disabled.
444 if (DiagnoseErrors)
445 D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
446 }
447
448 // Take out the Vptr sanitizer from the enabled sanitizers
449 AllRemove |= SanitizerKind::Vptr;
450 }
451
452 Add = expandSanitizerGroups(Add);
453 // Group expansion may have enabled a sanitizer which is disabled later.
454 Add &= ~AllRemove;
455 // Silently discard any unsupported sanitizers implicitly enabled through
456 // group expansion.
457 Add &= ~InvalidTrappingKinds;
458 if (MinimalRuntime) {
459 Add &= ~NotAllowedWithMinimalRuntime;
460 }
461 if (CfiCrossDso)
462 Add &= ~SanitizerKind::CFIMFCall;
463 Add &= Supported;
464
465 if (Add & SanitizerKind::Fuzzer)
466 Add |= SanitizerKind::FuzzerNoLink;
467
468 // Enable coverage if the fuzzing flag is set.
469 if (Add & SanitizerKind::FuzzerNoLink) {
470 CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall |
471 CoverageTraceCmp | CoveragePCTable;
472 // Due to TLS differences, stack depth tracking is only enabled on Linux
473 if (TC.getTriple().isOSLinux())
474 CoverageFeatures |= CoverageStackDepth;
475 }
476
477 Kinds |= Add;
478 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
479 Arg->claim();
480 SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
481 AllRemove |= expandSanitizerGroups(Remove);
482 }
483 }
484
485 std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
486 std::make_pair(SanitizerKind::Address,
487 SanitizerKind::Thread | SanitizerKind::Memory),
488 std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory),
489 std::make_pair(SanitizerKind::Leak,
490 SanitizerKind::Thread | SanitizerKind::Memory),
491 std::make_pair(SanitizerKind::KernelAddress,
492 SanitizerKind::Address | SanitizerKind::Leak |
493 SanitizerKind::Thread | SanitizerKind::Memory),
494 std::make_pair(SanitizerKind::HWAddress,
495 SanitizerKind::Address | SanitizerKind::Thread |
496 SanitizerKind::Memory | SanitizerKind::KernelAddress),
497 std::make_pair(SanitizerKind::Scudo,
498 SanitizerKind::Address | SanitizerKind::HWAddress |
499 SanitizerKind::Leak | SanitizerKind::Thread |
500 SanitizerKind::Memory | SanitizerKind::KernelAddress),
501 std::make_pair(SanitizerKind::SafeStack,
502 (TC.getTriple().isOSFuchsia() ? SanitizerMask()
503 : SanitizerKind::Leak) |
504 SanitizerKind::Address | SanitizerKind::HWAddress |
505 SanitizerKind::Thread | SanitizerKind::Memory |
506 SanitizerKind::KernelAddress),
507 std::make_pair(SanitizerKind::KernelHWAddress,
508 SanitizerKind::Address | SanitizerKind::HWAddress |
509 SanitizerKind::Leak | SanitizerKind::Thread |
510 SanitizerKind::Memory | SanitizerKind::KernelAddress |
511 SanitizerKind::SafeStack),
512 std::make_pair(SanitizerKind::KernelMemory,
513 SanitizerKind::Address | SanitizerKind::HWAddress |
514 SanitizerKind::Leak | SanitizerKind::Thread |
515 SanitizerKind::Memory | SanitizerKind::KernelAddress |
516 SanitizerKind::Scudo | SanitizerKind::SafeStack),
517 std::make_pair(SanitizerKind::MemTag,
518 SanitizerKind::Address | SanitizerKind::KernelAddress |
519 SanitizerKind::HWAddress |
520 SanitizerKind::KernelHWAddress)};
521 // Enable toolchain specific default sanitizers if not explicitly disabled.
522 SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
523
524 // Disable default sanitizers that are incompatible with explicitly requested
525 // ones.
526 for (auto G : IncompatibleGroups) {
527 SanitizerMask Group = G.first;
528 if ((Default & Group) && (Kinds & G.second))
529 Default &= ~Group;
530 }
531
532 Kinds |= Default;
533
534 // We disable the vptr sanitizer if it was enabled by group expansion but RTTI
535 // is disabled.
536 if ((Kinds & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) {
537 Kinds &= ~SanitizerKind::Vptr;
538 }
539
540 // Check that LTO is enabled if we need it.
541 if ((Kinds & NeedsLTO) && !D.isUsingLTO() && DiagnoseErrors) {
542 D.Diag(diag::err_drv_argument_only_allowed_with)
543 << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
544 }
545
546 if ((Kinds & SanitizerKind::ShadowCallStack) &&
547 ((TC.getTriple().isAArch64() &&
548 !llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) ||
549 (TC.getTriple().isRISCV() &&
550 !llvm::RISCV::isX18ReservedByDefault(TC.getTriple()))) &&
551 !Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) {
552 D.Diag(diag::err_drv_argument_only_allowed_with)
553 << lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack)
554 << "-ffixed-x18";
555 }
556
557 // Report error if there are non-trapping sanitizers that require
558 // c++abi-specific parts of UBSan runtime, and they are not provided by the
559 // toolchain. We don't have a good way to check the latter, so we just
560 // check if the toolchan supports vptr.
561 if (~Supported & SanitizerKind::Vptr) {
562 SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt;
563 // The runtime library supports the Microsoft C++ ABI, but only well enough
564 // for CFI. FIXME: Remove this once we support vptr on Windows.
565 if (TC.getTriple().isOSWindows())
566 KindsToDiagnose &= ~SanitizerKind::CFI;
567 if (KindsToDiagnose) {
568 SanitizerSet S;
569 S.Mask = KindsToDiagnose;
570 if (DiagnoseErrors)
571 D.Diag(diag::err_drv_unsupported_opt_for_target)
572 << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str();
573 Kinds &= ~KindsToDiagnose;
574 }
575 }
576
577 // Warn about incompatible groups of sanitizers.
578 for (auto G : IncompatibleGroups) {
579 SanitizerMask Group = G.first;
580 if (Kinds & Group) {
581 if (SanitizerMask Incompatible = Kinds & G.second) {
582 if (DiagnoseErrors)
583 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
584 << lastArgumentForMask(D, Args, Group)
585 << lastArgumentForMask(D, Args, Incompatible);
586 Kinds &= ~Incompatible;
587 }
588 }
589 }
590 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
591 // -fsanitize=address. Perhaps it should print an error, or perhaps
592 // -f(-no)sanitize=leak should change whether leak detection is enabled by
593 // default in ASan?
594
595 // Parse -f(no-)?sanitize-recover flags.
596 SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable;
597 SanitizerMask DiagnosedUnrecoverableKinds;
598 SanitizerMask DiagnosedAlwaysRecoverableKinds;
599 for (const auto *Arg : Args) {
600 if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
601 SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
602 // Report error if user explicitly tries to recover from unrecoverable
603 // sanitizer.
604 if (SanitizerMask KindsToDiagnose =
605 Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
606 SanitizerSet SetToDiagnose;
607 SetToDiagnose.Mask |= KindsToDiagnose;
608 if (DiagnoseErrors)
609 D.Diag(diag::err_drv_unsupported_option_argument)
610 << Arg->getSpelling() << toString(SetToDiagnose);
611 DiagnosedUnrecoverableKinds |= KindsToDiagnose;
612 }
613 RecoverableKinds |= expandSanitizerGroups(Add);
614 Arg->claim();
615 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
616 SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
617 // Report error if user explicitly tries to disable recovery from
618 // always recoverable sanitizer.
619 if (SanitizerMask KindsToDiagnose =
620 Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) {
621 SanitizerSet SetToDiagnose;
622 SetToDiagnose.Mask |= KindsToDiagnose;
623 if (DiagnoseErrors)
624 D.Diag(diag::err_drv_unsupported_option_argument)
625 << Arg->getSpelling() << toString(SetToDiagnose);
626 DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
627 }
628 RecoverableKinds &= ~expandSanitizerGroups(Remove);
629 Arg->claim();
630 }
631 }
632 RecoverableKinds &= Kinds;
633 RecoverableKinds &= ~Unrecoverable;
634
635 TrappingKinds &= Kinds;
636 RecoverableKinds &= ~TrappingKinds;
637
638 // Setup ignorelist files.
639 // Add default ignorelist from resource directory for activated sanitizers,
640 // and validate special case lists format.
641 if (!Args.hasArgNoClaim(options::OPT_fno_sanitize_ignorelist))
642 addDefaultIgnorelists(D, Kinds, SystemIgnorelistFiles, DiagnoseErrors);
643
644 // Parse -f(no-)?sanitize-ignorelist options.
645 // This also validates special case lists format.
646 parseSpecialCaseListArg(
647 D, Args, UserIgnorelistFiles, options::OPT_fsanitize_ignorelist_EQ,
648 options::OPT_fno_sanitize_ignorelist,
649 clang::diag::err_drv_malformed_sanitizer_ignorelist, DiagnoseErrors);
650
651 // Parse -f[no-]sanitize-memory-track-origins[=level] options.
652 if (AllAddedKinds & SanitizerKind::Memory) {
653 if (Arg *A =
654 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
655 options::OPT_fno_sanitize_memory_track_origins)) {
656 if (!A->getOption().matches(
657 options::OPT_fno_sanitize_memory_track_origins)) {
658 StringRef S = A->getValue();
659 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
660 MsanTrackOrigins > 2) {
661 if (DiagnoseErrors)
662 D.Diag(clang::diag::err_drv_invalid_value)
663 << A->getAsString(Args) << S;
664 }
665 }
666 }
667 MsanUseAfterDtor = Args.hasFlag(
668 options::OPT_fsanitize_memory_use_after_dtor,
669 options::OPT_fno_sanitize_memory_use_after_dtor, MsanUseAfterDtor);
670 MsanParamRetval = Args.hasFlag(
671 options::OPT_fsanitize_memory_param_retval,
672 options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
673 NeedPIE |= !(TC.getTriple().isOSLinux() &&
674 TC.getTriple().getArch() == llvm::Triple::x86_64);
675 } else if (AllAddedKinds & SanitizerKind::KernelMemory) {
676 MsanUseAfterDtor = false;
677 MsanParamRetval = Args.hasFlag(
678 options::OPT_fsanitize_memory_param_retval,
679 options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
680 } else {
681 MsanUseAfterDtor = false;
682 MsanParamRetval = false;
683 }
684
685 if (AllAddedKinds & SanitizerKind::MemTag) {
686 StringRef S =
687 Args.getLastArgValue(options::OPT_fsanitize_memtag_mode_EQ, "sync");
688 if (S == "async" || S == "sync") {
689 MemtagMode = S.str();
690 } else {
691 D.Diag(clang::diag::err_drv_invalid_value_with_suggestion)
692 << "-fsanitize-memtag-mode=" << S << "{async, sync}";
693 MemtagMode = "sync";
694 }
695 }
696
697 if (AllAddedKinds & SanitizerKind::Thread) {
698 TsanMemoryAccess = Args.hasFlag(
699 options::OPT_fsanitize_thread_memory_access,
700 options::OPT_fno_sanitize_thread_memory_access, TsanMemoryAccess);
701 TsanFuncEntryExit = Args.hasFlag(
702 options::OPT_fsanitize_thread_func_entry_exit,
703 options::OPT_fno_sanitize_thread_func_entry_exit, TsanFuncEntryExit);
704 TsanAtomics =
705 Args.hasFlag(options::OPT_fsanitize_thread_atomics,
706 options::OPT_fno_sanitize_thread_atomics, TsanAtomics);
707 }
708
709 if (AllAddedKinds & SanitizerKind::CFI) {
710 // Without PIE, external function address may resolve to a PLT record, which
711 // can not be verified by the target module.
712 NeedPIE |= CfiCrossDso;
713 CfiICallGeneralizePointers =
714 Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
715
716 if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors)
717 D.Diag(diag::err_drv_argument_not_allowed_with)
718 << "-fsanitize-cfi-cross-dso"
719 << "-fsanitize-cfi-icall-generalize-pointers";
720
721 CfiCanonicalJumpTables =
722 Args.hasFlag(options::OPT_fsanitize_cfi_canonical_jump_tables,
723 options::OPT_fno_sanitize_cfi_canonical_jump_tables, true);
724 }
725
726 if (AllAddedKinds & SanitizerKind::KCFI && DiagnoseErrors) {
727 if (AllAddedKinds & SanitizerKind::CFI)
728 D.Diag(diag::err_drv_argument_not_allowed_with)
729 << "-fsanitize=kcfi"
730 << lastArgumentForMask(D, Args, SanitizerKind::CFI);
731 }
732
733 Stats = Args.hasFlag(options::OPT_fsanitize_stats,
734 options::OPT_fno_sanitize_stats, false);
735
736 if (MinimalRuntime) {
737 SanitizerMask IncompatibleMask =
738 Kinds & ~setGroupBits(CompatibleWithMinimalRuntime);
739 if (IncompatibleMask && DiagnoseErrors)
740 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
741 << "-fsanitize-minimal-runtime"
742 << lastArgumentForMask(D, Args, IncompatibleMask);
743
744 SanitizerMask NonTrappingCfi = Kinds & SanitizerKind::CFI & ~TrappingKinds;
745 if (NonTrappingCfi && DiagnoseErrors)
746 D.Diag(clang::diag::err_drv_argument_only_allowed_with)
747 << "fsanitize-minimal-runtime"
748 << "fsanitize-trap=cfi";
749 }
750
751 // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
752 // enabled sanitizers.
753 for (const auto *Arg : Args) {
754 if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
755 int LegacySanitizeCoverage;
756 if (Arg->getNumValues() == 1 &&
757 !StringRef(Arg->getValue(0))
758 .getAsInteger(0, LegacySanitizeCoverage)) {
759 CoverageFeatures = 0;
760 Arg->claim();
761 if (LegacySanitizeCoverage != 0 && DiagnoseErrors) {
762 D.Diag(diag::warn_drv_deprecated_arg)
763 << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard";
764 }
765 continue;
766 }
767 CoverageFeatures |= parseCoverageFeatures(D, Arg, DiagnoseErrors);
768
769 // Disable coverage and not claim the flags if there is at least one
770 // non-supporting sanitizer.
771 if (!(AllAddedKinds & ~AllRemove & ~setGroupBits(SupportsCoverage))) {
772 Arg->claim();
773 } else {
774 CoverageFeatures = 0;
775 }
776 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
777 Arg->claim();
778 CoverageFeatures &= ~parseCoverageFeatures(D, Arg, DiagnoseErrors);
779 }
780 }
781 // Choose at most one coverage type: function, bb, or edge.
782 if (DiagnoseErrors) {
783 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB))
784 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
785 << "-fsanitize-coverage=func"
786 << "-fsanitize-coverage=bb";
787 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge))
788 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
789 << "-fsanitize-coverage=func"
790 << "-fsanitize-coverage=edge";
791 if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
792 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
793 << "-fsanitize-coverage=bb"
794 << "-fsanitize-coverage=edge";
795 // Basic block tracing and 8-bit counters require some type of coverage
796 // enabled.
797 if (CoverageFeatures & CoverageTraceBB)
798 D.Diag(clang::diag::warn_drv_deprecated_arg)
799 << "-fsanitize-coverage=trace-bb"
800 << "-fsanitize-coverage=trace-pc-guard";
801 if (CoverageFeatures & Coverage8bitCounters)
802 D.Diag(clang::diag::warn_drv_deprecated_arg)
803 << "-fsanitize-coverage=8bit-counters"
804 << "-fsanitize-coverage=trace-pc-guard";
805 }
806
807 int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
808 int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard |
809 CoverageInline8bitCounters | CoverageTraceLoads |
810 CoverageTraceStores | CoverageInlineBoolFlag |
811 CoverageControlFlow;
812 if ((CoverageFeatures & InsertionPointTypes) &&
813 !(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) {
814 D.Diag(clang::diag::warn_drv_deprecated_arg)
815 << "-fsanitize-coverage=[func|bb|edge]"
816 << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],["
817 "control-flow]";
818 }
819
820 // trace-pc w/o func/bb/edge implies edge.
821 if (!(CoverageFeatures & InsertionPointTypes)) {
822 if (CoverageFeatures &
823 (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters |
824 CoverageInlineBoolFlag | CoverageControlFlow))
825 CoverageFeatures |= CoverageEdge;
826
827 if (CoverageFeatures & CoverageStackDepth)
828 CoverageFeatures |= CoverageFunc;
829 }
830
831 // Parse -fsanitize-coverage-(allow|ignore)list options if coverage enabled.
832 // This also validates special case lists format.
833 // Here, OptSpecifier() acts as a never-matching command-line argument.
834 // So, there is no way to clear coverage lists but you can append to them.
835 if (CoverageFeatures) {
836 parseSpecialCaseListArg(
837 D, Args, CoverageAllowlistFiles,
838 options::OPT_fsanitize_coverage_allowlist, OptSpecifier(),
839 clang::diag::err_drv_malformed_sanitizer_coverage_allowlist,
840 DiagnoseErrors);
841 parseSpecialCaseListArg(
842 D, Args, CoverageIgnorelistFiles,
843 options::OPT_fsanitize_coverage_ignorelist, OptSpecifier(),
844 clang::diag::err_drv_malformed_sanitizer_coverage_ignorelist,
845 DiagnoseErrors);
846 }
847
848 // Parse -f(no-)?sanitize-metadata.
849 for (const auto *Arg :
850 Args.filtered(options::OPT_fexperimental_sanitize_metadata_EQ,
851 options::OPT_fno_experimental_sanitize_metadata_EQ)) {
852 if (Arg->getOption().matches(
853 options::OPT_fexperimental_sanitize_metadata_EQ)) {
854 Arg->claim();
855 BinaryMetadataFeatures |=
856 parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
857 } else {
858 Arg->claim();
859 BinaryMetadataFeatures &=
860 ~parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
861 }
862 }
863
864 SharedRuntime =
865 Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan,
866 TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() ||
867 TC.getTriple().isOSDarwin());
868
869 ImplicitCfiRuntime = TC.getTriple().isAndroid();
870
871 if (AllAddedKinds & SanitizerKind::Address) {
872 NeedPIE |= TC.getTriple().isOSFuchsia();
873 if (Arg *A =
874 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
875 StringRef S = A->getValue();
876 // Legal values are 0 and 1, 2, but in future we may add more levels.
877 if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
878 AsanFieldPadding > 2) &&
879 DiagnoseErrors) {
880 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
881 }
882 }
883
884 if (Arg *WindowsDebugRTArg =
885 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
886 options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
887 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
888 switch (WindowsDebugRTArg->getOption().getID()) {
889 case options::OPT__SLASH_MTd:
890 case options::OPT__SLASH_MDd:
891 case options::OPT__SLASH_LDd:
892 if (DiagnoseErrors) {
893 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
894 << WindowsDebugRTArg->getAsString(Args)
895 << lastArgumentForMask(D, Args, SanitizerKind::Address);
896 D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
897 }
898 }
899 }
900
901 AsanUseAfterScope = Args.hasFlag(
902 options::OPT_fsanitize_address_use_after_scope,
903 options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
904
905 AsanPoisonCustomArrayCookie = Args.hasFlag(
906 options::OPT_fsanitize_address_poison_custom_array_cookie,
907 options::OPT_fno_sanitize_address_poison_custom_array_cookie,
908 AsanPoisonCustomArrayCookie);
909
910 AsanOutlineInstrumentation =
911 Args.hasFlag(options::OPT_fsanitize_address_outline_instrumentation,
912 options::OPT_fno_sanitize_address_outline_instrumentation,
913 AsanOutlineInstrumentation);
914
915 // As a workaround for a bug in gold 2.26 and earlier, dead stripping of
916 // globals in ASan is disabled by default on most ELF targets.
917 // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002
918 AsanGlobalsDeadStripping = Args.hasFlag(
919 options::OPT_fsanitize_address_globals_dead_stripping,
920 options::OPT_fno_sanitize_address_globals_dead_stripping,
921 !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() ||
922 TC.getTriple().isPS());
923
924 // Enable ODR indicators which allow better handling of mixed instrumented
925 // and uninstrumented globals. Disable them for Windows where weak odr
926 // indicators (.weak.__odr_asan_gen*) may cause multiple definition linker
927 // errors in the absence of -lldmingw.
928 AsanUseOdrIndicator =
929 Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator,
930 options::OPT_fno_sanitize_address_use_odr_indicator,
931 !TC.getTriple().isOSWindows());
932
933 if (AllAddedKinds & SanitizerKind::PointerCompare & ~AllRemove) {
934 AsanInvalidPointerCmp = true;
935 }
936
937 if (AllAddedKinds & SanitizerKind::PointerSubtract & ~AllRemove) {
938 AsanInvalidPointerSub = true;
939 }
940
941 if (TC.getTriple().isOSDarwin() &&
942 (Args.hasArg(options::OPT_mkernel) ||
943 Args.hasArg(options::OPT_fapple_kext))) {
944 AsanDtorKind = llvm::AsanDtorKind::None;
945 }
946
947 if (const auto *Arg =
948 Args.getLastArg(options::OPT_sanitize_address_destructor_EQ)) {
949 auto parsedAsanDtorKind = AsanDtorKindFromString(Arg->getValue());
950 if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid && DiagnoseErrors) {
951 TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
952 << Arg->getSpelling() << Arg->getValue();
953 }
954 AsanDtorKind = parsedAsanDtorKind;
955 }
956
957 if (const auto *Arg = Args.getLastArg(
958 options::OPT_sanitize_address_use_after_return_EQ)) {
959 auto parsedAsanUseAfterReturn =
960 AsanDetectStackUseAfterReturnModeFromString(Arg->getValue());
961 if (parsedAsanUseAfterReturn ==
962 llvm::AsanDetectStackUseAfterReturnMode::Invalid &&
963 DiagnoseErrors) {
964 TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
965 << Arg->getSpelling() << Arg->getValue();
966 }
967 AsanUseAfterReturn = parsedAsanUseAfterReturn;
968 }
969
970 } else {
971 AsanUseAfterScope = false;
972 // -fsanitize=pointer-compare/pointer-subtract requires -fsanitize=address.
973 SanitizerMask DetectInvalidPointerPairs =
974 SanitizerKind::PointerCompare | SanitizerKind::PointerSubtract;
975 if ((AllAddedKinds & DetectInvalidPointerPairs & ~AllRemove) &&
976 DiagnoseErrors) {
977 TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with)
978 << lastArgumentForMask(D, Args,
979 SanitizerKind::PointerCompare |
980 SanitizerKind::PointerSubtract)
981 << "-fsanitize=address";
982 }
983 }
984
985 if (AllAddedKinds & SanitizerKind::HWAddress) {
986 if (Arg *HwasanAbiArg =
987 Args.getLastArg(options::OPT_fsanitize_hwaddress_abi_EQ)) {
988 HwasanAbi = HwasanAbiArg->getValue();
989 if (HwasanAbi != "platform" && HwasanAbi != "interceptor" &&
990 DiagnoseErrors)
991 D.Diag(clang::diag::err_drv_invalid_value)
992 << HwasanAbiArg->getAsString(Args) << HwasanAbi;
993 } else {
994 HwasanAbi = "interceptor";
995 }
996 if (TC.getTriple().getArch() == llvm::Triple::x86_64)
997 HwasanUseAliases = Args.hasFlag(
998 options::OPT_fsanitize_hwaddress_experimental_aliasing,
999 options::OPT_fno_sanitize_hwaddress_experimental_aliasing,
1000 HwasanUseAliases);
1001 }
1002
1003 if (AllAddedKinds & SanitizerKind::SafeStack) {
1004 // SafeStack runtime is built into the system on Android and Fuchsia.
1005 SafeStackRuntime =
1006 !TC.getTriple().isAndroid() && !TC.getTriple().isOSFuchsia();
1007 }
1008
1009 LinkRuntimes =
1010 Args.hasFlag(options::OPT_fsanitize_link_runtime,
1011 options::OPT_fno_sanitize_link_runtime, LinkRuntimes);
1012
1013 // Parse -link-cxx-sanitizer flag.
1014 LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime,
1015 options::OPT_fno_sanitize_link_cxx_runtime,
1016 LinkCXXRuntimes) ||
1017 D.CCCIsCXX();
1018
1019 NeedsMemProfRt = Args.hasFlag(options::OPT_fmemory_profile,
1020 options::OPT_fmemory_profile_EQ,
1021 options::OPT_fno_memory_profile, false);
1022
1023 // Finally, initialize the set of available and recoverable sanitizers.
1024 Sanitizers.Mask |= Kinds;
1025 RecoverableSanitizers.Mask |= RecoverableKinds;
1026 TrapSanitizers.Mask |= TrappingKinds;
1027 assert(!(RecoverableKinds & TrappingKinds) &&
1028 "Overlap between recoverable and trapping sanitizers");
1029 }
1030
toString(const clang::SanitizerSet & Sanitizers)1031 static std::string toString(const clang::SanitizerSet &Sanitizers) {
1032 std::string Res;
1033 #define SANITIZER(NAME, ID) \
1034 if (Sanitizers.has(SanitizerKind::ID)) { \
1035 if (!Res.empty()) \
1036 Res += ","; \
1037 Res += NAME; \
1038 }
1039 #include "clang/Basic/Sanitizers.def"
1040 return Res;
1041 }
1042
addSpecialCaseListOpt(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs,const char * SCLOptFlag,const std::vector<std::string> & SCLFiles)1043 static void addSpecialCaseListOpt(const llvm::opt::ArgList &Args,
1044 llvm::opt::ArgStringList &CmdArgs,
1045 const char *SCLOptFlag,
1046 const std::vector<std::string> &SCLFiles) {
1047 for (const auto &SCLPath : SCLFiles) {
1048 SmallString<64> SCLOpt(SCLOptFlag);
1049 SCLOpt += SCLPath;
1050 CmdArgs.push_back(Args.MakeArgString(SCLOpt));
1051 }
1052 }
1053
addIncludeLinkerOption(const ToolChain & TC,const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs,StringRef SymbolName)1054 static void addIncludeLinkerOption(const ToolChain &TC,
1055 const llvm::opt::ArgList &Args,
1056 llvm::opt::ArgStringList &CmdArgs,
1057 StringRef SymbolName) {
1058 SmallString<64> LinkerOptionFlag;
1059 LinkerOptionFlag = "--linker-option=/include:";
1060 if (TC.getTriple().getArch() == llvm::Triple::x86) {
1061 // Win32 mangles C function names with a '_' prefix.
1062 LinkerOptionFlag += '_';
1063 }
1064 LinkerOptionFlag += SymbolName;
1065 CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
1066 }
1067
hasTargetFeatureMTE(const llvm::opt::ArgStringList & CmdArgs)1068 static bool hasTargetFeatureMTE(const llvm::opt::ArgStringList &CmdArgs) {
1069 for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End;
1070 ++Start) {
1071 auto It = std::find(Start, End, StringRef("+mte"));
1072 if (It == End)
1073 break;
1074 if (It > Start && *std::prev(It) == StringRef("-target-feature"))
1075 return true;
1076 Start = It;
1077 }
1078 return false;
1079 }
1080
addArgs(const ToolChain & TC,const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs,types::ID InputType) const1081 void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
1082 llvm::opt::ArgStringList &CmdArgs,
1083 types::ID InputType) const {
1084 // NVPTX doesn't currently support sanitizers. Bailing out here means
1085 // that e.g. -fsanitize=address applies only to host code, which is what we
1086 // want for now.
1087 //
1088 // AMDGPU sanitizer support is experimental and controlled by -fgpu-sanitize.
1089 if (TC.getTriple().isNVPTX() ||
1090 (TC.getTriple().isAMDGPU() &&
1091 !Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
1092 true)))
1093 return;
1094
1095 // Translate available CoverageFeatures to corresponding clang-cc1 flags.
1096 // Do it even if Sanitizers.empty() since some forms of coverage don't require
1097 // sanitizers.
1098 std::pair<int, const char *> CoverageFlags[] = {
1099 std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"),
1100 std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"),
1101 std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"),
1102 std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"),
1103 std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"),
1104 std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"),
1105 std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"),
1106 std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"),
1107 std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"),
1108 std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"),
1109 std::make_pair(CoverageTracePCGuard,
1110 "-fsanitize-coverage-trace-pc-guard"),
1111 std::make_pair(CoverageInline8bitCounters,
1112 "-fsanitize-coverage-inline-8bit-counters"),
1113 std::make_pair(CoverageInlineBoolFlag,
1114 "-fsanitize-coverage-inline-bool-flag"),
1115 std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"),
1116 std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"),
1117 std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth"),
1118 std::make_pair(CoverageTraceLoads, "-fsanitize-coverage-trace-loads"),
1119 std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores"),
1120 std::make_pair(CoverageControlFlow, "-fsanitize-coverage-control-flow")};
1121 for (auto F : CoverageFlags) {
1122 if (CoverageFeatures & F.first)
1123 CmdArgs.push_back(F.second);
1124 }
1125 addSpecialCaseListOpt(
1126 Args, CmdArgs, "-fsanitize-coverage-allowlist=", CoverageAllowlistFiles);
1127 addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-ignorelist=",
1128 CoverageIgnorelistFiles);
1129
1130 // Translate available BinaryMetadataFeatures to corresponding clang-cc1
1131 // flags. Does not depend on any other sanitizers.
1132 const std::pair<int, std::string> BinaryMetadataFlags[] = {
1133 std::make_pair(BinaryMetadataCovered, "covered"),
1134 std::make_pair(BinaryMetadataAtomics, "atomics"),
1135 std::make_pair(BinaryMetadataUAR, "uar")};
1136 for (const auto &F : BinaryMetadataFlags) {
1137 if (BinaryMetadataFeatures & F.first)
1138 CmdArgs.push_back(
1139 Args.MakeArgString("-fexperimental-sanitize-metadata=" + F.second));
1140 }
1141
1142 if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
1143 // Instruct the code generator to embed linker directives in the object file
1144 // that cause the required runtime libraries to be linked.
1145 CmdArgs.push_back(
1146 Args.MakeArgString("--dependent-lib=" +
1147 TC.getCompilerRTBasename(Args, "ubsan_standalone")));
1148 if (types::isCXX(InputType))
1149 CmdArgs.push_back(Args.MakeArgString(
1150 "--dependent-lib=" +
1151 TC.getCompilerRTBasename(Args, "ubsan_standalone_cxx")));
1152 }
1153 if (TC.getTriple().isOSWindows() && needsStatsRt()) {
1154 CmdArgs.push_back(Args.MakeArgString(
1155 "--dependent-lib=" + TC.getCompilerRTBasename(Args, "stats_client")));
1156
1157 // The main executable must export the stats runtime.
1158 // FIXME: Only exporting from the main executable (e.g. based on whether the
1159 // translation unit defines main()) would save a little space, but having
1160 // multiple copies of the runtime shouldn't hurt.
1161 CmdArgs.push_back(Args.MakeArgString(
1162 "--dependent-lib=" + TC.getCompilerRTBasename(Args, "stats")));
1163 addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register");
1164 }
1165
1166 if (Sanitizers.empty())
1167 return;
1168 CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
1169
1170 if (!RecoverableSanitizers.empty())
1171 CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
1172 toString(RecoverableSanitizers)));
1173
1174 if (!TrapSanitizers.empty())
1175 CmdArgs.push_back(
1176 Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
1177
1178 addSpecialCaseListOpt(Args, CmdArgs,
1179 "-fsanitize-ignorelist=", UserIgnorelistFiles);
1180 addSpecialCaseListOpt(Args, CmdArgs,
1181 "-fsanitize-system-ignorelist=", SystemIgnorelistFiles);
1182
1183 if (MsanTrackOrigins)
1184 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
1185 Twine(MsanTrackOrigins)));
1186
1187 if (MsanUseAfterDtor)
1188 CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
1189
1190 if (!MsanParamRetval)
1191 CmdArgs.push_back("-fno-sanitize-memory-param-retval");
1192
1193 // FIXME: Pass these parameters as function attributes, not as -llvm flags.
1194 if (!TsanMemoryAccess) {
1195 CmdArgs.push_back("-mllvm");
1196 CmdArgs.push_back("-tsan-instrument-memory-accesses=0");
1197 CmdArgs.push_back("-mllvm");
1198 CmdArgs.push_back("-tsan-instrument-memintrinsics=0");
1199 }
1200 if (!TsanFuncEntryExit) {
1201 CmdArgs.push_back("-mllvm");
1202 CmdArgs.push_back("-tsan-instrument-func-entry-exit=0");
1203 }
1204 if (!TsanAtomics) {
1205 CmdArgs.push_back("-mllvm");
1206 CmdArgs.push_back("-tsan-instrument-atomics=0");
1207 }
1208
1209 if (HwasanUseAliases) {
1210 CmdArgs.push_back("-mllvm");
1211 CmdArgs.push_back("-hwasan-experimental-use-page-aliases=1");
1212 }
1213
1214 if (CfiCrossDso)
1215 CmdArgs.push_back("-fsanitize-cfi-cross-dso");
1216
1217 if (CfiICallGeneralizePointers)
1218 CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
1219
1220 if (CfiCanonicalJumpTables)
1221 CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");
1222
1223 if (Stats)
1224 CmdArgs.push_back("-fsanitize-stats");
1225
1226 if (MinimalRuntime)
1227 CmdArgs.push_back("-fsanitize-minimal-runtime");
1228
1229 if (AsanFieldPadding)
1230 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
1231 Twine(AsanFieldPadding)));
1232
1233 if (AsanUseAfterScope)
1234 CmdArgs.push_back("-fsanitize-address-use-after-scope");
1235
1236 if (AsanPoisonCustomArrayCookie)
1237 CmdArgs.push_back("-fsanitize-address-poison-custom-array-cookie");
1238
1239 if (AsanGlobalsDeadStripping)
1240 CmdArgs.push_back("-fsanitize-address-globals-dead-stripping");
1241
1242 if (!AsanUseOdrIndicator)
1243 CmdArgs.push_back("-fno-sanitize-address-use-odr-indicator");
1244
1245 if (AsanInvalidPointerCmp) {
1246 CmdArgs.push_back("-mllvm");
1247 CmdArgs.push_back("-asan-detect-invalid-pointer-cmp");
1248 }
1249
1250 if (AsanInvalidPointerSub) {
1251 CmdArgs.push_back("-mllvm");
1252 CmdArgs.push_back("-asan-detect-invalid-pointer-sub");
1253 }
1254
1255 if (AsanOutlineInstrumentation) {
1256 CmdArgs.push_back("-mllvm");
1257 CmdArgs.push_back("-asan-instrumentation-with-call-threshold=0");
1258 }
1259
1260 // Only pass the option to the frontend if the user requested,
1261 // otherwise the frontend will just use the codegen default.
1262 if (AsanDtorKind != llvm::AsanDtorKind::Invalid) {
1263 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-destructor=" +
1264 AsanDtorKindToString(AsanDtorKind)));
1265 }
1266
1267 if (AsanUseAfterReturn != llvm::AsanDetectStackUseAfterReturnMode::Invalid) {
1268 CmdArgs.push_back(Args.MakeArgString(
1269 "-fsanitize-address-use-after-return=" +
1270 AsanDetectStackUseAfterReturnModeToString(AsanUseAfterReturn)));
1271 }
1272
1273 if (!HwasanAbi.empty()) {
1274 CmdArgs.push_back("-default-function-attr");
1275 CmdArgs.push_back(Args.MakeArgString("hwasan-abi=" + HwasanAbi));
1276 }
1277
1278 if (Sanitizers.has(SanitizerKind::HWAddress) && !HwasanUseAliases) {
1279 CmdArgs.push_back("-target-feature");
1280 CmdArgs.push_back("+tagged-globals");
1281 }
1282
1283 // MSan: Workaround for PR16386.
1284 // ASan: This is mainly to help LSan with cases such as
1285 // https://github.com/google/sanitizers/issues/373
1286 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't
1287 // affect compilation.
1288 if (Sanitizers.has(SanitizerKind::Memory) ||
1289 Sanitizers.has(SanitizerKind::Address))
1290 CmdArgs.push_back("-fno-assume-sane-operator-new");
1291
1292 // libFuzzer wants to intercept calls to certain library functions, so the
1293 // following -fno-builtin-* flags force the compiler to emit interposable
1294 // libcalls to these functions. Other sanitizers effectively do the same thing
1295 // by marking all library call sites with NoBuiltin attribute in their LLVM
1296 // pass. (see llvm::maybeMarkSanitizerLibraryCallNoBuiltin)
1297 if (Sanitizers.has(SanitizerKind::FuzzerNoLink)) {
1298 CmdArgs.push_back("-fno-builtin-bcmp");
1299 CmdArgs.push_back("-fno-builtin-memcmp");
1300 CmdArgs.push_back("-fno-builtin-strncmp");
1301 CmdArgs.push_back("-fno-builtin-strcmp");
1302 CmdArgs.push_back("-fno-builtin-strncasecmp");
1303 CmdArgs.push_back("-fno-builtin-strcasecmp");
1304 CmdArgs.push_back("-fno-builtin-strstr");
1305 CmdArgs.push_back("-fno-builtin-strcasestr");
1306 CmdArgs.push_back("-fno-builtin-memmem");
1307 }
1308
1309 // Require -fvisibility= flag on non-Windows when compiling if vptr CFI is
1310 // enabled.
1311 if (Sanitizers.hasOneOf(CFIClasses) && !TC.getTriple().isOSWindows() &&
1312 !Args.hasArg(options::OPT_fvisibility_EQ)) {
1313 TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with)
1314 << lastArgumentForMask(TC.getDriver(), Args,
1315 Sanitizers.Mask & CFIClasses)
1316 << "-fvisibility=";
1317 }
1318
1319 if (Sanitizers.has(SanitizerKind::MemtagStack) &&
1320 !hasTargetFeatureMTE(CmdArgs))
1321 TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature);
1322 }
1323
parseArgValues(const Driver & D,const llvm::opt::Arg * A,bool DiagnoseErrors)1324 SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
1325 bool DiagnoseErrors) {
1326 assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
1327 A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
1328 A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
1329 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
1330 A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
1331 A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
1332 "Invalid argument in parseArgValues!");
1333 SanitizerMask Kinds;
1334 for (int i = 0, n = A->getNumValues(); i != n; ++i) {
1335 const char *Value = A->getValue(i);
1336 SanitizerMask Kind;
1337 // Special case: don't accept -fsanitize=all.
1338 if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
1339 0 == strcmp("all", Value))
1340 Kind = SanitizerMask();
1341 else
1342 Kind = parseSanitizerValue(Value, /*AllowGroups=*/true);
1343
1344 if (Kind)
1345 Kinds |= Kind;
1346 else if (DiagnoseErrors)
1347 D.Diag(clang::diag::err_drv_unsupported_option_argument)
1348 << A->getSpelling() << Value;
1349 }
1350 return Kinds;
1351 }
1352
parseCoverageFeatures(const Driver & D,const llvm::opt::Arg * A,bool DiagnoseErrors)1353 int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
1354 bool DiagnoseErrors) {
1355 assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
1356 A->getOption().matches(options::OPT_fno_sanitize_coverage));
1357 int Features = 0;
1358 for (int i = 0, n = A->getNumValues(); i != n; ++i) {
1359 const char *Value = A->getValue(i);
1360 int F = llvm::StringSwitch<int>(Value)
1361 .Case("func", CoverageFunc)
1362 .Case("bb", CoverageBB)
1363 .Case("edge", CoverageEdge)
1364 .Case("indirect-calls", CoverageIndirCall)
1365 .Case("trace-bb", CoverageTraceBB)
1366 .Case("trace-cmp", CoverageTraceCmp)
1367 .Case("trace-div", CoverageTraceDiv)
1368 .Case("trace-gep", CoverageTraceGep)
1369 .Case("8bit-counters", Coverage8bitCounters)
1370 .Case("trace-pc", CoverageTracePC)
1371 .Case("trace-pc-guard", CoverageTracePCGuard)
1372 .Case("no-prune", CoverageNoPrune)
1373 .Case("inline-8bit-counters", CoverageInline8bitCounters)
1374 .Case("inline-bool-flag", CoverageInlineBoolFlag)
1375 .Case("pc-table", CoveragePCTable)
1376 .Case("stack-depth", CoverageStackDepth)
1377 .Case("trace-loads", CoverageTraceLoads)
1378 .Case("trace-stores", CoverageTraceStores)
1379 .Case("control-flow", CoverageControlFlow)
1380 .Default(0);
1381 if (F == 0 && DiagnoseErrors)
1382 D.Diag(clang::diag::err_drv_unsupported_option_argument)
1383 << A->getSpelling() << Value;
1384 Features |= F;
1385 }
1386 return Features;
1387 }
1388
parseBinaryMetadataFeatures(const Driver & D,const llvm::opt::Arg * A,bool DiagnoseErrors)1389 int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
1390 bool DiagnoseErrors) {
1391 assert(
1392 A->getOption().matches(options::OPT_fexperimental_sanitize_metadata_EQ) ||
1393 A->getOption().matches(
1394 options::OPT_fno_experimental_sanitize_metadata_EQ));
1395 int Features = 0;
1396 for (int i = 0, n = A->getNumValues(); i != n; ++i) {
1397 const char *Value = A->getValue(i);
1398 int F = llvm::StringSwitch<int>(Value)
1399 .Case("covered", BinaryMetadataCovered)
1400 .Case("atomics", BinaryMetadataAtomics)
1401 .Case("uar", BinaryMetadataUAR)
1402 .Case("all", ~0)
1403 .Default(0);
1404 if (F == 0 && DiagnoseErrors)
1405 D.Diag(clang::diag::err_drv_unsupported_option_argument)
1406 << A->getSpelling() << Value;
1407 Features |= F;
1408 }
1409 return Features;
1410 }
1411
lastArgumentForMask(const Driver & D,const llvm::opt::ArgList & Args,SanitizerMask Mask)1412 std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
1413 SanitizerMask Mask) {
1414 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
1415 E = Args.rend();
1416 I != E; ++I) {
1417 const auto *Arg = *I;
1418 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
1419 SanitizerMask AddKinds =
1420 expandSanitizerGroups(parseArgValues(D, Arg, false));
1421 if (AddKinds & Mask)
1422 return describeSanitizeArg(Arg, Mask);
1423 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
1424 SanitizerMask RemoveKinds =
1425 expandSanitizerGroups(parseArgValues(D, Arg, false));
1426 Mask &= ~RemoveKinds;
1427 }
1428 }
1429 llvm_unreachable("arg list didn't provide expected value");
1430 }
1431
describeSanitizeArg(const llvm::opt::Arg * A,SanitizerMask Mask)1432 std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) {
1433 assert(A->getOption().matches(options::OPT_fsanitize_EQ) &&
1434 "Invalid argument in describeSanitizerArg!");
1435
1436 std::string Sanitizers;
1437 for (int i = 0, n = A->getNumValues(); i != n; ++i) {
1438 if (expandSanitizerGroups(
1439 parseSanitizerValue(A->getValue(i), /*AllowGroups=*/true)) &
1440 Mask) {
1441 if (!Sanitizers.empty())
1442 Sanitizers += ",";
1443 Sanitizers += A->getValue(i);
1444 }
1445 }
1446
1447 assert(!Sanitizers.empty() && "arg didn't provide expected value");
1448 return "-fsanitize=" + Sanitizers;
1449 }
1450