1 //===- unittests/Driver/SanitizerArgsTest.cpp -----------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
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"
31 using namespace clang
;
32 using namespace clang::driver
;
34 using ::testing::Contains
;
35 using ::testing::StrEq
;
39 static constexpr const char *ClangBinary
= "clang";
40 static constexpr const char *InputFile
= "/sources/foo.c";
42 std::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
);
49 class SanitizerArgsTest
: public ::testing::Test
{
51 const Command
&emulateSingleCompilation(std::vector
<std::string
> ExtraArgs
,
52 std::vector
<std::string
> ExtraFiles
) {
53 assert(!DriverInstance
&& "Running twice is not allowed");
55 llvm::IntrusiveRefCntPtr
<DiagnosticOptions
> Opts
= new DiagnosticOptions
;
56 DiagnosticsEngine
Diags(
57 new DiagnosticIDs
, Opts
,
58 new TextDiagnosticPrinter(llvm::errs(), Opts
.get()));
59 DriverInstance
.emplace(ClangBinary
, "x86_64-unknown-linux-gnu", Diags
,
60 "clang LLVM compiler", prepareFS(ExtraFiles
));
62 std::vector
<const char *> Args
= {ClangBinary
};
63 for (const auto &A
: ExtraArgs
)
64 Args
.push_back(A
.c_str());
66 Args
.push_back(InputFile
);
68 CompilationJob
.reset(DriverInstance
->BuildCompilation(Args
));
70 if (Diags
.hasErrorOccurred())
71 ADD_FAILURE() << "Error occurred while parsing compilation arguments. "
72 "See stderr for details.";
74 const auto &Commands
= CompilationJob
->getJobs().getJobs();
75 assert(Commands
.size() == 1);
76 return *Commands
.front();
80 llvm::IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
>
81 prepareFS(llvm::ArrayRef
<std::string
> ExtraFiles
) {
82 llvm::IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> FS
=
83 new llvm::vfs::InMemoryFileSystem
;
84 FS
->addFile(ClangBinary
, time_t(), llvm::MemoryBuffer::getMemBuffer(""));
85 FS
->addFile(InputFile
, time_t(), llvm::MemoryBuffer::getMemBuffer(""));
86 for (llvm::StringRef F
: ExtraFiles
)
87 FS
->addFile(F
, time_t(), llvm::MemoryBuffer::getMemBuffer(""));
91 std::optional
<Driver
> DriverInstance
;
92 std::unique_ptr
<driver::Compilation
> CompilationJob
;
95 TEST_F(SanitizerArgsTest
, Ignorelists
) {
96 const std::string ResourceDir
= "/opt/llvm/lib/resources";
97 const std::string UserIgnorelist
= "/source/my_ignorelist.txt";
98 const std::string ASanIgnorelist
=
99 concatPaths({ResourceDir
, "share", "asan_ignorelist.txt"});
101 auto &Command
= emulateSingleCompilation(
102 /*ExtraArgs=*/{"-fsanitize=address", "-resource-dir", ResourceDir
,
103 std::string("-fsanitize-ignorelist=") + UserIgnorelist
},
104 /*ExtraFiles=*/{ASanIgnorelist
, UserIgnorelist
});
106 // System ignorelists are added based on resource-dir.
107 EXPECT_THAT(Command
.getArguments(),
108 Contains(StrEq(std::string("-fsanitize-system-ignorelist=") +
110 // User ignorelists should also be added.
112 Command
.getArguments(),
113 Contains(StrEq(std::string("-fsanitize-ignorelist=") + UserIgnorelist
)));
116 TEST_F(SanitizerArgsTest
, XRayLists
) {
117 const std::string XRayAllowlist
= "/source/xray_allowlist.txt";
118 const std::string XRayIgnorelist
= "/source/xray_ignorelist.txt";
119 const std::string XRayAttrList
= "/source/xray_attr_list.txt";
121 auto &Command
= emulateSingleCompilation(
125 "-fxray-always-instrument=" + XRayAllowlist
,
126 "-fxray-never-instrument=" + XRayIgnorelist
,
127 "-fxray-attr-list=" + XRayAttrList
,
129 /*ExtraFiles=*/{XRayAllowlist
, XRayIgnorelist
, XRayAttrList
});
131 // Ignorelists exist in the filesystem, so they should be added to the
132 // compilation command, produced by the driver.
133 EXPECT_THAT(Command
.getArguments(),
134 Contains(StrEq("-fxray-always-instrument=" + XRayAllowlist
)));
135 EXPECT_THAT(Command
.getArguments(),
136 Contains(StrEq("-fxray-never-instrument=" + XRayIgnorelist
)));
137 EXPECT_THAT(Command
.getArguments(),
138 Contains(StrEq("-fxray-attr-list=" + XRayAttrList
)));