]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.h
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / llvm / tools / clang / lib / Driver / SanitizerArgs.h
1 //===--- SanitizerArgs.h - Arguments for sanitizer tools  -------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
9 #ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_
10 #define CLANG_LIB_DRIVER_SANITIZERARGS_H_
11
12 #include "clang/Driver/Arg.h"
13 #include "clang/Driver/ArgList.h"
14 #include "clang/Driver/Driver.h"
15 #include "clang/Driver/DriverDiagnostic.h"
16 #include "clang/Driver/Options.h"
17 #include "llvm/ADT/StringSwitch.h"
18 #include "llvm/Support/Path.h"
19
20 namespace clang {
21 namespace driver {
22
23 class SanitizerArgs {
24   /// Assign ordinals to sanitizer flags. We'll use the ordinal values as
25   /// bit positions within \c Kind.
26   enum SanitizeOrdinal {
27 #define SANITIZER(NAME, ID) SO_##ID,
28 #include "clang/Basic/Sanitizers.def"
29     SO_Count
30   };
31
32   /// Bugs to catch at runtime.
33   enum SanitizeKind {
34 #define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
35 #define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS,
36 #include "clang/Basic/Sanitizers.def"
37     NeedsAsanRt = Address,
38     NeedsTsanRt = Thread,
39     NeedsMsanRt = Memory,
40     NeedsUbsanRt = Undefined | Integer,
41     NotAllowedWithTrap = Vptr,
42     HasZeroBaseShadow = Thread | Memory
43   };
44   unsigned Kind;
45   std::string BlacklistFile;
46   bool MsanTrackOrigins;
47   bool AsanZeroBaseShadow;
48   bool UbsanTrapOnError;
49
50  public:
51   SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false),
52                     AsanZeroBaseShadow(false), UbsanTrapOnError(false) {}
53   /// Parses the sanitizer arguments from an argument list.
54   SanitizerArgs(const ToolChain &TC, const ArgList &Args);
55
56   bool needsAsanRt() const { return Kind & NeedsAsanRt; }
57   bool needsTsanRt() const { return Kind & NeedsTsanRt; }
58   bool needsMsanRt() const { return Kind & NeedsMsanRt; }
59   bool needsUbsanRt() const {
60     if (UbsanTrapOnError)
61       return false;
62     return Kind & NeedsUbsanRt;
63   }
64
65   bool sanitizesVptr() const { return Kind & Vptr; }
66   bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; }
67   bool hasZeroBaseShadow() const {
68     return (Kind & HasZeroBaseShadow) || AsanZeroBaseShadow;
69   }
70
71   void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
72     if (!Kind)
73       return;
74     SmallString<256> SanitizeOpt("-fsanitize=");
75 #define SANITIZER(NAME, ID) \
76     if (Kind & ID) \
77       SanitizeOpt += NAME ",";
78 #include "clang/Basic/Sanitizers.def"
79     SanitizeOpt.pop_back();
80     CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
81     if (!BlacklistFile.empty()) {
82       SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
83       BlacklistOpt += BlacklistFile;
84       CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
85     }
86
87     if (MsanTrackOrigins)
88       CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins"));
89
90     if (AsanZeroBaseShadow)
91       CmdArgs.push_back(Args.MakeArgString(
92           "-fsanitize-address-zero-base-shadow"));
93   }
94
95  private:
96   /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
97   /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0
98   /// if \p Value is not known.
99   static unsigned parse(const char *Value) {
100     unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
101 #define SANITIZER(NAME, ID) .Case(NAME, ID)
102 #define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID)
103 #include "clang/Basic/Sanitizers.def"
104       .Default(SanitizeKind());
105     // Assume -fsanitize=address implies -fsanitize=init-order.
106     // FIXME: This should be either specified in Sanitizers.def, or go away when
107     // we get rid of "-fsanitize=init-order" flag at all.
108     if (ParsedKind & Address)
109       ParsedKind |= InitOrder;
110     return ParsedKind;
111   }
112
113   /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
114   /// invalid components.
115   static unsigned parse(const Driver &D, const Arg *A, bool DiagnoseErrors) {
116     unsigned Kind = 0;
117     for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
118       if (unsigned K = parse(A->getValue(I)))
119         Kind |= K;
120       else if (DiagnoseErrors)
121         D.Diag(diag::err_drv_unsupported_option_argument)
122           << A->getOption().getName() << A->getValue(I);
123     }
124     return Kind;
125   }
126
127   /// Parse a single flag of the form -f[no]sanitize=, or
128   /// -f*-sanitizer. Sets the masks defining required change of Kind value.
129   /// Returns true if the flag was parsed successfully.
130   static bool parse(const Driver &D, const ArgList &Args, const Arg *A,
131                     unsigned &Add, unsigned &Remove, bool DiagnoseErrors) {
132     Add = 0;
133     Remove = 0;
134     const char *DeprecatedReplacement = 0;
135     if (A->getOption().matches(options::OPT_faddress_sanitizer)) {
136       Add = Address;
137       DeprecatedReplacement = "-fsanitize=address";
138     } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) {
139       Remove = Address;
140       DeprecatedReplacement = "-fno-sanitize=address";
141     } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) {
142       Add = Thread;
143       DeprecatedReplacement = "-fsanitize=thread";
144     } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) {
145       Remove = Thread;
146       DeprecatedReplacement = "-fno-sanitize=thread";
147     } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
148       Add = UndefinedTrap;
149       DeprecatedReplacement = 
150         "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error";
151     } else if (A->getOption().matches(options::OPT_fbounds_checking) ||
152                A->getOption().matches(options::OPT_fbounds_checking_EQ)) {
153       Add = Bounds;
154       DeprecatedReplacement = "-fsanitize=bounds";
155     } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
156       Add = parse(D, A, DiagnoseErrors);
157     } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
158       Remove = parse(D, A, DiagnoseErrors);
159     } else {
160       // Flag is not relevant to sanitizers.
161       return false;
162     }
163     // If this is a deprecated synonym, produce a warning directing users
164     // towards the new spelling.
165     if (DeprecatedReplacement && DiagnoseErrors)
166       D.Diag(diag::warn_drv_deprecated_arg)
167         << A->getAsString(Args) << DeprecatedReplacement;
168     return true;
169   }
170
171   /// Produce an argument string from ArgList \p Args, which shows how it
172   /// provides a sanitizer kind in \p Mask. For example, the argument list
173   /// "-fsanitize=thread,vptr -faddress-sanitizer" with mask \c NeedsUbsanRt
174   /// would produce "-fsanitize=vptr".
175   static std::string lastArgumentForKind(const Driver &D, const ArgList &Args,
176                                          unsigned Kind) {
177     for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
178          I != E; ++I) {
179       unsigned Add, Remove;
180       if (parse(D, Args, *I, Add, Remove, false) &&
181           (Add & Kind))
182         return describeSanitizeArg(Args, *I, Kind);
183       Kind &= ~Remove;
184     }
185     llvm_unreachable("arg list didn't provide expected value");
186   }
187
188   /// Produce an argument string from argument \p A, which shows how it provides
189   /// a value in \p Mask. For instance, the argument
190   /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
191   /// "-fsanitize=alignment".
192   static std::string describeSanitizeArg(const ArgList &Args, const Arg *A,
193                                          unsigned Mask) {
194     if (!A->getOption().matches(options::OPT_fsanitize_EQ))
195       return A->getAsString(Args);
196
197     for (unsigned I = 0, N = A->getNumValues(); I != N; ++I)
198       if (parse(A->getValue(I)) & Mask)
199         return std::string("-fsanitize=") + A->getValue(I);
200
201     llvm_unreachable("arg didn't provide expected value");
202   }
203
204   static bool getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
205                                          std::string &BLPath) {
206     // For now, specify the default blacklist location for ASan only.
207     if (Kind & NeedsAsanRt) {
208       SmallString<64> Path(D.ResourceDir);
209       llvm::sys::path::append(Path, "asan_blacklist.txt");
210       BLPath = Path.str();
211       return true;
212     }
213     return false;
214   }
215 };
216
217 }  // namespace driver
218 }  // namespace clang
219
220 #endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_