clang API Documentation
00001 //===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 #include "clang/Driver/SanitizerArgs.h" 00010 #include "clang/Driver/Driver.h" 00011 #include "clang/Driver/DriverDiagnostic.h" 00012 #include "clang/Driver/Options.h" 00013 #include "clang/Driver/ToolChain.h" 00014 #include "llvm/ADT/StringExtras.h" 00015 #include "llvm/ADT/StringSwitch.h" 00016 #include "llvm/Support/FileSystem.h" 00017 #include "llvm/Support/Path.h" 00018 #include "llvm/Support/SpecialCaseList.h" 00019 #include <memory> 00020 00021 using namespace clang::driver; 00022 using namespace llvm::opt; 00023 00024 namespace { 00025 /// Assign ordinals to possible values of -fsanitize= flag. 00026 /// We use the ordinal values as bit positions within \c SanitizeKind. 00027 enum SanitizeOrdinal { 00028 #define SANITIZER(NAME, ID) SO_##ID, 00029 #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, 00030 #include "clang/Basic/Sanitizers.def" 00031 SO_Count 00032 }; 00033 00034 /// Represents a set of sanitizer kinds. It is also used to define: 00035 /// 1) set of sanitizers each sanitizer group expands into. 00036 /// 2) set of sanitizers sharing a specific property (e.g. 00037 /// all sanitizers with zero-base shadow). 00038 enum SanitizeKind { 00039 #define SANITIZER(NAME, ID) ID = 1 << SO_##ID, 00040 #define SANITIZER_GROUP(NAME, ID, ALIAS) \ 00041 ID = ALIAS, ID##Group = 1 << SO_##ID##Group, 00042 #include "clang/Basic/Sanitizers.def" 00043 NeedsUbsanRt = Undefined | Integer, 00044 NotAllowedWithTrap = Vptr, 00045 HasZeroBaseShadow = Thread | Memory | DataFlow, 00046 NeedsUnwindTables = Address | Thread | Memory | DataFlow 00047 }; 00048 } 00049 00050 /// Returns true if set of \p Sanitizers contain at least one sanitizer from 00051 /// \p Kinds. 00052 static bool hasOneOf(const clang::SanitizerSet &Sanitizers, unsigned Kinds) { 00053 #define SANITIZER(NAME, ID) \ 00054 if (Sanitizers.has(clang::SanitizerKind::ID) && (Kinds & ID)) \ 00055 return true; 00056 #include "clang/Basic/Sanitizers.def" 00057 return false; 00058 } 00059 00060 /// Adds all sanitizers from \p Kinds to \p Sanitizers. 00061 static void addAllOf(clang::SanitizerSet &Sanitizers, unsigned Kinds) { 00062 #define SANITIZER(NAME, ID) \ 00063 if (Kinds & ID) \ 00064 Sanitizers.set(clang::SanitizerKind::ID, true); 00065 #include "clang/Basic/Sanitizers.def" 00066 } 00067 00068 static unsigned toSanitizeKind(clang::SanitizerKind K) { 00069 #define SANITIZER(NAME, ID) \ 00070 if (K == clang::SanitizerKind::ID) \ 00071 return ID; 00072 #include "clang/Basic/Sanitizers.def" 00073 llvm_unreachable("Invalid SanitizerKind!"); 00074 } 00075 00076 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. 00077 /// Returns a member of the \c SanitizeKind enumeration, or \c 0 00078 /// if \p Value is not known. 00079 static unsigned parseValue(const char *Value); 00080 00081 /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any 00082 /// invalid components. Returns OR of members of \c SanitizeKind enumeration. 00083 static unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A, 00084 bool DiagnoseErrors); 00085 00086 /// Parse a single flag of the form -f[no]sanitize=. 00087 /// Sets the masks defining required change of the set of sanitizers. 00088 /// Returns true if the flag was parsed successfully. 00089 static bool parseArgument(const Driver &D, const llvm::opt::Arg *A, 00090 unsigned &Add, unsigned &Remove, bool DiagnoseErrors); 00091 00092 /// Produce an argument string from ArgList \p Args, which shows how it 00093 /// provides some sanitizer kind from \p Mask. For example, the argument list 00094 /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt 00095 /// would produce "-fsanitize=vptr". 00096 static std::string lastArgumentForMask(const Driver &D, 00097 const llvm::opt::ArgList &Args, 00098 unsigned Mask); 00099 00100 static std::string lastArgumentForKind(const Driver &D, 00101 const llvm::opt::ArgList &Args, 00102 clang::SanitizerKind K) { 00103 return lastArgumentForMask(D, Args, toSanitizeKind(K)); 00104 } 00105 00106 /// Produce an argument string from argument \p A, which shows how it provides 00107 /// a value in \p Mask. For instance, the argument 00108 /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce 00109 /// "-fsanitize=alignment". 00110 static std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask); 00111 00112 /// Produce a string containing comma-separated names of sanitizers in \p 00113 /// Sanitizers set. 00114 static std::string toString(const clang::SanitizerSet &Sanitizers); 00115 00116 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers 00117 /// this group enables. 00118 static unsigned expandGroups(unsigned Kinds); 00119 00120 static unsigned getToolchainUnsupportedKinds(const ToolChain &TC) { 00121 bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD; 00122 bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux; 00123 bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86; 00124 bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64; 00125 00126 unsigned Unsupported = 0; 00127 if (!(IsLinux && IsX86_64)) { 00128 Unsupported |= Memory | DataFlow; 00129 } 00130 if (!((IsLinux || IsFreeBSD) && IsX86_64)) { 00131 Unsupported |= Thread; 00132 } 00133 if (!(IsLinux && (IsX86 || IsX86_64))) { 00134 Unsupported |= Function; 00135 } 00136 return Unsupported; 00137 } 00138 00139 bool SanitizerArgs::needsUbsanRt() const { 00140 return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt); 00141 } 00142 00143 bool SanitizerArgs::hasZeroBaseShadow() const { 00144 return AsanZeroBaseShadow || hasOneOf(Sanitizers, HasZeroBaseShadow); 00145 } 00146 00147 bool SanitizerArgs::needsUnwindTables() const { 00148 return hasOneOf(Sanitizers, NeedsUnwindTables); 00149 } 00150 00151 void SanitizerArgs::clear() { 00152 Sanitizers.clear(); 00153 SanitizeRecover = false; 00154 BlacklistFile = ""; 00155 SanitizeCoverage = 0; 00156 MsanTrackOrigins = 0; 00157 AsanFieldPadding = 0; 00158 AsanZeroBaseShadow = false; 00159 UbsanTrapOnError = false; 00160 AsanSharedRuntime = false; 00161 LinkCXXRuntimes = false; 00162 } 00163 00164 SanitizerArgs::SanitizerArgs(const ToolChain &TC, 00165 const llvm::opt::ArgList &Args) { 00166 clear(); 00167 unsigned AllRemove = 0; // During the loop below, the accumulated set of 00168 // sanitizers disabled by the current sanitizer 00169 // argument or any argument after it. 00170 unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. 00171 // Used to deduplicate diagnostics. 00172 unsigned Kinds = 0; 00173 unsigned NotSupported = getToolchainUnsupportedKinds(TC); 00174 const Driver &D = TC.getDriver(); 00175 for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); 00176 I != E; ++I) { 00177 unsigned Add, Remove; 00178 if (!parseArgument(D, *I, Add, Remove, true)) 00179 continue; 00180 (*I)->claim(); 00181 00182 AllRemove |= expandGroups(Remove); 00183 00184 // Avoid diagnosing any sanitizer which is disabled later. 00185 Add &= ~AllRemove; 00186 00187 // At this point we have not expanded groups, so any unsupported sanitizers 00188 // in Add are those which have been explicitly enabled. Diagnose them. 00189 if (unsigned KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) { 00190 // Only diagnose the new kinds. 00191 std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); 00192 D.Diag(diag::err_drv_unsupported_opt_for_target) << Desc 00193 << TC.getTriple().str(); 00194 DiagnosedKinds |= KindsToDiagnose; 00195 } 00196 Add &= ~NotSupported; 00197 00198 Add = expandGroups(Add); 00199 // Group expansion may have enabled a sanitizer which is disabled later. 00200 Add &= ~AllRemove; 00201 // Silently discard any unsupported sanitizers implicitly enabled through 00202 // group expansion. 00203 Add &= ~NotSupported; 00204 00205 Kinds |= Add; 00206 } 00207 addAllOf(Sanitizers, Kinds); 00208 00209 SanitizeRecover = Args.hasFlag(options::OPT_fsanitize_recover, 00210 options::OPT_fno_sanitize_recover, true); 00211 00212 UbsanTrapOnError = 00213 Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, 00214 options::OPT_fno_sanitize_undefined_trap_on_error, false); 00215 00216 // Warn about undefined sanitizer options that require runtime support. 00217 if (UbsanTrapOnError && hasOneOf(Sanitizers, NotAllowedWithTrap)) { 00218 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 00219 << lastArgumentForMask(D, Args, NotAllowedWithTrap) 00220 << "-fsanitize-undefined-trap-on-error"; 00221 } 00222 00223 // Check for incompatible sanitizers. 00224 bool NeedsAsan = Sanitizers.has(SanitizerKind::Address); 00225 bool NeedsTsan = Sanitizers.has(SanitizerKind::Thread); 00226 bool NeedsMsan = Sanitizers.has(SanitizerKind::Memory); 00227 bool NeedsLsan = Sanitizers.has(SanitizerKind::Leak); 00228 if (NeedsAsan && NeedsTsan) 00229 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 00230 << lastArgumentForKind(D, Args, SanitizerKind::Address) 00231 << lastArgumentForKind(D, Args, SanitizerKind::Thread); 00232 if (NeedsAsan && NeedsMsan) 00233 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 00234 << lastArgumentForKind(D, Args, SanitizerKind::Address) 00235 << lastArgumentForKind(D, Args, SanitizerKind::Memory); 00236 if (NeedsTsan && NeedsMsan) 00237 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 00238 << lastArgumentForKind(D, Args, SanitizerKind::Thread) 00239 << lastArgumentForKind(D, Args, SanitizerKind::Memory); 00240 if (NeedsLsan && NeedsTsan) 00241 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 00242 << lastArgumentForKind(D, Args, SanitizerKind::Leak) 00243 << lastArgumentForKind(D, Args, SanitizerKind::Thread); 00244 if (NeedsLsan && NeedsMsan) 00245 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 00246 << lastArgumentForKind(D, Args, SanitizerKind::Leak) 00247 << lastArgumentForKind(D, Args, SanitizerKind::Memory); 00248 // FIXME: Currently -fsanitize=leak is silently ignored in the presence of 00249 // -fsanitize=address. Perhaps it should print an error, or perhaps 00250 // -f(-no)sanitize=leak should change whether leak detection is enabled by 00251 // default in ASan? 00252 00253 // Parse -f(no-)sanitize-blacklist options. 00254 if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist, 00255 options::OPT_fno_sanitize_blacklist)) { 00256 if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) { 00257 std::string BLPath = BLArg->getValue(); 00258 if (llvm::sys::fs::exists(BLPath)) { 00259 // Validate the blacklist format. 00260 std::string BLError; 00261 std::unique_ptr<llvm::SpecialCaseList> SCL( 00262 llvm::SpecialCaseList::create(BLPath, BLError)); 00263 if (!SCL.get()) 00264 D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; 00265 else 00266 BlacklistFile = BLPath; 00267 } else { 00268 D.Diag(clang::diag::err_drv_no_such_file) << BLPath; 00269 } 00270 } 00271 } else { 00272 // If no -fsanitize-blacklist option is specified, try to look up for 00273 // blacklist in the resource directory. 00274 std::string BLPath; 00275 if (getDefaultBlacklist(D, BLPath) && llvm::sys::fs::exists(BLPath)) 00276 BlacklistFile = BLPath; 00277 } 00278 00279 // Parse -f[no-]sanitize-memory-track-origins[=level] options. 00280 if (NeedsMsan) { 00281 if (Arg *A = 00282 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, 00283 options::OPT_fsanitize_memory_track_origins, 00284 options::OPT_fno_sanitize_memory_track_origins)) { 00285 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { 00286 MsanTrackOrigins = 1; 00287 } else if (A->getOption().matches( 00288 options::OPT_fno_sanitize_memory_track_origins)) { 00289 MsanTrackOrigins = 0; 00290 } else { 00291 StringRef S = A->getValue(); 00292 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || 00293 MsanTrackOrigins > 2) { 00294 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 00295 } 00296 } 00297 } 00298 } 00299 00300 // Parse -fsanitize-coverage=N 00301 if (NeedsAsan) { // Currently asan is required. 00302 if (Arg *A = Args.getLastArg(options::OPT_fsanitize_coverage)) { 00303 StringRef S = A->getValue(); 00304 // Legal values are 0..4. 00305 if (S.getAsInteger(0, SanitizeCoverage) || SanitizeCoverage < 0 || 00306 SanitizeCoverage > 4) 00307 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 00308 } 00309 } 00310 00311 if (NeedsAsan) { 00312 AsanSharedRuntime = 00313 Args.hasArg(options::OPT_shared_libasan) || 00314 (TC.getTriple().getEnvironment() == llvm::Triple::Android); 00315 AsanZeroBaseShadow = 00316 (TC.getTriple().getEnvironment() == llvm::Triple::Android); 00317 if (Arg *A = 00318 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { 00319 StringRef S = A->getValue(); 00320 // Legal values are 0 and 1, 2, but in future we may add more levels. 00321 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || 00322 AsanFieldPadding > 2) { 00323 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 00324 } 00325 } 00326 00327 if (Arg *WindowsDebugRTArg = 00328 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT, 00329 options::OPT__SLASH_MDd, options::OPT__SLASH_MD, 00330 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) { 00331 switch (WindowsDebugRTArg->getOption().getID()) { 00332 case options::OPT__SLASH_MTd: 00333 case options::OPT__SLASH_MDd: 00334 case options::OPT__SLASH_LDd: 00335 D.Diag(clang::diag::err_drv_argument_not_allowed_with) 00336 << WindowsDebugRTArg->getAsString(Args) 00337 << lastArgumentForKind(D, Args, SanitizerKind::Address); 00338 D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); 00339 } 00340 } 00341 } 00342 00343 // Parse -link-cxx-sanitizer flag. 00344 LinkCXXRuntimes = 00345 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); 00346 } 00347 00348 static std::string toString(const clang::SanitizerSet &Sanitizers) { 00349 std::string Res; 00350 #define SANITIZER(NAME, ID) \ 00351 if (Sanitizers.has(clang::SanitizerKind::ID)) { \ 00352 if (!Res.empty()) \ 00353 Res += ","; \ 00354 Res += NAME; \ 00355 } 00356 #include "clang/Basic/Sanitizers.def" 00357 return Res; 00358 } 00359 00360 void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, 00361 llvm::opt::ArgStringList &CmdArgs) const { 00362 if (Sanitizers.empty()) 00363 return; 00364 CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers))); 00365 00366 if (!SanitizeRecover) 00367 CmdArgs.push_back("-fno-sanitize-recover"); 00368 00369 if (UbsanTrapOnError) 00370 CmdArgs.push_back("-fsanitize-undefined-trap-on-error"); 00371 00372 if (!BlacklistFile.empty()) { 00373 SmallString<64> BlacklistOpt("-fsanitize-blacklist="); 00374 BlacklistOpt += BlacklistFile; 00375 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); 00376 } 00377 00378 if (MsanTrackOrigins) 00379 CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + 00380 llvm::utostr(MsanTrackOrigins))); 00381 if (AsanFieldPadding) 00382 CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + 00383 llvm::utostr(AsanFieldPadding))); 00384 if (SanitizeCoverage) 00385 CmdArgs.push_back(Args.MakeArgString("-fsanitize-coverage=" + 00386 llvm::utostr(SanitizeCoverage))); 00387 // Workaround for PR16386. 00388 if (Sanitizers.has(SanitizerKind::Memory)) 00389 CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); 00390 } 00391 00392 bool SanitizerArgs::getDefaultBlacklist(const Driver &D, std::string &BLPath) { 00393 const char *BlacklistFile = nullptr; 00394 if (Sanitizers.has(SanitizerKind::Address)) 00395 BlacklistFile = "asan_blacklist.txt"; 00396 else if (Sanitizers.has(SanitizerKind::Memory)) 00397 BlacklistFile = "msan_blacklist.txt"; 00398 else if (Sanitizers.has(SanitizerKind::Thread)) 00399 BlacklistFile = "tsan_blacklist.txt"; 00400 else if (Sanitizers.has(SanitizerKind::DataFlow)) 00401 BlacklistFile = "dfsan_abilist.txt"; 00402 00403 if (BlacklistFile) { 00404 SmallString<64> Path(D.ResourceDir); 00405 llvm::sys::path::append(Path, BlacklistFile); 00406 BLPath = Path.str(); 00407 return true; 00408 } 00409 return false; 00410 } 00411 00412 unsigned parseValue(const char *Value) { 00413 unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value) 00414 #define SANITIZER(NAME, ID) .Case(NAME, ID) 00415 #define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group) 00416 #include "clang/Basic/Sanitizers.def" 00417 .Default(SanitizeKind()); 00418 return ParsedKind; 00419 } 00420 00421 unsigned expandGroups(unsigned Kinds) { 00422 #define SANITIZER(NAME, ID) 00423 #define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID; 00424 #include "clang/Basic/Sanitizers.def" 00425 return Kinds; 00426 } 00427 00428 unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A, 00429 bool DiagnoseErrors) { 00430 unsigned Kind = 0; 00431 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { 00432 if (unsigned K = parseValue(A->getValue(I))) 00433 Kind |= K; 00434 else if (DiagnoseErrors) 00435 D.Diag(clang::diag::err_drv_unsupported_option_argument) 00436 << A->getOption().getName() << A->getValue(I); 00437 } 00438 return Kind; 00439 } 00440 00441 bool parseArgument(const Driver &D, const llvm::opt::Arg *A, unsigned &Add, 00442 unsigned &Remove, bool DiagnoseErrors) { 00443 Add = 0; 00444 Remove = 0; 00445 if (A->getOption().matches(options::OPT_fsanitize_EQ)) { 00446 Add = parseArgValues(D, A, DiagnoseErrors); 00447 return true; 00448 } 00449 if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) { 00450 Remove = parseArgValues(D, A, DiagnoseErrors); 00451 return true; 00452 } 00453 return false; 00454 } 00455 00456 std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, 00457 unsigned Mask) { 00458 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), 00459 E = Args.rend(); 00460 I != E; ++I) { 00461 unsigned Add, Remove; 00462 if (parseArgument(D, *I, Add, Remove, false) && 00463 (expandGroups(Add) & Mask)) 00464 return describeSanitizeArg(*I, Mask); 00465 Mask &= ~Remove; 00466 } 00467 llvm_unreachable("arg list didn't provide expected value"); 00468 } 00469 00470 std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask) { 00471 assert(A->getOption().matches(options::OPT_fsanitize_EQ) 00472 && "Invalid argument in describeSanitizerArg!"); 00473 00474 std::string Sanitizers; 00475 for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { 00476 if (expandGroups(parseValue(A->getValue(I))) & Mask) { 00477 if (!Sanitizers.empty()) 00478 Sanitizers += ","; 00479 Sanitizers += A->getValue(I); 00480 } 00481 } 00482 00483 assert(!Sanitizers.empty() && "arg didn't provide expected value"); 00484 return "-fsanitize=" + Sanitizers; 00485 }