blob: 09c2cb05f4f29b9bd83cc36bda8f529cc635e759 [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,
Kostya Serebryany2d88f3d2015-01-06 01:02:48 +000046 NeedsUnwindTables = Address | Thread | Memory | DataFlow,
47 SupportsCoverage = Address | Memory | Leak | Undefined | Integer
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +000048};
49}
50
51/// Returns true if set of \p Sanitizers contain at least one sanitizer from
52/// \p Kinds.
53static bool hasOneOf(const clang::SanitizerSet &Sanitizers, unsigned Kinds) {
54#define SANITIZER(NAME, ID) \
55 if (Sanitizers.has(clang::SanitizerKind::ID) && (Kinds & ID)) \
56 return true;
57#include "clang/Basic/Sanitizers.def"
58 return false;
59}
60
61/// Adds all sanitizers from \p Kinds to \p Sanitizers.
62static void addAllOf(clang::SanitizerSet &Sanitizers, unsigned Kinds) {
63#define SANITIZER(NAME, ID) \
64 if (Kinds & ID) \
65 Sanitizers.set(clang::SanitizerKind::ID, true);
66#include "clang/Basic/Sanitizers.def"
67}
68
69static unsigned toSanitizeKind(clang::SanitizerKind K) {
70#define SANITIZER(NAME, ID) \
71 if (K == clang::SanitizerKind::ID) \
72 return ID;
73#include "clang/Basic/Sanitizers.def"
74 llvm_unreachable("Invalid SanitizerKind!");
75}
76
77/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
78/// Returns a member of the \c SanitizeKind enumeration, or \c 0
79/// if \p Value is not known.
80static unsigned parseValue(const char *Value);
81
82/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
83/// invalid components. Returns OR of members of \c SanitizeKind enumeration.
84static unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
85 bool DiagnoseErrors);
86
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +000087/// Produce an argument string from ArgList \p Args, which shows how it
88/// provides some sanitizer kind from \p Mask. For example, the argument list
89/// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
90/// would produce "-fsanitize=vptr".
91static std::string lastArgumentForMask(const Driver &D,
92 const llvm::opt::ArgList &Args,
93 unsigned Mask);
94
95static std::string lastArgumentForKind(const Driver &D,
96 const llvm::opt::ArgList &Args,
97 clang::SanitizerKind K) {
98 return lastArgumentForMask(D, Args, toSanitizeKind(K));
99}
100
101/// Produce an argument string from argument \p A, which shows how it provides
102/// a value in \p Mask. For instance, the argument
103/// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
104/// "-fsanitize=alignment".
105static std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask);
106
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000107/// Produce a string containing comma-separated names of sanitizers in \p
108/// Sanitizers set.
109static std::string toString(const clang::SanitizerSet &Sanitizers);
110
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000111/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
112/// this group enables.
113static unsigned expandGroups(unsigned Kinds);
114
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000115static unsigned getToolchainUnsupportedKinds(const ToolChain &TC) {
116 bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD;
117 bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
118 bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
119 bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64;
120
121 unsigned Unsupported = 0;
122 if (!(IsLinux && IsX86_64)) {
123 Unsupported |= Memory | DataFlow;
124 }
125 if (!((IsLinux || IsFreeBSD) && IsX86_64)) {
126 Unsupported |= Thread;
127 }
128 if (!(IsLinux && (IsX86 || IsX86_64))) {
129 Unsupported |= Function;
130 }
131 return Unsupported;
132}
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000133
134bool SanitizerArgs::needsUbsanRt() const {
135 return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt);
136}
137
Dmitry Vyukov43419a72014-11-21 12:19:01 +0000138bool SanitizerArgs::requiresPIE() const {
139 return AsanZeroBaseShadow || hasOneOf(Sanitizers, RequiresPIE);
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000140}
141
142bool SanitizerArgs::needsUnwindTables() const {
143 return hasOneOf(Sanitizers, NeedsUnwindTables);
144}
145
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000146void SanitizerArgs::clear() {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000147 Sanitizers.clear();
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000148 SanitizeRecover = false;
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000149 BlacklistFile = "";
Kostya Serebryany75b4f9e2014-11-11 22:15:07 +0000150 SanitizeCoverage = 0;
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000151 MsanTrackOrigins = 0;
Kostya Serebryanyaed71a82014-10-09 17:53:04 +0000152 AsanFieldPadding = 0;
Peter Collingbourne32701642013-11-01 18:16:25 +0000153 AsanZeroBaseShadow = false;
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000154 UbsanTrapOnError = false;
Alexey Samsonovbdfa6c22014-04-01 13:31:10 +0000155 AsanSharedRuntime = false;
Alexey Samsonov90490af2014-08-08 22:47:17 +0000156 LinkCXXRuntimes = false;
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000157}
Alexey Samsonovcf055962013-08-08 10:11:02 +0000158
Peter Collingbourne32701642013-11-01 18:16:25 +0000159SanitizerArgs::SanitizerArgs(const ToolChain &TC,
160 const llvm::opt::ArgList &Args) {
Alexey Samsonovbb14f342013-08-08 11:32:17 +0000161 clear();
Peter Collingbourne32701642013-11-01 18:16:25 +0000162 unsigned AllRemove = 0; // During the loop below, the accumulated set of
163 // sanitizers disabled by the current sanitizer
164 // argument or any argument after it.
165 unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
166 // Used to deduplicate diagnostics.
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000167 unsigned Kinds = 0;
168 unsigned NotSupported = getToolchainUnsupportedKinds(TC);
Peter Collingbourne32701642013-11-01 18:16:25 +0000169 const Driver &D = TC.getDriver();
170 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
171 I != E; ++I) {
Alexey Samsonov799f7932014-12-19 02:35:16 +0000172 const auto *Arg = *I;
173 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
174 Arg->claim();
175 unsigned Add = parseArgValues(D, Arg, true);
Peter Collingbourne32701642013-11-01 18:16:25 +0000176
Alexey Samsonov799f7932014-12-19 02:35:16 +0000177 // Avoid diagnosing any sanitizer which is disabled later.
178 Add &= ~AllRemove;
179 // At this point we have not expanded groups, so any unsupported
180 // sanitizers in Add are those which have been explicitly enabled.
181 // Diagnose them.
182 if (unsigned KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) {
183 // Only diagnose the new kinds.
184 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
185 D.Diag(diag::err_drv_unsupported_opt_for_target)
186 << Desc << TC.getTriple().str();
187 DiagnosedKinds |= KindsToDiagnose;
188 }
189 Add &= ~NotSupported;
Peter Collingbourne32701642013-11-01 18:16:25 +0000190
Alexey Samsonov799f7932014-12-19 02:35:16 +0000191 Add = expandGroups(Add);
192 // Group expansion may have enabled a sanitizer which is disabled later.
193 Add &= ~AllRemove;
194 // Silently discard any unsupported sanitizers implicitly enabled through
195 // group expansion.
196 Add &= ~NotSupported;
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000197
Alexey Samsonov799f7932014-12-19 02:35:16 +0000198 Kinds |= Add;
199 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
200 Arg->claim();
201 unsigned Remove = parseArgValues(D, Arg, true);
202 AllRemove |= expandGroups(Remove);
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000203 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000204 }
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000205 addAllOf(Sanitizers, Kinds);
206
207 SanitizeRecover = Args.hasFlag(options::OPT_fsanitize_recover,
208 options::OPT_fno_sanitize_recover, true);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000209
210 UbsanTrapOnError =
Alexey Samsonovcf055962013-08-08 10:11:02 +0000211 Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
212 options::OPT_fno_sanitize_undefined_trap_on_error, false);
213
Alexey Samsonovcf055962013-08-08 10:11:02 +0000214 // Warn about undefined sanitizer options that require runtime support.
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000215 if (UbsanTrapOnError && hasOneOf(Sanitizers, NotAllowedWithTrap)) {
216 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
217 << lastArgumentForMask(D, Args, NotAllowedWithTrap)
Alexey Samsonovcb3f8122014-03-20 10:48:29 +0000218 << "-fsanitize-undefined-trap-on-error";
Alexey Samsonovcf055962013-08-08 10:11:02 +0000219 }
220
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000221 // Check for incompatible sanitizers.
222 bool NeedsAsan = Sanitizers.has(SanitizerKind::Address);
223 bool NeedsTsan = Sanitizers.has(SanitizerKind::Thread);
224 bool NeedsMsan = Sanitizers.has(SanitizerKind::Memory);
225 bool NeedsLsan = Sanitizers.has(SanitizerKind::Leak);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000226 if (NeedsAsan && NeedsTsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000227 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
228 << lastArgumentForKind(D, Args, SanitizerKind::Address)
229 << lastArgumentForKind(D, Args, SanitizerKind::Thread);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000230 if (NeedsAsan && NeedsMsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000231 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
232 << lastArgumentForKind(D, Args, SanitizerKind::Address)
233 << lastArgumentForKind(D, Args, SanitizerKind::Memory);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000234 if (NeedsTsan && NeedsMsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000235 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
236 << lastArgumentForKind(D, Args, SanitizerKind::Thread)
237 << lastArgumentForKind(D, Args, SanitizerKind::Memory);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000238 if (NeedsLsan && NeedsTsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000239 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
240 << lastArgumentForKind(D, Args, SanitizerKind::Leak)
241 << lastArgumentForKind(D, Args, SanitizerKind::Thread);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000242 if (NeedsLsan && NeedsMsan)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000243 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
244 << lastArgumentForKind(D, Args, SanitizerKind::Leak)
245 << lastArgumentForKind(D, Args, SanitizerKind::Memory);
Alp Tokerf6a24ce2013-12-05 16:25:25 +0000246 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
Alexey Samsonovcf055962013-08-08 10:11:02 +0000247 // -fsanitize=address. Perhaps it should print an error, or perhaps
248 // -f(-no)sanitize=leak should change whether leak detection is enabled by
249 // default in ASan?
250
Alexey Samsonovcf055962013-08-08 10:11:02 +0000251 // Parse -f(no-)sanitize-blacklist options.
252 if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist,
253 options::OPT_fno_sanitize_blacklist)) {
254 if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) {
255 std::string BLPath = BLArg->getValue();
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000256 if (llvm::sys::fs::exists(BLPath)) {
257 // Validate the blacklist format.
258 std::string BLError;
Ahmed Charlesb8984322014-03-07 20:03:18 +0000259 std::unique_ptr<llvm::SpecialCaseList> SCL(
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000260 llvm::SpecialCaseList::create(BLPath, BLError));
261 if (!SCL.get())
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000262 D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000263 else
264 BlacklistFile = BLPath;
265 } else {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000266 D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000267 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000268 }
269 } else {
270 // If no -fsanitize-blacklist option is specified, try to look up for
271 // blacklist in the resource directory.
272 std::string BLPath;
Alexey Samsonov59f34bb2014-11-14 00:46:39 +0000273 if (getDefaultBlacklist(D, BLPath) && llvm::sys::fs::exists(BLPath))
Alexey Samsonovcf055962013-08-08 10:11:02 +0000274 BlacklistFile = BLPath;
275 }
276
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000277 // Parse -f[no-]sanitize-memory-track-origins[=level] options.
278 if (NeedsMsan) {
279 if (Arg *A =
280 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
281 options::OPT_fsanitize_memory_track_origins,
282 options::OPT_fno_sanitize_memory_track_origins)) {
283 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
284 MsanTrackOrigins = 1;
285 } else if (A->getOption().matches(
286 options::OPT_fno_sanitize_memory_track_origins)) {
287 MsanTrackOrigins = 0;
288 } else {
289 StringRef S = A->getValue();
290 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
291 MsanTrackOrigins > 2) {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000292 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000293 }
294 }
295 }
296 }
297
Kostya Serebryany78df9d02014-12-17 21:46:33 +0000298 // Parse -fsanitize-coverage=N. Currently one of asan/msan/lsan is required.
Kostya Serebryany2d88f3d2015-01-06 01:02:48 +0000299 if (hasOneOf(Sanitizers, SupportsCoverage)) {
Kostya Serebryany75b4f9e2014-11-11 22:15:07 +0000300 if (Arg *A = Args.getLastArg(options::OPT_fsanitize_coverage)) {
301 StringRef S = A->getValue();
302 // Legal values are 0..4.
303 if (S.getAsInteger(0, SanitizeCoverage) || SanitizeCoverage < 0 ||
304 SanitizeCoverage > 4)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000305 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
Kostya Serebryany75b4f9e2014-11-11 22:15:07 +0000306 }
307 }
308
Alexey Samsonovbdfa6c22014-04-01 13:31:10 +0000309 if (NeedsAsan) {
310 AsanSharedRuntime =
Evgeniy Stepanov6f0ae182014-06-05 11:14:00 +0000311 Args.hasArg(options::OPT_shared_libasan) ||
312 (TC.getTriple().getEnvironment() == llvm::Triple::Android);
Peter Collingbourne32701642013-11-01 18:16:25 +0000313 AsanZeroBaseShadow =
Evgeniy Stepanovd04b8612014-01-16 10:19:31 +0000314 (TC.getTriple().getEnvironment() == llvm::Triple::Android);
Kostya Serebryanyaed71a82014-10-09 17:53:04 +0000315 if (Arg *A =
316 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
317 StringRef S = A->getValue();
318 // Legal values are 0 and 1, 2, but in future we may add more levels.
319 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
320 AsanFieldPadding > 2) {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000321 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
Kostya Serebryanyaed71a82014-10-09 17:53:04 +0000322 }
323 }
Ehsan Akhgarie0db1962014-10-14 23:15:44 +0000324
325 if (Arg *WindowsDebugRTArg =
326 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
327 options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
328 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
329 switch (WindowsDebugRTArg->getOption().getID()) {
330 case options::OPT__SLASH_MTd:
331 case options::OPT__SLASH_MDd:
332 case options::OPT__SLASH_LDd:
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000333 D.Diag(clang::diag::err_drv_argument_not_allowed_with)
Ehsan Akhgarie0db1962014-10-14 23:15:44 +0000334 << WindowsDebugRTArg->getAsString(Args)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000335 << lastArgumentForKind(D, Args, SanitizerKind::Address);
336 D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
Ehsan Akhgarie0db1962014-10-14 23:15:44 +0000337 }
338 }
Alexey Samsonovbdfa6c22014-04-01 13:31:10 +0000339 }
Alexey Samsonov90490af2014-08-08 22:47:17 +0000340
341 // Parse -link-cxx-sanitizer flag.
342 LinkCXXRuntimes =
343 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
Alexey Samsonovcf055962013-08-08 10:11:02 +0000344}
345
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000346static std::string toString(const clang::SanitizerSet &Sanitizers) {
347 std::string Res;
348#define SANITIZER(NAME, ID) \
349 if (Sanitizers.has(clang::SanitizerKind::ID)) { \
350 if (!Res.empty()) \
351 Res += ","; \
352 Res += NAME; \
353 }
354#include "clang/Basic/Sanitizers.def"
355 return Res;
356}
357
Peter Collingbourne32701642013-11-01 18:16:25 +0000358void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
Alexey Samsonovcf055962013-08-08 10:11:02 +0000359 llvm::opt::ArgStringList &CmdArgs) const {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000360 if (Sanitizers.empty())
Alexey Samsonovcf055962013-08-08 10:11:02 +0000361 return;
Alexey Samsonov1e715a62014-11-16 20:53:53 +0000362 CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
363
364 if (!SanitizeRecover)
365 CmdArgs.push_back("-fno-sanitize-recover");
366
367 if (UbsanTrapOnError)
368 CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
369
Alexey Samsonovcf055962013-08-08 10:11:02 +0000370 if (!BlacklistFile.empty()) {
371 SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
372 BlacklistOpt += BlacklistFile;
373 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
374 }
375
376 if (MsanTrackOrigins)
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000377 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
378 llvm::utostr(MsanTrackOrigins)));
Kostya Serebryanyaed71a82014-10-09 17:53:04 +0000379 if (AsanFieldPadding)
380 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
381 llvm::utostr(AsanFieldPadding)));
Kostya Serebryany75b4f9e2014-11-11 22:15:07 +0000382 if (SanitizeCoverage)
383 CmdArgs.push_back(Args.MakeArgString("-fsanitize-coverage=" +
384 llvm::utostr(SanitizeCoverage)));
Alexey Samsonovcf055962013-08-08 10:11:02 +0000385 // Workaround for PR16386.
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000386 if (Sanitizers.has(SanitizerKind::Memory))
Alexey Samsonovcf055962013-08-08 10:11:02 +0000387 CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
388}
389
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000390bool SanitizerArgs::getDefaultBlacklist(const Driver &D, std::string &BLPath) {
391 const char *BlacklistFile = nullptr;
392 if (Sanitizers.has(SanitizerKind::Address))
393 BlacklistFile = "asan_blacklist.txt";
394 else if (Sanitizers.has(SanitizerKind::Memory))
395 BlacklistFile = "msan_blacklist.txt";
396 else if (Sanitizers.has(SanitizerKind::Thread))
397 BlacklistFile = "tsan_blacklist.txt";
398 else if (Sanitizers.has(SanitizerKind::DataFlow))
399 BlacklistFile = "dfsan_abilist.txt";
400
401 if (BlacklistFile) {
402 SmallString<64> Path(D.ResourceDir);
403 llvm::sys::path::append(Path, BlacklistFile);
404 BLPath = Path.str();
405 return true;
406 }
407 return false;
408}
409
410unsigned parseValue(const char *Value) {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000411 unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
412#define SANITIZER(NAME, ID) .Case(NAME, ID)
Peter Collingbourne32701642013-11-01 18:16:25 +0000413#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
Alexey Samsonovcf055962013-08-08 10:11:02 +0000414#include "clang/Basic/Sanitizers.def"
415 .Default(SanitizeKind());
Alexey Samsonovcf055962013-08-08 10:11:02 +0000416 return ParsedKind;
417}
418
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000419unsigned expandGroups(unsigned Kinds) {
Peter Collingbourne32701642013-11-01 18:16:25 +0000420#define SANITIZER(NAME, ID)
421#define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID;
422#include "clang/Basic/Sanitizers.def"
423 return Kinds;
424}
425
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000426unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
427 bool DiagnoseErrors) {
Alexey Samsonov799f7932014-12-19 02:35:16 +0000428 assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
429 A->getOption().matches(options::OPT_fno_sanitize_EQ)) &&
430 "Invalid argument in parseArgValues!");
Alexey Samsonovabd5bea2014-12-19 18:41:43 +0000431 unsigned Kinds = 0;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000432 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
Alexey Samsonovabd5bea2014-12-19 18:41:43 +0000433 const char *Value = A->getValue(I);
434 unsigned Kind;
435 // Special case: don't accept -fsanitize=all.
436 if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
437 0 == strcmp("all", Value))
438 Kind = 0;
439 else
440 Kind = parseValue(Value);
441
442 if (Kind)
443 Kinds |= Kind;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000444 else if (DiagnoseErrors)
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000445 D.Diag(clang::diag::err_drv_unsupported_option_argument)
Alexey Samsonovabd5bea2014-12-19 18:41:43 +0000446 << A->getOption().getName() << Value;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000447 }
Alexey Samsonovabd5bea2014-12-19 18:41:43 +0000448 return Kinds;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000449}
450
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000451std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
452 unsigned Mask) {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000453 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
454 E = Args.rend();
455 I != E; ++I) {
Alexey Samsonov799f7932014-12-19 02:35:16 +0000456 const auto *Arg = *I;
457 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
458 unsigned AddKinds = expandGroups(parseArgValues(D, Arg, false));
459 if (AddKinds & Mask)
460 return describeSanitizeArg(Arg, Mask);
461 } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
462 unsigned RemoveKinds = expandGroups(parseArgValues(D, Arg, false));
463 Mask &= ~RemoveKinds;
464 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000465 }
466 llvm_unreachable("arg list didn't provide expected value");
467}
468
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000469std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask) {
470 assert(A->getOption().matches(options::OPT_fsanitize_EQ)
471 && "Invalid argument in describeSanitizerArg!");
Alexey Samsonovcf055962013-08-08 10:11:02 +0000472
Peter Collingbourne32701642013-11-01 18:16:25 +0000473 std::string Sanitizers;
474 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
Alexey Samsonov4c12c6c2014-11-14 02:59:20 +0000475 if (expandGroups(parseValue(A->getValue(I))) & Mask) {
Peter Collingbourne32701642013-11-01 18:16:25 +0000476 if (!Sanitizers.empty())
477 Sanitizers += ",";
478 Sanitizers += A->getValue(I);
479 }
480 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000481
Peter Collingbourne32701642013-11-01 18:16:25 +0000482 assert(!Sanitizers.empty() && "arg didn't provide expected value");
483 return "-fsanitize=" + Sanitizers;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000484}