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