blob: 1e7487f7690f5fda682a7fc9b12996bb97865336 [file] [log] [blame]
Alexey Samsonovcf055962013-08-08 10:11:02 +00001//===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Alexey Samsonov609213f92013-08-19 09:14:21 +00009#include "clang/Driver/SanitizerArgs.h"
Alexey Samsonovcf055962013-08-08 10:11:02 +000010#include "clang/Driver/Driver.h"
11#include "clang/Driver/DriverDiagnostic.h"
12#include "clang/Driver/Options.h"
13#include "clang/Driver/ToolChain.h"
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +000014#include "llvm/ADT/StringExtras.h"
Alexey Samsonovcf055962013-08-08 10:11:02 +000015#include "llvm/ADT/StringSwitch.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/Path.h"
Alexey Samsonovb7dd3292014-07-09 19:40:08 +000018#include "llvm/Support/SpecialCaseList.h"
Ahmed Charlesdfca6f92014-03-09 11:36:40 +000019#include <memory>
Alexey Samsonovcf055962013-08-08 10:11:02 +000020
21using namespace clang::driver;
22using namespace llvm::opt;
23
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +000024namespace {
25/// Assign ordinals to possible values of -fsanitize= flag.
26/// We use the ordinal values as bit positions within \c SanitizeKind.
27enum SanitizeOrdinal {
28#define SANITIZER(NAME, ID) SO_##ID,
29#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
30#include "clang/Basic/Sanitizers.def"
31 SO_Count
32};
33
34/// Represents a set of sanitizer kinds. It is also used to define:
35/// 1) set of sanitizers each sanitizer group expands into.
36/// 2) set of sanitizers sharing a specific property (e.g.
37/// all sanitizers with zero-base shadow).
38enum SanitizeKind {
39#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
40#define SANITIZER_GROUP(NAME, ID, ALIAS) \
41ID = ALIAS, ID##Group = 1 << SO_##ID##Group,
42#include "clang/Basic/Sanitizers.def"
43 NeedsUbsanRt = Undefined | Integer,
44 NotAllowedWithTrap = Vptr,
Dmitry Vyukov43419a72014-11-21 12:19:01 +000045 RequiresPIE = Memory | DataFlow,
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +000046 NeedsUnwindTables = Address | Thread | Memory | DataFlow
47};
48}
49
50/// Returns true if set of \p Sanitizers contain at least one sanitizer from
51/// \p Kinds.
52static bool hasOneOf(const clang::SanitizerSet &Sanitizers, unsigned Kinds) {
53#define SANITIZER(NAME, ID) \
54 if (Sanitizers.has(clang::SanitizerKind::ID) && (Kinds & ID)) \
55 return true;
56#include "clang/Basic/Sanitizers.def"
57 return false;
58}
59
60/// Adds all sanitizers from \p Kinds to \p Sanitizers.
61static void addAllOf(clang::SanitizerSet &Sanitizers, unsigned Kinds) {
62#define SANITIZER(NAME, ID) \
63 if (Kinds & ID) \
64 Sanitizers.set(clang::SanitizerKind::ID, true);
65#include "clang/Basic/Sanitizers.def"
66}
67
68static unsigned toSanitizeKind(clang::SanitizerKind K) {
69#define SANITIZER(NAME, ID) \
70 if (K == clang::SanitizerKind::ID) \
71 return ID;
72#include "clang/Basic/Sanitizers.def"
73 llvm_unreachable("Invalid SanitizerKind!");
74}
75
76/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
77/// Returns a member of the \c SanitizeKind enumeration, or \c 0
78/// if \p Value is not known.
79static unsigned parseValue(const char *Value);
80
81/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
82/// invalid components. Returns OR of members of \c SanitizeKind enumeration.
83static unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
84 bool DiagnoseErrors);
85
86/// Parse a single flag of the form -f[no]sanitize=.
87/// Sets the masks defining required change of the set of sanitizers.
88/// Returns true if the flag was parsed successfully.
89static bool parseArgument(const Driver &D, const llvm::opt::Arg *A,
90 unsigned &Add, unsigned &Remove, bool DiagnoseErrors);
91
92/// Produce an argument string from ArgList \p Args, which shows how it
93/// provides some sanitizer kind from \p Mask. For example, the argument list
94/// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
95/// would produce "-fsanitize=vptr".
96static std::string lastArgumentForMask(const Driver &D,
97 const llvm::opt::ArgList &Args,
98 unsigned Mask);
99
100static std::string lastArgumentForKind(const Driver &D,
101 const llvm::opt::ArgList &Args,
102 clang::SanitizerKind K) {
103 return lastArgumentForMask(D, Args, toSanitizeKind(K));
104}
105
106/// Produce an argument string from argument \p A, which shows how it provides
107/// a value in \p Mask. For instance, the argument
108/// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
109/// "-fsanitize=alignment".
110static std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask);
111
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000112/// Produce a string containing comma-separated names of sanitizers in \p
113/// Sanitizers set.
114static std::string toString(const clang::SanitizerSet &Sanitizers);
115
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000116/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
117/// this group enables.
118static unsigned expandGroups(unsigned Kinds);
119
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000120static unsigned getToolchainUnsupportedKinds(const ToolChain &TC) {
121 bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD;
122 bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
123 bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
124 bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64;
125
126 unsigned Unsupported = 0;
127 if (!(IsLinux && IsX86_64)) {
128 Unsupported |= Memory | DataFlow;
129 }
130 if (!((IsLinux || IsFreeBSD) && IsX86_64)) {
131 Unsupported |= Thread;
132 }
133 if (!(IsLinux && (IsX86 || IsX86_64))) {
134 Unsupported |= Function;
135 }
136 return Unsupported;
137}
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000138
139bool SanitizerArgs::needsUbsanRt() const {
140 return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt);
141}
142
Dmitry Vyukov43419a72014-11-21 12:19:01 +0000143bool SanitizerArgs::requiresPIE() const {
144 return AsanZeroBaseShadow || hasOneOf(Sanitizers, RequiresPIE);
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000145}
146
147bool SanitizerArgs::needsUnwindTables() const {
148 return hasOneOf(Sanitizers, NeedsUnwindTables);
149}
150
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000151void SanitizerArgs::clear() {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000152 Sanitizers.clear();
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000153 SanitizeRecover = false;
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000154 BlacklistFile = "";
Kostya Serebryany75b4f9e2014-11-11 22:15:07 +0000155 SanitizeCoverage = 0;
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000156 MsanTrackOrigins = 0;
Kostya Serebryanyaed71a82014-10-09 17:53:04 +0000157 AsanFieldPadding = 0;
Peter Collingbourne32701642013-11-01 18:16:25 +0000158 AsanZeroBaseShadow = false;
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000159 UbsanTrapOnError = false;
Alexey Samsonovbdfa6c22014-04-01 13:31:10 +0000160 AsanSharedRuntime = false;
Alexey Samsonov90490af2014-08-08 22:47:17 +0000161 LinkCXXRuntimes = false;
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000162}
Alexey Samsonovcf055962013-08-08 10:11:02 +0000163
Peter Collingbourne32701642013-11-01 18:16:25 +0000164SanitizerArgs::SanitizerArgs(const ToolChain &TC,
165 const llvm::opt::ArgList &Args) {
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000166 clear();
Peter Collingbourne32701642013-11-01 18:16:25 +0000167 unsigned AllRemove = 0; // During the loop below, the accumulated set of
168 // sanitizers disabled by the current sanitizer
169 // argument or any argument after it.
170 unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
171 // Used to deduplicate diagnostics.
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000172 unsigned Kinds = 0;
173 unsigned NotSupported = getToolchainUnsupportedKinds(TC);
Peter Collingbourne32701642013-11-01 18:16:25 +0000174 const Driver &D = TC.getDriver();
175 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
176 I != E; ++I) {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000177 unsigned Add, Remove;
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000178 if (!parseArgument(D, *I, Add, Remove, true))
Alexey Samsonovcf055962013-08-08 10:11:02 +0000179 continue;
180 (*I)->claim();
Peter Collingbourne32701642013-11-01 18:16:25 +0000181
Peter Collingbourne32701642013-11-01 18:16:25 +0000182 AllRemove |= expandGroups(Remove);
183
184 // Avoid diagnosing any sanitizer which is disabled later.
185 Add &= ~AllRemove;
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000186
Peter Collingbourne32701642013-11-01 18:16:25 +0000187 // At this point we have not expanded groups, so any unsupported sanitizers
188 // in Add are those which have been explicitly enabled. Diagnose them.
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000189 if (unsigned KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) {
190 // Only diagnose the new kinds.
191 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
192 D.Diag(diag::err_drv_unsupported_opt_for_target) << Desc
193 << TC.getTriple().str();
194 DiagnosedKinds |= KindsToDiagnose;
195 }
196 Add &= ~NotSupported;
197
Peter Collingbourne32701642013-11-01 18:16:25 +0000198 Add = expandGroups(Add);
199 // Group expansion may have enabled a sanitizer which is disabled later.
200 Add &= ~AllRemove;
201 // Silently discard any unsupported sanitizers implicitly enabled through
202 // group expansion.
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000203 Add &= ~NotSupported;
Peter Collingbourne32701642013-11-01 18:16:25 +0000204
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000205 Kinds |= Add;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000206 }
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000207 addAllOf(Sanitizers, Kinds);
208
209 SanitizeRecover = Args.hasFlag(options::OPT_fsanitize_recover,
210 options::OPT_fno_sanitize_recover, true);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000211
212 UbsanTrapOnError =
Alexey Samsonovcf055962013-08-08 10:11:02 +0000213 Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
214 options::OPT_fno_sanitize_undefined_trap_on_error, false);
215
Alexey Samsonovcf055962013-08-08 10:11:02 +0000216 // Warn about undefined sanitizer options that require runtime support.
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000217 if (UbsanTrapOnError && hasOneOf(Sanitizers, NotAllowedWithTrap)) {
218 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
219 << lastArgumentForMask(D, Args, NotAllowedWithTrap)
Alexey Samsonovcb3f8122014-03-20 10:48:29 +0000220 << "-fsanitize-undefined-trap-on-error";
Alexey Samsonovcf055962013-08-08 10:11:02 +0000221 }
222
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000223 // Check for incompatible sanitizers.
224 bool NeedsAsan = Sanitizers.has(SanitizerKind::Address);
225 bool NeedsTsan = Sanitizers.has(SanitizerKind::Thread);
226 bool NeedsMsan = Sanitizers.has(SanitizerKind::Memory);
227 bool NeedsLsan = Sanitizers.has(SanitizerKind::Leak);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000228 if (NeedsAsan && NeedsTsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000229 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
230 << lastArgumentForKind(D, Args, SanitizerKind::Address)
231 << lastArgumentForKind(D, Args, SanitizerKind::Thread);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000232 if (NeedsAsan && NeedsMsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000233 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
234 << lastArgumentForKind(D, Args, SanitizerKind::Address)
235 << lastArgumentForKind(D, Args, SanitizerKind::Memory);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000236 if (NeedsTsan && NeedsMsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000237 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
238 << lastArgumentForKind(D, Args, SanitizerKind::Thread)
239 << lastArgumentForKind(D, Args, SanitizerKind::Memory);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000240 if (NeedsLsan && NeedsTsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000241 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
242 << lastArgumentForKind(D, Args, SanitizerKind::Leak)
243 << lastArgumentForKind(D, Args, SanitizerKind::Thread);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000244 if (NeedsLsan && NeedsMsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000245 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
246 << lastArgumentForKind(D, Args, SanitizerKind::Leak)
247 << lastArgumentForKind(D, Args, SanitizerKind::Memory);
Alp Tokerf6a24ce2013-12-05 16:25:25 +0000248 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
Alexey Samsonovcf055962013-08-08 10:11:02 +0000249 // -fsanitize=address. Perhaps it should print an error, or perhaps
250 // -f(-no)sanitize=leak should change whether leak detection is enabled by
251 // default in ASan?
252
Alexey Samsonovcf055962013-08-08 10:11:02 +0000253 // Parse -f(no-)sanitize-blacklist options.
254 if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist,
255 options::OPT_fno_sanitize_blacklist)) {
256 if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) {
257 std::string BLPath = BLArg->getValue();
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000258 if (llvm::sys::fs::exists(BLPath)) {
259 // Validate the blacklist format.
260 std::string BLError;
Ahmed Charlesb8984322014-03-07 20:03:18 +0000261 std::unique_ptr<llvm::SpecialCaseList> SCL(
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000262 llvm::SpecialCaseList::create(BLPath, BLError));
263 if (!SCL.get())
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000264 D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000265 else
266 BlacklistFile = BLPath;
267 } else {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000268 D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000269 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000270 }
271 } else {
272 // If no -fsanitize-blacklist option is specified, try to look up for
273 // blacklist in the resource directory.
274 std::string BLPath;
Alexey Samsonov59f34bb2014-11-14 00:46:39 +0000275 if (getDefaultBlacklist(D, BLPath) && llvm::sys::fs::exists(BLPath))
Alexey Samsonovcf055962013-08-08 10:11:02 +0000276 BlacklistFile = BLPath;
277 }
278
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000279 // Parse -f[no-]sanitize-memory-track-origins[=level] options.
280 if (NeedsMsan) {
281 if (Arg *A =
282 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
283 options::OPT_fsanitize_memory_track_origins,
284 options::OPT_fno_sanitize_memory_track_origins)) {
285 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
286 MsanTrackOrigins = 1;
287 } else if (A->getOption().matches(
288 options::OPT_fno_sanitize_memory_track_origins)) {
289 MsanTrackOrigins = 0;
290 } else {
291 StringRef S = A->getValue();
292 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
293 MsanTrackOrigins > 2) {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000294 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000295 }
296 }
297 }
298 }
299
Kostya Serebryany75b4f9e2014-11-11 22:15:07 +0000300 // Parse -fsanitize-coverage=N
301 if (NeedsAsan) { // Currently asan is required.
302 if (Arg *A = Args.getLastArg(options::OPT_fsanitize_coverage)) {
303 StringRef S = A->getValue();
304 // Legal values are 0..4.
305 if (S.getAsInteger(0, SanitizeCoverage) || SanitizeCoverage < 0 ||
306 SanitizeCoverage > 4)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000307 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
Kostya Serebryany75b4f9e2014-11-11 22:15:07 +0000308 }
309 }
310
Alexey Samsonovbdfa6c22014-04-01 13:31:10 +0000311 if (NeedsAsan) {
312 AsanSharedRuntime =
Evgeniy Stepanov6f0ae182014-06-05 11:14:00 +0000313 Args.hasArg(options::OPT_shared_libasan) ||
314 (TC.getTriple().getEnvironment() == llvm::Triple::Android);
Peter Collingbourne32701642013-11-01 18:16:25 +0000315 AsanZeroBaseShadow =
Evgeniy Stepanovd04b8612014-01-16 10:19:31 +0000316 (TC.getTriple().getEnvironment() == llvm::Triple::Android);
Kostya Serebryanyaed71a82014-10-09 17:53:04 +0000317 if (Arg *A =
318 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
319 StringRef S = A->getValue();
320 // Legal values are 0 and 1, 2, but in future we may add more levels.
321 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
322 AsanFieldPadding > 2) {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000323 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
Kostya Serebryanyaed71a82014-10-09 17:53:04 +0000324 }
325 }
Ehsan Akhgarie0db1962014-10-14 23:15:44 +0000326
327 if (Arg *WindowsDebugRTArg =
328 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
329 options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
330 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
331 switch (WindowsDebugRTArg->getOption().getID()) {
332 case options::OPT__SLASH_MTd:
333 case options::OPT__SLASH_MDd:
334 case options::OPT__SLASH_LDd:
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000335 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
Ehsan Akhgarie0db1962014-10-14 23:15:44 +0000336 << WindowsDebugRTArg->getAsString(Args)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000337 << lastArgumentForKind(D, Args, SanitizerKind::Address);
338 D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
Ehsan Akhgarie0db1962014-10-14 23:15:44 +0000339 }
340 }
Alexey Samsonovbdfa6c22014-04-01 13:31:10 +0000341 }
Alexey Samsonov90490af2014-08-08 22:47:17 +0000342
343 // Parse -link-cxx-sanitizer flag.
344 LinkCXXRuntimes =
345 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
Alexey Samsonovcf055962013-08-08 10:11:02 +0000346}
347
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000348static std::string toString(const clang::SanitizerSet &Sanitizers) {
349 std::string Res;
350#define SANITIZER(NAME, ID) \
351 if (Sanitizers.has(clang::SanitizerKind::ID)) { \
352 if (!Res.empty()) \
353 Res += ","; \
354 Res += NAME; \
355 }
356#include "clang/Basic/Sanitizers.def"
357 return Res;
358}
359
Peter Collingbourne32701642013-11-01 18:16:25 +0000360void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
Alexey Samsonovcf055962013-08-08 10:11:02 +0000361 llvm::opt::ArgStringList &CmdArgs) const {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000362 if (Sanitizers.empty())
Alexey Samsonovcf055962013-08-08 10:11:02 +0000363 return;
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000364 CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
365
366 if (!SanitizeRecover)
367 CmdArgs.push_back("-fno-sanitize-recover");
368
369 if (UbsanTrapOnError)
370 CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
371
Alexey Samsonovcf055962013-08-08 10:11:02 +0000372 if (!BlacklistFile.empty()) {
373 SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
374 BlacklistOpt += BlacklistFile;
375 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
376 }
377
378 if (MsanTrackOrigins)
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000379 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
380 llvm::utostr(MsanTrackOrigins)));
Kostya Serebryanyaed71a82014-10-09 17:53:04 +0000381 if (AsanFieldPadding)
382 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
383 llvm::utostr(AsanFieldPadding)));
Kostya Serebryany75b4f9e2014-11-11 22:15:07 +0000384 if (SanitizeCoverage)
385 CmdArgs.push_back(Args.MakeArgString("-fsanitize-coverage=" +
386 llvm::utostr(SanitizeCoverage)));
Alexey Samsonovcf055962013-08-08 10:11:02 +0000387 // Workaround for PR16386.
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000388 if (Sanitizers.has(SanitizerKind::Memory))
Alexey Samsonovcf055962013-08-08 10:11:02 +0000389 CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
390}
391
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000392bool SanitizerArgs::getDefaultBlacklist(const Driver &D, std::string &BLPath) {
393 const char *BlacklistFile = nullptr;
394 if (Sanitizers.has(SanitizerKind::Address))
395 BlacklistFile = "asan_blacklist.txt";
396 else if (Sanitizers.has(SanitizerKind::Memory))
397 BlacklistFile = "msan_blacklist.txt";
398 else if (Sanitizers.has(SanitizerKind::Thread))
399 BlacklistFile = "tsan_blacklist.txt";
400 else if (Sanitizers.has(SanitizerKind::DataFlow))
401 BlacklistFile = "dfsan_abilist.txt";
402
403 if (BlacklistFile) {
404 SmallString<64> Path(D.ResourceDir);
405 llvm::sys::path::append(Path, BlacklistFile);
406 BLPath = Path.str();
407 return true;
408 }
409 return false;
410}
411
412unsigned parseValue(const char *Value) {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000413 unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
414#define SANITIZER(NAME, ID) .Case(NAME, ID)
Peter Collingbourne32701642013-11-01 18:16:25 +0000415#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
Alexey Samsonovcf055962013-08-08 10:11:02 +0000416#include "clang/Basic/Sanitizers.def"
417 .Default(SanitizeKind());
Alexey Samsonovcf055962013-08-08 10:11:02 +0000418 return ParsedKind;
419}
420
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000421unsigned expandGroups(unsigned Kinds) {
Peter Collingbourne32701642013-11-01 18:16:25 +0000422#define SANITIZER(NAME, ID)
423#define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID;
424#include "clang/Basic/Sanitizers.def"
425 return Kinds;
426}
427
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000428unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
429 bool DiagnoseErrors) {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000430 unsigned Kind = 0;
431 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000432 if (unsigned K = parseValue(A->getValue(I)))
Alexey Samsonovcf055962013-08-08 10:11:02 +0000433 Kind |= K;
434 else if (DiagnoseErrors)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000435 D.Diag(clang::diag::err_drv_unsupported_option_argument)
Alexey Samsonovcf055962013-08-08 10:11:02 +0000436 << A->getOption().getName() << A->getValue(I);
437 }
438 return Kind;
439}
440
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000441bool parseArgument(const Driver &D, const llvm::opt::Arg *A, unsigned &Add,
442 unsigned &Remove, bool DiagnoseErrors) {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000443 Add = 0;
444 Remove = 0;
Alexey Samsonove1237992014-03-21 07:15:47 +0000445 if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000446 Add = parseArgValues(D, A, DiagnoseErrors);
447 return true;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000448 }
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000449 if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
450 Remove = parseArgValues(D, A, DiagnoseErrors);
451 return true;
452 }
453 return false;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000454}
455
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000456std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
457 unsigned Mask) {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000458 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
459 E = Args.rend();
460 I != E; ++I) {
461 unsigned Add, Remove;
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000462 if (parseArgument(D, *I, Add, Remove, false) &&
463 (expandGroups(Add) & Mask))
464 return describeSanitizeArg(*I, Mask);
465 Mask &= ~Remove;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000466 }
467 llvm_unreachable("arg list didn't provide expected value");
468}
469
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000470std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask) {
471 assert(A->getOption().matches(options::OPT_fsanitize_EQ)
472 && "Invalid argument in describeSanitizerArg!");
Alexey Samsonovcf055962013-08-08 10:11:02 +0000473
Peter Collingbourne32701642013-11-01 18:16:25 +0000474 std::string Sanitizers;
475 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000476 if (expandGroups(parseValue(A->getValue(I))) & Mask) {
Peter Collingbourne32701642013-11-01 18:16:25 +0000477 if (!Sanitizers.empty())
478 Sanitizers += ",";
479 Sanitizers += A->getValue(I);
480 }
481 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000482
Peter Collingbourne32701642013-11-01 18:16:25 +0000483 assert(!Sanitizers.empty() && "arg didn't provide expected value");
484 return "-fsanitize=" + Sanitizers;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000485}