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