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