blob: 502cec7d3f730339ee4b4910192356a09ad71b9a [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 Samsonov0c127d72013-08-19 13:59:22 +000018#include "llvm/Transforms/Utils/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 Samsonovbb14f342013-08-08 11:32:17 +000024void SanitizerArgs::clear() {
25 Kind = 0;
26 BlacklistFile = "";
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +000027 MsanTrackOrigins = 0;
Peter Collingbourne32701642013-11-01 18:16:25 +000028 AsanZeroBaseShadow = false;
Alexey Samsonovbb14f342013-08-08 11:32:17 +000029 UbsanTrapOnError = false;
30}
31
32SanitizerArgs::SanitizerArgs() {
33 clear();
34}
Alexey Samsonovcf055962013-08-08 10:11:02 +000035
Peter Collingbourne32701642013-11-01 18:16:25 +000036SanitizerArgs::SanitizerArgs(const ToolChain &TC,
37 const llvm::opt::ArgList &Args) {
Alexey Samsonovbb14f342013-08-08 11:32:17 +000038 clear();
Peter Collingbourne32701642013-11-01 18:16:25 +000039 unsigned AllAdd = 0; // All kinds of sanitizers that were turned on
40 // at least once (possibly, disabled further).
41 unsigned AllRemove = 0; // During the loop below, the accumulated set of
42 // sanitizers disabled by the current sanitizer
43 // argument or any argument after it.
44 unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
45 // Used to deduplicate diagnostics.
46 const Driver &D = TC.getDriver();
47 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
48 I != E; ++I) {
Alexey Samsonovcf055962013-08-08 10:11:02 +000049 unsigned Add, Remove;
50 if (!parse(D, Args, *I, Add, Remove, true))
51 continue;
52 (*I)->claim();
Peter Collingbourne32701642013-11-01 18:16:25 +000053
54 AllAdd |= expandGroups(Add);
55 AllRemove |= expandGroups(Remove);
56
57 // Avoid diagnosing any sanitizer which is disabled later.
58 Add &= ~AllRemove;
59 // At this point we have not expanded groups, so any unsupported sanitizers
60 // in Add are those which have been explicitly enabled. Diagnose them.
61 Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/true,
62 DiagnosedKinds);
63 Add = expandGroups(Add);
64 // Group expansion may have enabled a sanitizer which is disabled later.
65 Add &= ~AllRemove;
66 // Silently discard any unsupported sanitizers implicitly enabled through
67 // group expansion.
68 Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/false,
69 DiagnosedKinds);
70
Alexey Samsonovcf055962013-08-08 10:11:02 +000071 Kind |= Add;
Alexey Samsonovcf055962013-08-08 10:11:02 +000072 }
73
74 UbsanTrapOnError =
Alexey Samsonovcf055962013-08-08 10:11:02 +000075 Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
76 options::OPT_fno_sanitize_undefined_trap_on_error, false);
77
Alexey Samsonovcf055962013-08-08 10:11:02 +000078 // Warn about undefined sanitizer options that require runtime support.
79 if (UbsanTrapOnError && notAllowedWithTrap()) {
Alexey Samsonovcb3f8122014-03-20 10:48:29 +000080 D.Diag(diag::err_drv_argument_not_allowed_with)
81 << lastArgumentForKind(D, Args, NotAllowedWithTrap)
82 << "-fsanitize-undefined-trap-on-error";
Alexey Samsonovcf055962013-08-08 10:11:02 +000083 }
84
85 // Only one runtime library can be used at once.
86 bool NeedsAsan = needsAsanRt();
87 bool NeedsTsan = needsTsanRt();
88 bool NeedsMsan = needsMsanRt();
89 bool NeedsLsan = needsLeakDetection();
90 if (NeedsAsan && NeedsTsan)
91 D.Diag(diag::err_drv_argument_not_allowed_with)
92 << lastArgumentForKind(D, Args, NeedsAsanRt)
93 << lastArgumentForKind(D, Args, NeedsTsanRt);
94 if (NeedsAsan && NeedsMsan)
95 D.Diag(diag::err_drv_argument_not_allowed_with)
96 << lastArgumentForKind(D, Args, NeedsAsanRt)
97 << lastArgumentForKind(D, Args, NeedsMsanRt);
98 if (NeedsTsan && NeedsMsan)
99 D.Diag(diag::err_drv_argument_not_allowed_with)
100 << lastArgumentForKind(D, Args, NeedsTsanRt)
101 << lastArgumentForKind(D, Args, NeedsMsanRt);
102 if (NeedsLsan && NeedsTsan)
103 D.Diag(diag::err_drv_argument_not_allowed_with)
104 << lastArgumentForKind(D, Args, NeedsLeakDetection)
105 << lastArgumentForKind(D, Args, NeedsTsanRt);
106 if (NeedsLsan && NeedsMsan)
107 D.Diag(diag::err_drv_argument_not_allowed_with)
108 << lastArgumentForKind(D, Args, NeedsLeakDetection)
109 << lastArgumentForKind(D, Args, NeedsMsanRt);
Alp Tokerf6a24ce2013-12-05 16:25:25 +0000110 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
Alexey Samsonovcf055962013-08-08 10:11:02 +0000111 // -fsanitize=address. Perhaps it should print an error, or perhaps
112 // -f(-no)sanitize=leak should change whether leak detection is enabled by
113 // default in ASan?
114
115 // If -fsanitize contains extra features of ASan, it should also
116 // explicitly contain -fsanitize=address (probably, turned off later in the
117 // command line).
Peter Collingbourne32701642013-11-01 18:16:25 +0000118 if ((Kind & AddressFull) != 0 && (AllAdd & Address) == 0)
Alexey Samsonovcf055962013-08-08 10:11:02 +0000119 D.Diag(diag::warn_drv_unused_sanitizer)
120 << lastArgumentForKind(D, Args, AddressFull)
121 << "-fsanitize=address";
122
123 // Parse -f(no-)sanitize-blacklist options.
124 if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist,
125 options::OPT_fno_sanitize_blacklist)) {
126 if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) {
127 std::string BLPath = BLArg->getValue();
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000128 if (llvm::sys::fs::exists(BLPath)) {
129 // Validate the blacklist format.
130 std::string BLError;
Ahmed Charlesb8984322014-03-07 20:03:18 +0000131 std::unique_ptr<llvm::SpecialCaseList> SCL(
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000132 llvm::SpecialCaseList::create(BLPath, BLError));
133 if (!SCL.get())
134 D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError;
135 else
136 BlacklistFile = BLPath;
137 } else {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000138 D.Diag(diag::err_drv_no_such_file) << BLPath;
Alexey Samsonov0c127d72013-08-19 13:59:22 +0000139 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000140 }
141 } else {
142 // If no -fsanitize-blacklist option is specified, try to look up for
143 // blacklist in the resource directory.
144 std::string BLPath;
145 if (getDefaultBlacklistForKind(D, Kind, BLPath) &&
146 llvm::sys::fs::exists(BLPath))
147 BlacklistFile = BLPath;
148 }
149
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000150 // Parse -f[no-]sanitize-memory-track-origins[=level] options.
151 if (NeedsMsan) {
152 if (Arg *A =
153 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
154 options::OPT_fsanitize_memory_track_origins,
155 options::OPT_fno_sanitize_memory_track_origins)) {
156 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
157 MsanTrackOrigins = 1;
158 } else if (A->getOption().matches(
159 options::OPT_fno_sanitize_memory_track_origins)) {
160 MsanTrackOrigins = 0;
161 } else {
162 StringRef S = A->getValue();
163 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
164 MsanTrackOrigins > 2) {
165 D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
166 }
167 }
168 }
169 }
170
Evgeniy Stepanovd04b8612014-01-16 10:19:31 +0000171 if (NeedsAsan)
Peter Collingbourne32701642013-11-01 18:16:25 +0000172 AsanZeroBaseShadow =
Evgeniy Stepanovd04b8612014-01-16 10:19:31 +0000173 (TC.getTriple().getEnvironment() == llvm::Triple::Android);
Alexey Samsonovcf055962013-08-08 10:11:02 +0000174}
175
Peter Collingbourne32701642013-11-01 18:16:25 +0000176void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
Alexey Samsonovcf055962013-08-08 10:11:02 +0000177 llvm::opt::ArgStringList &CmdArgs) const {
178 if (!Kind)
179 return;
180 SmallString<256> SanitizeOpt("-fsanitize=");
181#define SANITIZER(NAME, ID) \
182 if (Kind & ID) \
183 SanitizeOpt += NAME ",";
184#include "clang/Basic/Sanitizers.def"
185 SanitizeOpt.pop_back();
186 CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
187 if (!BlacklistFile.empty()) {
188 SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
189 BlacklistOpt += BlacklistFile;
190 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
191 }
192
193 if (MsanTrackOrigins)
Evgeniy Stepanov2bfcaab2014-03-20 14:58:36 +0000194 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
195 llvm::utostr(MsanTrackOrigins)));
Alexey Samsonovcf055962013-08-08 10:11:02 +0000196
Alexey Samsonovcf055962013-08-08 10:11:02 +0000197 // Workaround for PR16386.
198 if (needsMsanRt())
199 CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
200}
201
Alexey Samsonovcf055962013-08-08 10:11:02 +0000202unsigned SanitizerArgs::parse(const char *Value) {
203 unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
204#define SANITIZER(NAME, ID) .Case(NAME, ID)
Peter Collingbourne32701642013-11-01 18:16:25 +0000205#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
Alexey Samsonovcf055962013-08-08 10:11:02 +0000206#include "clang/Basic/Sanitizers.def"
207 .Default(SanitizeKind());
Kostya Serebryanybedc6162013-09-23 09:52:37 +0000208 // Assume -fsanitize=address implies -fsanitize=init-order,use-after-return.
Alexey Samsonovcf055962013-08-08 10:11:02 +0000209 // FIXME: This should be either specified in Sanitizers.def, or go away when
Kostya Serebryanybedc6162013-09-23 09:52:37 +0000210 // we get rid of "-fsanitize=init-order,use-after-return" flags at all.
Alexey Samsonovcf055962013-08-08 10:11:02 +0000211 if (ParsedKind & Address)
Kostya Serebryanybedc6162013-09-23 09:52:37 +0000212 ParsedKind |= InitOrder | UseAfterReturn;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000213 return ParsedKind;
214}
215
Peter Collingbourne32701642013-11-01 18:16:25 +0000216unsigned SanitizerArgs::expandGroups(unsigned Kinds) {
217#define SANITIZER(NAME, ID)
218#define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID;
219#include "clang/Basic/Sanitizers.def"
220 return Kinds;
221}
222
223void SanitizerArgs::filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds,
224 unsigned Mask,
225 const llvm::opt::ArgList &Args,
226 const llvm::opt::Arg *A,
227 bool DiagnoseErrors,
228 unsigned &DiagnosedKinds) {
229 unsigned MaskedKinds = Kinds & Mask;
230 if (!MaskedKinds)
231 return;
232 Kinds &= ~Mask;
233 // Do we have new kinds to diagnose?
234 if (DiagnoseErrors && (DiagnosedKinds & MaskedKinds) != MaskedKinds) {
235 // Only diagnose the new kinds.
236 std::string Desc =
237 describeSanitizeArg(Args, A, MaskedKinds & ~DiagnosedKinds);
238 TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
239 << Desc << TC.getTriple().str();
240 DiagnosedKinds |= MaskedKinds;
241 }
242}
243
244unsigned SanitizerArgs::filterUnsupportedKinds(const ToolChain &TC,
245 unsigned Kinds,
246 const llvm::opt::ArgList &Args,
247 const llvm::opt::Arg *A,
248 bool DiagnoseErrors,
249 unsigned &DiagnosedKinds) {
250 bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
251 bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
252 bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64;
253 if (!(IsLinux && IsX86_64)) {
254 filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A,
255 DiagnoseErrors, DiagnosedKinds);
256 }
257 if (!(IsLinux && (IsX86 || IsX86_64))) {
258 filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors,
259 DiagnosedKinds);
260 }
261 return Kinds;
262}
263
Alexey Samsonovcf055962013-08-08 10:11:02 +0000264unsigned SanitizerArgs::parse(const Driver &D, const llvm::opt::Arg *A,
265 bool DiagnoseErrors) {
266 unsigned Kind = 0;
267 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
268 if (unsigned K = parse(A->getValue(I)))
269 Kind |= K;
270 else if (DiagnoseErrors)
271 D.Diag(diag::err_drv_unsupported_option_argument)
272 << A->getOption().getName() << A->getValue(I);
273 }
274 return Kind;
275}
276
277bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args,
278 const llvm::opt::Arg *A, unsigned &Add,
279 unsigned &Remove, bool DiagnoseErrors) {
280 Add = 0;
281 Remove = 0;
Alexey Samsonove1237992014-03-21 07:15:47 +0000282 if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
Alexey Samsonovcf055962013-08-08 10:11:02 +0000283 Add = parse(D, A, DiagnoseErrors);
284 } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
285 Remove = parse(D, A, DiagnoseErrors);
286 } else {
287 // Flag is not relevant to sanitizers.
288 return false;
289 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000290 return true;
291}
292
293std::string SanitizerArgs::lastArgumentForKind(const Driver &D,
294 const llvm::opt::ArgList &Args,
295 unsigned Kind) {
296 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
297 E = Args.rend();
298 I != E; ++I) {
299 unsigned Add, Remove;
300 if (parse(D, Args, *I, Add, Remove, false) &&
Peter Collingbourne32701642013-11-01 18:16:25 +0000301 (expandGroups(Add) & Kind))
Alexey Samsonovcf055962013-08-08 10:11:02 +0000302 return describeSanitizeArg(Args, *I, Kind);
303 Kind &= ~Remove;
304 }
305 llvm_unreachable("arg list didn't provide expected value");
306}
307
308std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args,
309 const llvm::opt::Arg *A,
310 unsigned Mask) {
311 if (!A->getOption().matches(options::OPT_fsanitize_EQ))
312 return A->getAsString(Args);
313
Peter Collingbourne32701642013-11-01 18:16:25 +0000314 std::string Sanitizers;
315 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
316 if (expandGroups(parse(A->getValue(I))) & Mask) {
317 if (!Sanitizers.empty())
318 Sanitizers += ",";
319 Sanitizers += A->getValue(I);
320 }
321 }
Alexey Samsonovcf055962013-08-08 10:11:02 +0000322
Peter Collingbourne32701642013-11-01 18:16:25 +0000323 assert(!Sanitizers.empty() && "arg didn't provide expected value");
324 return "-fsanitize=" + Sanitizers;
Alexey Samsonovcf055962013-08-08 10:11:02 +0000325}
326
327bool SanitizerArgs::getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
328 std::string &BLPath) {
329 const char *BlacklistFile = 0;
330 if (Kind & NeedsAsanRt)
331 BlacklistFile = "asan_blacklist.txt";
332 else if (Kind & NeedsMsanRt)
333 BlacklistFile = "msan_blacklist.txt";
334 else if (Kind & NeedsTsanRt)
335 BlacklistFile = "tsan_blacklist.txt";
Peter Collingbourne276be3c2013-08-14 18:54:18 +0000336 else if (Kind & NeedsDfsanRt)
337 BlacklistFile = "dfsan_abilist.txt";
338
Alexey Samsonovcf055962013-08-08 10:11:02 +0000339 if (BlacklistFile) {
340 SmallString<64> Path(D.ResourceDir);
341 llvm::sys::path::append(Path, BlacklistFile);
342 BLPath = Path.str();
343 return true;
344 }
345 return false;
346}