[Driver] Use VFS to check if sanitizer blacklists exist

Summary:
This is a follow-up to 590f279c456bbde632eca8ef89a85c478f15a249, which
moved some of the callers to use VFS.

It turned out more code in Driver calls into real filesystem APIs and
also needs an update.

Reviewers: gribozavr2, kadircet

Reviewed By: kadircet

Subscribers: ormris, mgorny, hiraditya, llvm-commits, jkorous, cfe-commits

Tags: #clang, #llvm

Differential Revision: https://reviews.llvm.org/D70440
diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp
index 7a820d4..5bf8d39 100644
--- a/clang/lib/Basic/SanitizerSpecialCaseList.cpp
+++ b/clang/lib/Basic/SanitizerSpecialCaseList.cpp
@@ -20,7 +20,7 @@
                                  std::string &Error) {
   std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL(
       new SanitizerSpecialCaseList());
-  if (SSCL->createInternal(Paths, Error, VFS)) {
+  if (SSCL->createInternal(Paths, VFS, Error)) {
     SSCL->createSanitizerSections();
     return SSCL;
   }
diff --git a/clang/lib/Basic/XRayLists.cpp b/clang/lib/Basic/XRayLists.cpp
index eb54943..222a28f 100644
--- a/clang/lib/Basic/XRayLists.cpp
+++ b/clang/lib/Basic/XRayLists.cpp
@@ -17,10 +17,13 @@
     ArrayRef<std::string> AlwaysInstrumentPaths,
     ArrayRef<std::string> NeverInstrumentPaths,
     ArrayRef<std::string> AttrListPaths, SourceManager &SM)
-    : AlwaysInstrument(
-          llvm::SpecialCaseList::createOrDie(AlwaysInstrumentPaths)),
-      NeverInstrument(llvm::SpecialCaseList::createOrDie(NeverInstrumentPaths)),
-      AttrList(llvm::SpecialCaseList::createOrDie(AttrListPaths)), SM(SM) {}
+    : AlwaysInstrument(llvm::SpecialCaseList::createOrDie(
+          AlwaysInstrumentPaths, SM.getFileManager().getVirtualFileSystem())),
+      NeverInstrument(llvm::SpecialCaseList::createOrDie(
+          NeverInstrumentPaths, SM.getFileManager().getVirtualFileSystem())),
+      AttrList(llvm::SpecialCaseList::createOrDie(
+          AttrListPaths, SM.getFileManager().getVirtualFileSystem())),
+      SM(SM) {}
 
 XRayFunctionFilter::ImbueAttribute
 XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const {
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 8937197..ac9a294 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -141,7 +141,7 @@
 
     clang::SmallString<64> Path(D.ResourceDir);
     llvm::sys::path::append(Path, "share", BL.File);
-    if (llvm::sys::fs::exists(Path))
+    if (D.getVFS().exists(Path))
       BlacklistFiles.push_back(Path.str());
     else if (BL.Mask == SanitizerKind::CFI)
       // If cfi_blacklist.txt cannot be found in the resource dir, driver
@@ -563,7 +563,7 @@
     if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
       Arg->claim();
       std::string BLPath = Arg->getValue();
-      if (llvm::sys::fs::exists(BLPath)) {
+      if (D.getVFS().exists(BLPath)) {
         UserBlacklistFiles.push_back(BLPath);
       } else {
         D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
@@ -578,14 +578,14 @@
   {
     std::string BLError;
     std::unique_ptr<llvm::SpecialCaseList> SCL(
-        llvm::SpecialCaseList::create(UserBlacklistFiles, BLError));
+        llvm::SpecialCaseList::create(UserBlacklistFiles, D.getVFS(), BLError));
     if (!SCL.get())
       D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
   }
   {
     std::string BLError;
-    std::unique_ptr<llvm::SpecialCaseList> SCL(
-        llvm::SpecialCaseList::create(SystemBlacklistFiles, BLError));
+    std::unique_ptr<llvm::SpecialCaseList> SCL(llvm::SpecialCaseList::create(
+        SystemBlacklistFiles, D.getVFS(), BLError));
     if (!SCL.get())
       D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
   }
diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp
index 16e7c7e..6011dea 100644
--- a/clang/lib/Driver/XRayArgs.cpp
+++ b/clang/lib/Driver/XRayArgs.cpp
@@ -129,7 +129,7 @@
     // are treated as actual dependencies.
     for (const auto &Filename :
          Args.getAllArgValues(options::OPT_fxray_always_instrument)) {
-      if (llvm::sys::fs::exists(Filename)) {
+      if (D.getVFS().exists(Filename)) {
         AlwaysInstrumentFiles.push_back(Filename);
         ExtraDeps.push_back(Filename);
       } else
@@ -138,7 +138,7 @@
 
     for (const auto &Filename :
          Args.getAllArgValues(options::OPT_fxray_never_instrument)) {
-      if (llvm::sys::fs::exists(Filename)) {
+      if (D.getVFS().exists(Filename)) {
         NeverInstrumentFiles.push_back(Filename);
         ExtraDeps.push_back(Filename);
       } else
@@ -147,7 +147,7 @@
 
     for (const auto &Filename :
          Args.getAllArgValues(options::OPT_fxray_attr_list)) {
-      if (llvm::sys::fs::exists(Filename)) {
+      if (D.getVFS().exists(Filename)) {
         AttrListFiles.push_back(Filename);
         ExtraDeps.push_back(Filename);
       } else
diff --git a/clang/unittests/Driver/CMakeLists.txt b/clang/unittests/Driver/CMakeLists.txt
index 55b8a74..d0ab87b 100644
--- a/clang/unittests/Driver/CMakeLists.txt
+++ b/clang/unittests/Driver/CMakeLists.txt
@@ -9,10 +9,12 @@
   ToolChainTest.cpp
   ModuleCacheTest.cpp
   MultilibTest.cpp
+  SanitizerArgsTest.cpp
   )
 
 clang_target_link_libraries(ClangDriverTests
   PRIVATE
   clangDriver
   clangBasic
+  clangFrontend # For TextDiagnosticPrinter.
   )
diff --git a/clang/unittests/Driver/SanitizerArgsTest.cpp b/clang/unittests/Driver/SanitizerArgsTest.cpp
new file mode 100644
index 0000000..164bc68
--- /dev/null
+++ b/clang/unittests/Driver/SanitizerArgsTest.cpp
@@ -0,0 +1,141 @@
+//===- unittests/Driver/SanitizerArgsTest.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Job.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+#include <memory>
+#include <string>
+using namespace clang;
+using namespace clang::driver;
+
+using ::testing::Contains;
+using ::testing::StrEq;
+
+namespace {
+
+static constexpr const char *ClangBinary = "clang";
+static constexpr const char *InputFile = "/sources/foo.c";
+
+std::string concatPaths(llvm::ArrayRef<StringRef> Components) {
+  llvm::SmallString<128> P;
+  for (StringRef C : Components)
+    llvm::sys::path::append(P, C);
+  return P.str().str();
+}
+
+class SanitizerArgsTest : public ::testing::Test {
+protected:
+  const Command &emulateSingleCompilation(std::vector<std::string> ExtraArgs,
+                                          std::vector<std::string> ExtraFiles) {
+    assert(!Driver && "Running twice is not allowed");
+
+    llvm::IntrusiveRefCntPtr<DiagnosticOptions> Opts = new DiagnosticOptions;
+    DiagnosticsEngine Diags(
+        new DiagnosticIDs, Opts,
+        new TextDiagnosticPrinter(llvm::errs(), Opts.get()));
+    Driver.emplace(ClangBinary, "x86_64-unknown-linux-gnu", Diags,
+                   prepareFS(ExtraFiles));
+
+    std::vector<const char *> Args = {ClangBinary};
+    for (const auto &A : ExtraArgs)
+      Args.push_back(A.c_str());
+    Args.push_back("-c");
+    Args.push_back(InputFile);
+
+    Compilation.reset(Driver->BuildCompilation(Args));
+
+    if (Diags.hasErrorOccurred())
+      ADD_FAILURE() << "Error occurred while parsing compilation arguments. "
+                       "See stderr for details.";
+
+    const auto &Commands = Compilation->getJobs().getJobs();
+    assert(Commands.size() == 1);
+    return *Commands.front();
+  }
+
+private:
+  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>
+  prepareFS(llvm::ArrayRef<std::string> ExtraFiles) {
+    llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
+        new llvm::vfs::InMemoryFileSystem;
+    FS->addFile(ClangBinary, time_t(), llvm::MemoryBuffer::getMemBuffer(""));
+    FS->addFile(InputFile, time_t(), llvm::MemoryBuffer::getMemBuffer(""));
+    for (llvm::StringRef F : ExtraFiles)
+      FS->addFile(F, time_t(), llvm::MemoryBuffer::getMemBuffer(""));
+    return FS;
+  }
+
+  llvm::Optional<Driver> Driver;
+  std::unique_ptr<driver::Compilation> Compilation;
+};
+
+TEST_F(SanitizerArgsTest, Blacklists) {
+  const std::string ResourceDir = "/opt/llvm/lib/resources";
+  const std::string UserBlacklist = "/source/my_blacklist.txt";
+  const std::string ASanBlacklist =
+      concatPaths({ResourceDir, "share", "asan_blacklist.txt"});
+
+  auto &Command = emulateSingleCompilation(
+      /*ExtraArgs=*/{"-fsanitize=address", "-resource-dir", ResourceDir,
+                     std::string("-fsanitize-blacklist=") + UserBlacklist},
+      /*ExtraFiles=*/{ASanBlacklist, UserBlacklist});
+
+  // System blacklists are added based on resource-dir.
+  EXPECT_THAT(Command.getArguments(),
+              Contains(StrEq(std::string("-fsanitize-system-blacklist=") +
+                             ASanBlacklist)));
+  // User blacklists should also be added.
+  EXPECT_THAT(
+      Command.getArguments(),
+      Contains(StrEq(std::string("-fsanitize-blacklist=") + UserBlacklist)));
+}
+
+TEST_F(SanitizerArgsTest, XRayLists) {
+  const std::string XRayWhitelist = "/source/xray_whitelist.txt";
+  const std::string XRayBlacklist = "/source/xray_blacklist.txt";
+  const std::string XRayAttrList = "/source/xray_attr_list.txt";
+
+  auto &Command = emulateSingleCompilation(
+      /*ExtraArgs=*/
+      {
+          "-fxray-instrument",
+          "-fxray-always-instrument=" + XRayWhitelist,
+          "-fxray-never-instrument=" + XRayBlacklist,
+          "-fxray-attr-list=" + XRayAttrList,
+      },
+      /*ExtraFiles=*/{XRayWhitelist, XRayBlacklist, XRayAttrList});
+
+  // Blacklists exist in the filesystem, so they should be added to the
+  // compilation command, produced by the driver.
+  EXPECT_THAT(Command.getArguments(),
+              Contains(StrEq("-fxray-always-instrument=" + XRayWhitelist)));
+  EXPECT_THAT(Command.getArguments(),
+              Contains(StrEq("-fxray-never-instrument=" + XRayBlacklist)));
+  EXPECT_THAT(Command.getArguments(),
+              Contains(StrEq("-fxray-attr-list=" + XRayAttrList)));
+}
+
+} // namespace