140 lines · cpp
1//===- unittests/Driver/SanitizerArgsTest.cpp -----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Basic/Diagnostic.h"10#include "clang/Basic/DiagnosticIDs.h"11#include "clang/Basic/DiagnosticOptions.h"12#include "clang/Driver/Compilation.h"13#include "clang/Driver/Driver.h"14#include "clang/Driver/Job.h"15#include "clang/Frontend/TextDiagnosticPrinter.h"16#include "llvm/ADT/ArrayRef.h"17#include "llvm/ADT/IntrusiveRefCntPtr.h"18#include "llvm/ADT/SmallString.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/Support/MemoryBuffer.h"21#include "llvm/Support/Path.h"22#include "llvm/Support/VirtualFileSystem.h"23#include "llvm/Support/raw_ostream.h"24#include "llvm/TargetParser/Host.h"25#include "gmock/gmock.h"26#include "gtest/gtest.h"27#include <cstdlib>28#include <memory>29#include <optional>30#include <string>31using namespace clang;32using namespace clang::driver;33 34using ::testing::Contains;35using ::testing::StrEq;36 37namespace {38 39static constexpr const char *ClangBinary = "clang";40static constexpr const char *InputFile = "/sources/foo.c";41 42std::string concatPaths(llvm::ArrayRef<StringRef> Components) {43 llvm::SmallString<128> P;44 for (StringRef C : Components)45 llvm::sys::path::append(P, C);46 return std::string(P);47}48 49class SanitizerArgsTest : public ::testing::Test {50protected:51 const Command &emulateSingleCompilation(std::vector<std::string> ExtraArgs,52 std::vector<std::string> ExtraFiles) {53 assert(!DriverInstance && "Running twice is not allowed");54 55 DiagnosticOptions DiagOpts;56 DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts,57 new TextDiagnosticPrinter(llvm::errs(), DiagOpts));58 DriverInstance.emplace(ClangBinary, "x86_64-unknown-linux-gnu", Diags,59 "clang LLVM compiler", prepareFS(ExtraFiles));60 61 std::vector<const char *> Args = {ClangBinary};62 for (const auto &A : ExtraArgs)63 Args.push_back(A.c_str());64 Args.push_back("-c");65 Args.push_back(InputFile);66 67 CompilationJob.reset(DriverInstance->BuildCompilation(Args));68 69 if (Diags.hasErrorOccurred())70 ADD_FAILURE() << "Error occurred while parsing compilation arguments. "71 "See stderr for details.";72 73 const auto &Commands = CompilationJob->getJobs().getJobs();74 assert(Commands.size() == 1);75 return *Commands.front();76 }77 78private:79 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>80 prepareFS(llvm::ArrayRef<std::string> ExtraFiles) {81 auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();82 FS->addFile(ClangBinary, time_t(), llvm::MemoryBuffer::getMemBuffer(""));83 FS->addFile(InputFile, time_t(), llvm::MemoryBuffer::getMemBuffer(""));84 for (llvm::StringRef F : ExtraFiles)85 FS->addFile(F, time_t(), llvm::MemoryBuffer::getMemBuffer(""));86 return FS;87 }88 89 std::optional<Driver> DriverInstance;90 std::unique_ptr<driver::Compilation> CompilationJob;91};92 93TEST_F(SanitizerArgsTest, Ignorelists) {94 const std::string ResourceDir = "/opt/llvm/lib/resources";95 const std::string UserIgnorelist = "/source/my_ignorelist.txt";96 const std::string ASanIgnorelist =97 concatPaths({ResourceDir, "share", "asan_ignorelist.txt"});98 99 auto &Command = emulateSingleCompilation(100 /*ExtraArgs=*/{"-fsanitize=address", "-resource-dir", ResourceDir,101 std::string("-fsanitize-ignorelist=") + UserIgnorelist},102 /*ExtraFiles=*/{ASanIgnorelist, UserIgnorelist});103 104 // System ignorelists are added based on resource-dir.105 EXPECT_THAT(Command.getArguments(),106 Contains(StrEq(std::string("-fsanitize-system-ignorelist=") +107 ASanIgnorelist)));108 // User ignorelists should also be added.109 EXPECT_THAT(110 Command.getArguments(),111 Contains(StrEq(std::string("-fsanitize-ignorelist=") + UserIgnorelist)));112}113 114TEST_F(SanitizerArgsTest, XRayLists) {115 const std::string XRayAllowlist = "/source/xray_allowlist.txt";116 const std::string XRayIgnorelist = "/source/xray_ignorelist.txt";117 const std::string XRayAttrList = "/source/xray_attr_list.txt";118 119 auto &Command = emulateSingleCompilation(120 /*ExtraArgs=*/121 {122 "-fxray-instrument",123 "-fxray-always-instrument=" + XRayAllowlist,124 "-fxray-never-instrument=" + XRayIgnorelist,125 "-fxray-attr-list=" + XRayAttrList,126 },127 /*ExtraFiles=*/{XRayAllowlist, XRayIgnorelist, XRayAttrList});128 129 // Ignorelists exist in the filesystem, so they should be added to the130 // compilation command, produced by the driver.131 EXPECT_THAT(Command.getArguments(),132 Contains(StrEq("-fxray-always-instrument=" + XRayAllowlist)));133 EXPECT_THAT(Command.getArguments(),134 Contains(StrEq("-fxray-never-instrument=" + XRayIgnorelist)));135 EXPECT_THAT(Command.getArguments(),136 Contains(StrEq("-fxray-attr-list=" + XRayAttrList)));137}138 139} // namespace140