Home | History | Annotate | Download | only in Driver
      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