1 //===--- 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 //===----------------------------------------------------------------------===// 9 #include "clang/Driver/SanitizerArgs.h" 10 #include "clang/Driver/Driver.h" 11 #include "clang/Driver/DriverDiagnostic.h" 12 #include "clang/Driver/Options.h" 13 #include "clang/Driver/ToolChain.h" 14 #include "llvm/ADT/StringExtras.h" 15 #include "llvm/ADT/StringSwitch.h" 16 #include "llvm/Support/FileSystem.h" 17 #include "llvm/Support/Path.h" 18 #include "llvm/Support/SpecialCaseList.h" 19 #include <memory> 20 21 using namespace clang::driver; 22 using namespace llvm::opt; 23 24 void SanitizerArgs::clear() { 25 Kind = 0; 26 BlacklistFile = ""; 27 MsanTrackOrigins = 0; 28 AsanZeroBaseShadow = false; 29 UbsanTrapOnError = false; 30 AsanSharedRuntime = false; 31 } 32 33 SanitizerArgs::SanitizerArgs() { 34 clear(); 35 } 36 37 SanitizerArgs::SanitizerArgs(const ToolChain &TC, 38 const llvm::opt::ArgList &Args) { 39 clear(); 40 unsigned AllAdd = 0; // All kinds of sanitizers that were turned on 41 // at least once (possibly, disabled further). 42 unsigned AllRemove = 0; // During the loop below, the accumulated set of 43 // sanitizers disabled by the current sanitizer 44 // argument or any argument after it. 45 unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. 46 // Used to deduplicate diagnostics. 47 const Driver &D = TC.getDriver(); 48 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); 49 I != E; ++I) { 50 unsigned Add, Remove; 51 if (!parse(D, Args, *I, Add, Remove, true)) 52 continue; 53 (*I)->claim(); 54 55 AllAdd |= expandGroups(Add); 56 AllRemove |= expandGroups(Remove); 57 58 // Avoid diagnosing any sanitizer which is disabled later. 59 Add &= ~AllRemove; 60 // At this point we have not expanded groups, so any unsupported sanitizers 61 // in Add are those which have been explicitly enabled. Diagnose them. 62 Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/true, 63 DiagnosedKinds); 64 Add = expandGroups(Add); 65 // Group expansion may have enabled a sanitizer which is disabled later. 66 Add &= ~AllRemove; 67 // Silently discard any unsupported sanitizers implicitly enabled through 68 // group expansion. 69 Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/false, 70 DiagnosedKinds); 71 72 Kind |= Add; 73 } 74 75 UbsanTrapOnError = 76 Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, 77 options::OPT_fno_sanitize_undefined_trap_on_error, false); 78 79 // Warn about undefined sanitizer options that require runtime support. 80 if (UbsanTrapOnError && notAllowedWithTrap()) { 81 D.Diag(diag::err_drv_argument_not_allowed_with) 82 << lastArgumentForKind(D, Args, NotAllowedWithTrap) 83 << "-fsanitize-undefined-trap-on-error"; 84 } 85 86 // Only one runtime library can be used at once. 87 bool NeedsAsan = needsAsanRt(); 88 bool NeedsTsan = needsTsanRt(); 89 bool NeedsMsan = needsMsanRt(); 90 bool NeedsLsan = needsLeakDetection(); 91 if (NeedsAsan && NeedsTsan) 92 D.Diag(diag::err_drv_argument_not_allowed_with) 93 << lastArgumentForKind(D, Args, NeedsAsanRt) 94 << lastArgumentForKind(D, Args, NeedsTsanRt); 95 if (NeedsAsan && NeedsMsan) 96 D.Diag(diag::err_drv_argument_not_allowed_with) 97 << lastArgumentForKind(D, Args, NeedsAsanRt) 98 << lastArgumentForKind(D, Args, NeedsMsanRt); 99 if (NeedsTsan && NeedsMsan) 100 D.Diag(diag::err_drv_argument_not_allowed_with) 101 << lastArgumentForKind(D, Args, NeedsTsanRt) 102 << lastArgumentForKind(D, Args, NeedsMsanRt); 103 if (NeedsLsan && NeedsTsan) 104 D.Diag(diag::err_drv_argument_not_allowed_with) 105 << lastArgumentForKind(D, Args, NeedsLeakDetection) 106 << lastArgumentForKind(D, Args, NeedsTsanRt); 107 if (NeedsLsan && NeedsMsan) 108 D.Diag(diag::err_drv_argument_not_allowed_with) 109 << lastArgumentForKind(D, Args, NeedsLeakDetection) 110 << lastArgumentForKind(D, Args, NeedsMsanRt); 111 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of 112 // -fsanitize=address. Perhaps it should print an error, or perhaps 113 // -f(-no)sanitize=leak should change whether leak detection is enabled by 114 // default in ASan? 115 116 // Parse -f(no-)sanitize-blacklist options. 117 if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist, 118 options::OPT_fno_sanitize_blacklist)) { 119 if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) { 120 std::string BLPath = BLArg->getValue(); 121 if (llvm::sys::fs::exists(BLPath)) { 122 // Validate the blacklist format. 123 std::string BLError; 124 std::unique_ptr<llvm::SpecialCaseList> SCL( 125 llvm::SpecialCaseList::create(BLPath, BLError)); 126 if (!SCL.get()) 127 D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError; 128 else 129 BlacklistFile = BLPath; 130 } else { 131 D.Diag(diag::err_drv_no_such_file) << BLPath; 132 } 133 } 134 } else { 135 // If no -fsanitize-blacklist option is specified, try to look up for 136 // blacklist in the resource directory. 137 std::string BLPath; 138 if (getDefaultBlacklistForKind(D, Kind, BLPath) && 139 llvm::sys::fs::exists(BLPath)) 140 BlacklistFile = BLPath; 141 } 142 143 // Parse -f[no-]sanitize-memory-track-origins[=level] options. 144 if (NeedsMsan) { 145 if (Arg *A = 146 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, 147 options::OPT_fsanitize_memory_track_origins, 148 options::OPT_fno_sanitize_memory_track_origins)) { 149 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { 150 MsanTrackOrigins = 1; 151 } else if (A->getOption().matches( 152 options::OPT_fno_sanitize_memory_track_origins)) { 153 MsanTrackOrigins = 0; 154 } else { 155 StringRef S = A->getValue(); 156 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || 157 MsanTrackOrigins > 2) { 158 D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S; 159 } 160 } 161 } 162 } 163 164 if (NeedsAsan) { 165 AsanSharedRuntime = 166 Args.hasArg(options::OPT_shared_libasan) || 167 (TC.getTriple().getEnvironment() == llvm::Triple::Android); 168 AsanZeroBaseShadow = 169 (TC.getTriple().getEnvironment() == llvm::Triple::Android); 170 } 171 } 172 173 void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, 174 llvm::opt::ArgStringList &CmdArgs) const { 175 if (!Kind) 176 return; 177 SmallString<256> SanitizeOpt("-fsanitize="); 178 #define SANITIZER(NAME, ID) \ 179 if (Kind & ID) \ 180 SanitizeOpt += NAME ","; 181 #include "clang/Basic/Sanitizers.def" 182 SanitizeOpt.pop_back(); 183 CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); 184 if (!BlacklistFile.empty()) { 185 SmallString<64> BlacklistOpt("-fsanitize-blacklist="); 186 BlacklistOpt += BlacklistFile; 187 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); 188 } 189 190 if (MsanTrackOrigins) 191 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + 192 llvm::utostr(MsanTrackOrigins))); 193 194 // Workaround for PR16386. 195 if (needsMsanRt()) 196 CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); 197 } 198 199 unsigned SanitizerArgs::parse(const char *Value) { 200 unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value) 201 #define SANITIZER(NAME, ID) .Case(NAME, ID) 202 #define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group) 203 #include "clang/Basic/Sanitizers.def" 204 .Default(SanitizeKind()); 205 return ParsedKind; 206 } 207 208 unsigned SanitizerArgs::expandGroups(unsigned Kinds) { 209 #define SANITIZER(NAME, ID) 210 #define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID; 211 #include "clang/Basic/Sanitizers.def" 212 return Kinds; 213 } 214 215 void SanitizerArgs::filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds, 216 unsigned Mask, 217 const llvm::opt::ArgList &Args, 218 const llvm::opt::Arg *A, 219 bool DiagnoseErrors, 220 unsigned &DiagnosedKinds) { 221 unsigned MaskedKinds = Kinds & Mask; 222 if (!MaskedKinds) 223 return; 224 Kinds &= ~Mask; 225 // Do we have new kinds to diagnose? 226 if (DiagnoseErrors && (DiagnosedKinds & MaskedKinds) != MaskedKinds) { 227 // Only diagnose the new kinds. 228 std::string Desc = 229 describeSanitizeArg(Args, A, MaskedKinds & ~DiagnosedKinds); 230 TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) 231 << Desc << TC.getTriple().str(); 232 DiagnosedKinds |= MaskedKinds; 233 } 234 } 235 236 unsigned SanitizerArgs::filterUnsupportedKinds(const ToolChain &TC, 237 unsigned Kinds, 238 const llvm::opt::ArgList &Args, 239 const llvm::opt::Arg *A, 240 bool DiagnoseErrors, 241 unsigned &DiagnosedKinds) { 242 bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux; 243 bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86; 244 bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64; 245 if (!(IsLinux && IsX86_64)) { 246 filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A, 247 DiagnoseErrors, DiagnosedKinds); 248 } 249 if (!(IsLinux && (IsX86 || IsX86_64))) { 250 filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors, 251 DiagnosedKinds); 252 } 253 return Kinds; 254 } 255 256 unsigned SanitizerArgs::parse(const Driver &D, const llvm::opt::Arg *A, 257 bool DiagnoseErrors) { 258 unsigned Kind = 0; 259 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { 260 if (unsigned K = parse(A->getValue(I))) 261 Kind |= K; 262 else if (DiagnoseErrors) 263 D.Diag(diag::err_drv_unsupported_option_argument) 264 << A->getOption().getName() << A->getValue(I); 265 } 266 return Kind; 267 } 268 269 bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args, 270 const llvm::opt::Arg *A, unsigned &Add, 271 unsigned &Remove, bool DiagnoseErrors) { 272 Add = 0; 273 Remove = 0; 274 if (A->getOption().matches(options::OPT_fsanitize_EQ)) { 275 Add = parse(D, A, DiagnoseErrors); 276 } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) { 277 Remove = parse(D, A, DiagnoseErrors); 278 } else { 279 // Flag is not relevant to sanitizers. 280 return false; 281 } 282 return true; 283 } 284 285 std::string SanitizerArgs::lastArgumentForKind(const Driver &D, 286 const llvm::opt::ArgList &Args, 287 unsigned Kind) { 288 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), 289 E = Args.rend(); 290 I != E; ++I) { 291 unsigned Add, Remove; 292 if (parse(D, Args, *I, Add, Remove, false) && 293 (expandGroups(Add) & Kind)) 294 return describeSanitizeArg(Args, *I, Kind); 295 Kind &= ~Remove; 296 } 297 llvm_unreachable("arg list didn't provide expected value"); 298 } 299 300 std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args, 301 const llvm::opt::Arg *A, 302 unsigned Mask) { 303 if (!A->getOption().matches(options::OPT_fsanitize_EQ)) 304 return A->getAsString(Args); 305 306 std::string Sanitizers; 307 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { 308 if (expandGroups(parse(A->getValue(I))) & Mask) { 309 if (!Sanitizers.empty()) 310 Sanitizers += ","; 311 Sanitizers += A->getValue(I); 312 } 313 } 314 315 assert(!Sanitizers.empty() && "arg didn't provide expected value"); 316 return "-fsanitize=" + Sanitizers; 317 } 318 319 bool SanitizerArgs::getDefaultBlacklistForKind(const Driver &D, unsigned Kind, 320 std::string &BLPath) { 321 const char *BlacklistFile = nullptr; 322 if (Kind & NeedsAsanRt) 323 BlacklistFile = "asan_blacklist.txt"; 324 else if (Kind & NeedsMsanRt) 325 BlacklistFile = "msan_blacklist.txt"; 326 else if (Kind & NeedsTsanRt) 327 BlacklistFile = "tsan_blacklist.txt"; 328 else if (Kind & NeedsDfsanRt) 329 BlacklistFile = "dfsan_abilist.txt"; 330 331 if (BlacklistFile) { 332 SmallString<64> Path(D.ResourceDir); 333 llvm::sys::path::append(Path, BlacklistFile); 334 BLPath = Path.str(); 335 return true; 336 } 337 return false; 338 } 339