1 //===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "clang/Driver/SanitizerArgs.h"
10 #include "ToolChains/CommonArgs.h"
11 #include "clang/Basic/Sanitizers.h"
12 #include "clang/Driver/Driver.h"
13 #include "clang/Driver/DriverDiagnostic.h"
14 #include "clang/Driver/Options.h"
15 #include "clang/Driver/ToolChain.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringSwitch.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/Path.h"
20 #include "llvm/Support/SpecialCaseList.h"
23 using namespace clang;
24 using namespace clang::SanitizerKind;
25 using namespace clang::driver;
26 using namespace llvm::opt;
28 enum : SanitizerMask {
29 NeedsUbsanRt = Undefined | Integer | Nullability | CFI,
30 NeedsUbsanCxxRt = Vptr | CFI,
31 NotAllowedWithTrap = Vptr,
32 RequiresPIE = DataFlow,
33 NeedsUnwindTables = Address | Thread | Memory | DataFlow,
35 Address | Memory | Leak | Undefined | Integer | Nullability | DataFlow,
36 RecoverableByDefault = Undefined | Integer | Nullability,
37 Unrecoverable = Unreachable | Return,
38 LegacyFsanitizeRecoverMask = Undefined | Integer,
40 TrappingSupported = (Undefined & ~Vptr) | UnsignedIntegerOverflow |
41 Nullability | LocalBounds | CFI,
42 TrappingDefault = CFI,
43 CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast,
46 enum CoverageFeature {
47 CoverageFunc = 1 << 0,
49 CoverageEdge = 1 << 2,
50 CoverageIndirCall = 1 << 3,
51 CoverageTraceBB = 1 << 4,
52 CoverageTraceCmp = 1 << 5,
53 CoverageTraceDiv = 1 << 6,
54 CoverageTraceGep = 1 << 7,
55 Coverage8bitCounters = 1 << 8,
56 CoverageTracePC = 1 << 9,
57 CoverageTracePCGuard = 1 << 10,
58 CoverageNoPrune = 1 << 11,
61 /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
62 /// invalid components. Returns a SanitizerMask.
63 static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
66 /// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
67 /// components. Returns OR of members of \c CoverageFeature enumeration.
68 static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A);
70 /// Produce an argument string from ArgList \p Args, which shows how it
71 /// provides some sanitizer kind from \p Mask. For example, the argument list
72 /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
73 /// would produce "-fsanitize=vptr".
74 static std::string lastArgumentForMask(const Driver &D,
75 const llvm::opt::ArgList &Args,
78 /// Produce an argument string from argument \p A, which shows how it provides
79 /// a value in \p Mask. For instance, the argument
80 /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
81 /// "-fsanitize=alignment".
82 static std::string describeSanitizeArg(const llvm::opt::Arg *A,
85 /// Produce a string containing comma-separated names of sanitizers in \p
87 static std::string toString(const clang::SanitizerSet &Sanitizers);
89 static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds,
90 std::string &BLPath) {
91 const char *BlacklistFile = nullptr;
93 BlacklistFile = "asan_blacklist.txt";
94 else if (Kinds & Memory)
95 BlacklistFile = "msan_blacklist.txt";
96 else if (Kinds & Thread)
97 BlacklistFile = "tsan_blacklist.txt";
98 else if (Kinds & DataFlow)
99 BlacklistFile = "dfsan_abilist.txt";
100 else if (Kinds & CFI)
101 BlacklistFile = "cfi_blacklist.txt";
104 clang::SmallString<64> Path(D.ResourceDir);
105 llvm::sys::path::append(Path, BlacklistFile);
112 /// Sets group bits for every group that has at least one representative already
113 /// enabled in \p Kinds.
114 static SanitizerMask setGroupBits(SanitizerMask Kinds) {
115 #define SANITIZER(NAME, ID)
116 #define SANITIZER_GROUP(NAME, ID, ALIAS) \
117 if (Kinds & SanitizerKind::ID) \
118 Kinds |= SanitizerKind::ID##Group;
119 #include "clang/Basic/Sanitizers.def"
123 static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
124 const llvm::opt::ArgList &Args) {
125 SanitizerMask TrapRemove = 0; // During the loop below, the accumulated set of
126 // sanitizers disabled by the current sanitizer
127 // argument or any argument after it.
128 SanitizerMask TrappingKinds = 0;
129 SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported);
131 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
133 const auto *Arg = *I;
134 if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
136 SanitizerMask Add = parseArgValues(D, Arg, true);
138 if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) {
140 S.Mask = InvalidValues;
141 D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap"
144 TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove;
145 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
147 TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true));
148 } else if (Arg->getOption().matches(
149 options::OPT_fsanitize_undefined_trap_on_error)) {
152 expandSanitizerGroups(UndefinedGroup & ~TrapRemove) & ~TrapRemove;
153 } else if (Arg->getOption().matches(
154 options::OPT_fno_sanitize_undefined_trap_on_error)) {
156 TrapRemove |= expandSanitizerGroups(UndefinedGroup);
160 // Apply default trapping behavior.
161 TrappingKinds |= TrappingDefault & ~TrapRemove;
163 return TrappingKinds;
166 bool SanitizerArgs::needsUbsanRt() const {
167 return ((Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) ||
169 !Sanitizers.has(Address) && !Sanitizers.has(Memory) &&
170 !Sanitizers.has(Thread) && !Sanitizers.has(DataFlow) &&
171 !Sanitizers.has(Leak) && !CfiCrossDso;
174 bool SanitizerArgs::needsCfiRt() const {
175 return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
178 bool SanitizerArgs::needsCfiDiagRt() const {
179 return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
182 bool SanitizerArgs::requiresPIE() const {
183 return NeedPIE || (Sanitizers.Mask & RequiresPIE);
186 bool SanitizerArgs::needsUnwindTables() const {
187 return Sanitizers.Mask & NeedsUnwindTables;
190 SanitizerArgs::SanitizerArgs(const ToolChain &TC,
191 const llvm::opt::ArgList &Args) {
192 SanitizerMask AllRemove = 0; // During the loop below, the accumulated set of
193 // sanitizers disabled by the current sanitizer
194 // argument or any argument after it.
195 SanitizerMask AllAddedKinds = 0; // Mask of all sanitizers ever enabled by
196 // -fsanitize= flags (directly or via group
197 // expansion), some of which may be disabled
198 // later. Used to carefully prune
199 // unused-argument diagnostics.
200 SanitizerMask DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
201 // Used to deduplicate diagnostics.
202 SanitizerMask Kinds = 0;
203 const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
204 ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
206 const Driver &D = TC.getDriver();
207 SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args);
208 SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
210 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
212 const auto *Arg = *I;
213 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
215 SanitizerMask Add = parseArgValues(D, Arg, true);
216 AllAddedKinds |= expandSanitizerGroups(Add);
218 // Avoid diagnosing any sanitizer which is disabled later.
220 // At this point we have not expanded groups, so any unsupported
221 // sanitizers in Add are those which have been explicitly enabled.
223 if (SanitizerMask KindsToDiagnose =
224 Add & InvalidTrappingKinds & ~DiagnosedKinds) {
225 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
226 D.Diag(diag::err_drv_argument_not_allowed_with)
227 << Desc << "-fsanitize-trap=undefined";
228 DiagnosedKinds |= KindsToDiagnose;
230 Add &= ~InvalidTrappingKinds;
231 if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
232 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
233 D.Diag(diag::err_drv_unsupported_opt_for_target)
234 << Desc << TC.getTriple().str();
235 DiagnosedKinds |= KindsToDiagnose;
239 // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups
240 // so we don't error out if -fno-rtti and -fsanitize=undefined were
243 (RTTIMode == ToolChain::RM_DisabledImplicitly ||
244 RTTIMode == ToolChain::RM_DisabledExplicitly)) {
245 if (RTTIMode == ToolChain::RM_DisabledImplicitly)
246 // Warn about not having rtti enabled if the vptr sanitizer is
247 // explicitly enabled
248 D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
250 const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg();
252 "RTTI disabled explicitly but we have no argument!");
253 D.Diag(diag::err_drv_argument_not_allowed_with)
254 << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
257 // Take out the Vptr sanitizer from the enabled sanitizers
261 Add = expandSanitizerGroups(Add);
262 // Group expansion may have enabled a sanitizer which is disabled later.
264 // Silently discard any unsupported sanitizers implicitly enabled through
266 Add &= ~InvalidTrappingKinds;
269 // Enable coverage if the fuzzing flag is set.
271 CoverageFeatures |= CoverageTracePCGuard | CoverageIndirCall | CoverageTraceCmp;
274 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
276 SanitizerMask Remove = parseArgValues(D, Arg, true);
277 AllRemove |= expandSanitizerGroups(Remove);
281 // Enable toolchain specific default sanitizers if not explicitly disabled.
282 Kinds |= TC.getDefaultSanitizers() & ~AllRemove;
284 // We disable the vptr sanitizer if it was enabled by group expansion but RTTI
286 if ((Kinds & Vptr) &&
287 (RTTIMode == ToolChain::RM_DisabledImplicitly ||
288 RTTIMode == ToolChain::RM_DisabledExplicitly)) {
292 // Check that LTO is enabled if we need it.
293 if ((Kinds & NeedsLTO) && !D.isUsingLTO()) {
294 D.Diag(diag::err_drv_argument_only_allowed_with)
295 << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
298 // Report error if there are non-trapping sanitizers that require
299 // c++abi-specific parts of UBSan runtime, and they are not provided by the
300 // toolchain. We don't have a good way to check the latter, so we just
301 // check if the toolchan supports vptr.
302 if (~Supported & Vptr) {
303 SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt;
304 // The runtime library supports the Microsoft C++ ABI, but only well enough
305 // for CFI. FIXME: Remove this once we support vptr on Windows.
306 if (TC.getTriple().isOSWindows())
307 KindsToDiagnose &= ~CFI;
308 if (KindsToDiagnose) {
310 S.Mask = KindsToDiagnose;
311 D.Diag(diag::err_drv_unsupported_opt_for_target)
312 << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str();
313 Kinds &= ~KindsToDiagnose;
317 // Warn about incompatible groups of sanitizers.
318 std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
319 std::make_pair(Address, Thread), std::make_pair(Address, Memory),
320 std::make_pair(Thread, Memory), std::make_pair(Leak, Thread),
321 std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address),
322 std::make_pair(KernelAddress, Leak),
323 std::make_pair(KernelAddress, Thread),
324 std::make_pair(KernelAddress, Memory),
325 std::make_pair(Efficiency, Address),
326 std::make_pair(Efficiency, Leak),
327 std::make_pair(Efficiency, Thread),
328 std::make_pair(Efficiency, Memory),
329 std::make_pair(Efficiency, KernelAddress)};
330 for (auto G : IncompatibleGroups) {
331 SanitizerMask Group = G.first;
333 if (SanitizerMask Incompatible = Kinds & G.second) {
334 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
335 << lastArgumentForMask(D, Args, Group)
336 << lastArgumentForMask(D, Args, Incompatible);
337 Kinds &= ~Incompatible;
341 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
342 // -fsanitize=address. Perhaps it should print an error, or perhaps
343 // -f(-no)sanitize=leak should change whether leak detection is enabled by
346 // Parse -f(no-)?sanitize-recover flags.
347 SanitizerMask RecoverableKinds = RecoverableByDefault;
348 SanitizerMask DiagnosedUnrecoverableKinds = 0;
349 for (const auto *Arg : Args) {
350 const char *DeprecatedReplacement = nullptr;
351 if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
352 DeprecatedReplacement =
353 "-fsanitize-recover=undefined,integer' or '-fsanitize-recover=all";
354 RecoverableKinds |= expandSanitizerGroups(LegacyFsanitizeRecoverMask);
356 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
357 DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer' or "
358 "'-fno-sanitize-recover=all";
359 RecoverableKinds &= ~expandSanitizerGroups(LegacyFsanitizeRecoverMask);
361 } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
362 SanitizerMask Add = parseArgValues(D, Arg, true);
363 // Report error if user explicitly tries to recover from unrecoverable
365 if (SanitizerMask KindsToDiagnose =
366 Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
367 SanitizerSet SetToDiagnose;
368 SetToDiagnose.Mask |= KindsToDiagnose;
369 D.Diag(diag::err_drv_unsupported_option_argument)
370 << Arg->getOption().getName() << toString(SetToDiagnose);
371 DiagnosedUnrecoverableKinds |= KindsToDiagnose;
373 RecoverableKinds |= expandSanitizerGroups(Add);
375 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
376 RecoverableKinds &= ~expandSanitizerGroups(parseArgValues(D, Arg, true));
379 if (DeprecatedReplacement) {
380 D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
381 << DeprecatedReplacement;
384 RecoverableKinds &= Kinds;
385 RecoverableKinds &= ~Unrecoverable;
387 TrappingKinds &= Kinds;
389 // Setup blacklist files.
390 // Add default blacklist from resource directory.
393 if (getDefaultBlacklist(D, Kinds, BLPath) && llvm::sys::fs::exists(BLPath))
394 BlacklistFiles.push_back(BLPath);
396 // Parse -f(no-)sanitize-blacklist options.
397 for (const auto *Arg : Args) {
398 if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
400 std::string BLPath = Arg->getValue();
401 if (llvm::sys::fs::exists(BLPath)) {
402 BlacklistFiles.push_back(BLPath);
403 ExtraDeps.push_back(BLPath);
405 D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
407 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
409 BlacklistFiles.clear();
413 // Validate blacklists format.
416 std::unique_ptr<llvm::SpecialCaseList> SCL(
417 llvm::SpecialCaseList::create(BlacklistFiles, BLError));
419 D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
422 // Parse -f[no-]sanitize-memory-track-origins[=level] options.
423 if (AllAddedKinds & Memory) {
425 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
426 options::OPT_fsanitize_memory_track_origins,
427 options::OPT_fno_sanitize_memory_track_origins)) {
428 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
429 MsanTrackOrigins = 2;
430 } else if (A->getOption().matches(
431 options::OPT_fno_sanitize_memory_track_origins)) {
432 MsanTrackOrigins = 0;
434 StringRef S = A->getValue();
435 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
436 MsanTrackOrigins > 2) {
437 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
442 Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor);
443 NeedPIE |= !(TC.getTriple().isOSLinux() &&
444 TC.getTriple().getArch() == llvm::Triple::x86_64);
447 if (AllAddedKinds & Thread) {
448 TsanMemoryAccess = Args.hasFlag(options::OPT_fsanitize_thread_memory_access,
449 options::OPT_fno_sanitize_thread_memory_access,
451 TsanFuncEntryExit = Args.hasFlag(options::OPT_fsanitize_thread_func_entry_exit,
452 options::OPT_fno_sanitize_thread_func_entry_exit,
454 TsanAtomics = Args.hasFlag(options::OPT_fsanitize_thread_atomics,
455 options::OPT_fno_sanitize_thread_atomics,
459 if (AllAddedKinds & CFI) {
460 CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
461 options::OPT_fno_sanitize_cfi_cross_dso, false);
462 // Without PIE, external function address may resolve to a PLT record, which
463 // can not be verified by the target module.
464 NeedPIE |= CfiCrossDso;
467 Stats = Args.hasFlag(options::OPT_fsanitize_stats,
468 options::OPT_fno_sanitize_stats, false);
470 // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
471 // enabled sanitizers.
472 for (const auto *Arg : Args) {
473 if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
474 int LegacySanitizeCoverage;
475 if (Arg->getNumValues() == 1 &&
476 !StringRef(Arg->getValue(0))
477 .getAsInteger(0, LegacySanitizeCoverage)) {
478 CoverageFeatures = 0;
480 if (LegacySanitizeCoverage != 0) {
481 D.Diag(diag::warn_drv_deprecated_arg)
482 << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard";
486 CoverageFeatures |= parseCoverageFeatures(D, Arg);
488 // Disable coverage and not claim the flags if there is at least one
489 // non-supporting sanitizer.
490 if (!(AllAddedKinds & ~setGroupBits(SupportsCoverage))) {
493 CoverageFeatures = 0;
495 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
497 CoverageFeatures &= ~parseCoverageFeatures(D, Arg);
500 // Choose at most one coverage type: function, bb, or edge.
501 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB))
502 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
503 << "-fsanitize-coverage=func"
504 << "-fsanitize-coverage=bb";
505 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge))
506 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
507 << "-fsanitize-coverage=func"
508 << "-fsanitize-coverage=edge";
509 if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
510 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
511 << "-fsanitize-coverage=bb"
512 << "-fsanitize-coverage=edge";
513 // Basic block tracing and 8-bit counters require some type of coverage
515 if (CoverageFeatures & CoverageTraceBB)
516 D.Diag(clang::diag::warn_drv_deprecated_arg)
517 << "-fsanitize-coverage=trace-bb"
518 << "-fsanitize-coverage=trace-pc-guard";
519 if (CoverageFeatures & Coverage8bitCounters)
520 D.Diag(clang::diag::warn_drv_deprecated_arg)
521 << "-fsanitize-coverage=8bit-counters"
522 << "-fsanitize-coverage=trace-pc-guard";
524 int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
525 if ((CoverageFeatures & InsertionPointTypes) &&
526 !(CoverageFeatures &(CoverageTracePC | CoverageTracePCGuard))) {
527 D.Diag(clang::diag::warn_drv_deprecated_arg)
528 << "-fsanitize-coverage=[func|bb|edge]"
529 << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
532 // trace-pc w/o func/bb/edge implies edge.
533 if ((CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard)) &&
534 !(CoverageFeatures & InsertionPointTypes))
535 CoverageFeatures |= CoverageEdge;
537 if (AllAddedKinds & Address) {
539 Args.hasArg(options::OPT_shared_libasan) || TC.getTriple().isAndroid();
540 NeedPIE |= TC.getTriple().isAndroid();
542 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
543 StringRef S = A->getValue();
544 // Legal values are 0 and 1, 2, but in future we may add more levels.
545 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
546 AsanFieldPadding > 2) {
547 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
551 if (Arg *WindowsDebugRTArg =
552 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
553 options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
554 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
555 switch (WindowsDebugRTArg->getOption().getID()) {
556 case options::OPT__SLASH_MTd:
557 case options::OPT__SLASH_MDd:
558 case options::OPT__SLASH_LDd:
559 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
560 << WindowsDebugRTArg->getAsString(Args)
561 << lastArgumentForMask(D, Args, Address);
562 D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
566 AsanUseAfterScope = Args.hasFlag(
567 options::OPT_fsanitize_address_use_after_scope,
568 options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
570 // As a workaround for a bug in gold 2.26 and earlier, dead stripping of
571 // globals in ASan is disabled by default on ELF targets.
572 // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002
573 AsanGlobalsDeadStripping =
574 !TC.getTriple().isOSBinFormatELF() ||
575 Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping);
577 AsanUseAfterScope = false;
580 // Parse -link-cxx-sanitizer flag.
582 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
584 // Finally, initialize the set of available and recoverable sanitizers.
585 Sanitizers.Mask |= Kinds;
586 RecoverableSanitizers.Mask |= RecoverableKinds;
587 TrapSanitizers.Mask |= TrappingKinds;
590 static std::string toString(const clang::SanitizerSet &Sanitizers) {
592 #define SANITIZER(NAME, ID) \
593 if (Sanitizers.has(ID)) { \
598 #include "clang/Basic/Sanitizers.def"
602 static void addIncludeLinkerOption(const ToolChain &TC,
603 const llvm::opt::ArgList &Args,
604 llvm::opt::ArgStringList &CmdArgs,
605 StringRef SymbolName) {
606 SmallString<64> LinkerOptionFlag;
607 LinkerOptionFlag = "--linker-option=/include:";
608 if (TC.getTriple().getArch() == llvm::Triple::x86) {
609 // Win32 mangles C function names with a '_' prefix.
610 LinkerOptionFlag += '_';
612 LinkerOptionFlag += SymbolName;
613 CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
616 void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
617 llvm::opt::ArgStringList &CmdArgs,
618 types::ID InputType) const {
619 // NVPTX doesn't currently support sanitizers. Bailing out here means that
620 // e.g. -fsanitize=address applies only to host code, which is what we want
622 if (TC.getTriple().isNVPTX())
625 // Translate available CoverageFeatures to corresponding clang-cc1 flags.
626 // Do it even if Sanitizers.empty() since some forms of coverage don't require
628 std::pair<int, const char *> CoverageFlags[] = {
629 std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"),
630 std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"),
631 std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"),
632 std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"),
633 std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"),
634 std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"),
635 std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"),
636 std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"),
637 std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"),
638 std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"),
639 std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"),
640 std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune")};
641 for (auto F : CoverageFlags) {
642 if (CoverageFeatures & F.first)
643 CmdArgs.push_back(F.second);
646 if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
647 // Instruct the code generator to embed linker directives in the object file
648 // that cause the required runtime libraries to be linked.
649 CmdArgs.push_back(Args.MakeArgString(
650 "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone")));
651 if (types::isCXX(InputType))
652 CmdArgs.push_back(Args.MakeArgString(
653 "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx")));
655 if (TC.getTriple().isOSWindows() && needsStatsRt()) {
656 CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
657 TC.getCompilerRT(Args, "stats_client")));
659 // The main executable must export the stats runtime.
660 // FIXME: Only exporting from the main executable (e.g. based on whether the
661 // translation unit defines main()) would save a little space, but having
662 // multiple copies of the runtime shouldn't hurt.
663 CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
664 TC.getCompilerRT(Args, "stats")));
665 addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register");
668 if (Sanitizers.empty())
670 CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
672 if (!RecoverableSanitizers.empty())
673 CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
674 toString(RecoverableSanitizers)));
676 if (!TrapSanitizers.empty())
678 Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
680 for (const auto &BLPath : BlacklistFiles) {
681 SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
682 BlacklistOpt += BLPath;
683 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
685 for (const auto &Dep : ExtraDeps) {
686 SmallString<64> ExtraDepOpt("-fdepfile-entry=");
688 CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
691 if (MsanTrackOrigins)
692 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
693 llvm::utostr(MsanTrackOrigins)));
695 if (MsanUseAfterDtor)
696 CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
698 // FIXME: Pass these parameters as function attributes, not as -llvm flags.
699 if (!TsanMemoryAccess) {
700 CmdArgs.push_back("-mllvm");
701 CmdArgs.push_back("-tsan-instrument-memory-accesses=0");
702 CmdArgs.push_back("-mllvm");
703 CmdArgs.push_back("-tsan-instrument-memintrinsics=0");
705 if (!TsanFuncEntryExit) {
706 CmdArgs.push_back("-mllvm");
707 CmdArgs.push_back("-tsan-instrument-func-entry-exit=0");
710 CmdArgs.push_back("-mllvm");
711 CmdArgs.push_back("-tsan-instrument-atomics=0");
715 CmdArgs.push_back("-fsanitize-cfi-cross-dso");
718 CmdArgs.push_back("-fsanitize-stats");
720 if (AsanFieldPadding)
721 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
722 llvm::utostr(AsanFieldPadding)));
724 if (AsanUseAfterScope)
725 CmdArgs.push_back("-fsanitize-address-use-after-scope");
727 if (AsanGlobalsDeadStripping)
728 CmdArgs.push_back("-fsanitize-address-globals-dead-stripping");
730 // MSan: Workaround for PR16386.
731 // ASan: This is mainly to help LSan with cases such as
732 // https://code.google.com/p/address-sanitizer/issues/detail?id=373
733 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't
734 // affect compilation.
735 if (Sanitizers.has(Memory) || Sanitizers.has(Address))
736 CmdArgs.push_back("-fno-assume-sane-operator-new");
738 // Require -fvisibility= flag on non-Windows when compiling if vptr CFI is
740 if (Sanitizers.hasOneOf(CFIClasses) && !TC.getTriple().isOSWindows() &&
741 !Args.hasArg(options::OPT_fvisibility_EQ)) {
742 TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with)
743 << lastArgumentForMask(TC.getDriver(), Args,
744 Sanitizers.Mask & CFIClasses)
749 SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
750 bool DiagnoseErrors) {
751 assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
752 A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
753 A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
754 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
755 A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
756 A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
757 "Invalid argument in parseArgValues!");
758 SanitizerMask Kinds = 0;
759 for (int i = 0, n = A->getNumValues(); i != n; ++i) {
760 const char *Value = A->getValue(i);
762 // Special case: don't accept -fsanitize=all.
763 if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
764 0 == strcmp("all", Value))
766 // Similarly, don't accept -fsanitize=efficiency-all.
767 else if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
768 0 == strcmp("efficiency-all", Value))
771 Kind = parseSanitizerValue(Value, /*AllowGroups=*/true);
775 else if (DiagnoseErrors)
776 D.Diag(clang::diag::err_drv_unsupported_option_argument)
777 << A->getOption().getName() << Value;
782 int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) {
783 assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
784 A->getOption().matches(options::OPT_fno_sanitize_coverage));
786 for (int i = 0, n = A->getNumValues(); i != n; ++i) {
787 const char *Value = A->getValue(i);
788 int F = llvm::StringSwitch<int>(Value)
789 .Case("func", CoverageFunc)
790 .Case("bb", CoverageBB)
791 .Case("edge", CoverageEdge)
792 .Case("indirect-calls", CoverageIndirCall)
793 .Case("trace-bb", CoverageTraceBB)
794 .Case("trace-cmp", CoverageTraceCmp)
795 .Case("trace-div", CoverageTraceDiv)
796 .Case("trace-gep", CoverageTraceGep)
797 .Case("8bit-counters", Coverage8bitCounters)
798 .Case("trace-pc", CoverageTracePC)
799 .Case("trace-pc-guard", CoverageTracePCGuard)
800 .Case("no-prune", CoverageNoPrune)
803 D.Diag(clang::diag::err_drv_unsupported_option_argument)
804 << A->getOption().getName() << Value;
810 std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
811 SanitizerMask Mask) {
812 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
815 const auto *Arg = *I;
816 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
817 SanitizerMask AddKinds =
818 expandSanitizerGroups(parseArgValues(D, Arg, false));
820 return describeSanitizeArg(Arg, Mask);
821 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
822 SanitizerMask RemoveKinds =
823 expandSanitizerGroups(parseArgValues(D, Arg, false));
824 Mask &= ~RemoveKinds;
827 llvm_unreachable("arg list didn't provide expected value");
830 std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) {
831 assert(A->getOption().matches(options::OPT_fsanitize_EQ)
832 && "Invalid argument in describeSanitizerArg!");
834 std::string Sanitizers;
835 for (int i = 0, n = A->getNumValues(); i != n; ++i) {
836 if (expandSanitizerGroups(
837 parseSanitizerValue(A->getValue(i), /*AllowGroups=*/true)) &
839 if (!Sanitizers.empty())
841 Sanitizers += A->getValue(i);
845 assert(!Sanitizers.empty() && "arg didn't provide expected value");
846 return "-fsanitize=" + Sanitizers;