Skip to content

Commit a5d76b3

Browse files
benlangmuirqiongsiwu
authored andcommitted
[clang][deps] Fix a use-after-free from expanding response files (llvm#164676)
In 4368616 we accidentally moved uses of command-line args saved into a bump pointer allocator during response file expansion out of scope of the allocator. Also, the test that should have caught this (at least with asan) was not working correctly because clang-scan-deps was expanding response files itself during argument adjustment rather than the underlying scanner library. rdar://162720059 (cherry picked from commit 3e6f696)
1 parent 579e9f0 commit a5d76b3

File tree

6 files changed

+30
-15
lines changed

6 files changed

+30
-15
lines changed

clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,8 @@ DignosticsEngineWithDiagOpts::DignosticsEngineWithDiagOpts(
508508

509509
std::pair<std::unique_ptr<driver::Driver>, std::unique_ptr<driver::Compilation>>
510510
buildCompilation(ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
511-
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
511+
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
512+
llvm::BumpPtrAllocator &Alloc) {
512513
SmallVector<const char *, 256> Argv;
513514
Argv.reserve(ArgStrs.size());
514515
for (const std::string &Arg : ArgStrs)
@@ -519,7 +520,6 @@ buildCompilation(ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
519520
"clang LLVM compiler", FS);
520521
Driver->setTitle("clang_based_tool");
521522

522-
llvm::BumpPtrAllocator Alloc;
523523
bool CLMode = driver::IsClangCL(
524524
driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
525525

clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ struct TextDiagnosticsPrinterWithOutput {
114114

115115
std::pair<std::unique_ptr<driver::Driver>, std::unique_ptr<driver::Compilation>>
116116
buildCompilation(ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
117-
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);
117+
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
118+
llvm::BumpPtrAllocator &Alloc);
118119

119120
std::unique_ptr<CompilerInvocation>
120121
createCompilerInvocation(ArrayRef<std::string> CommandLine,

clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,10 @@ static bool forEachDriverJob(
9292
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
9393
llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
9494
// Compilation holds a non-owning a reference to the Driver, hence we need to
95-
// keep the Driver alive when we use Compilation.
96-
auto [Driver, Compilation] = buildCompilation(ArgStrs, Diags, FS);
95+
// keep the Driver alive when we use Compilation. Arguments to commands may be
96+
// owned by Alloc when expanded from response files.
97+
llvm::BumpPtrAllocator Alloc;
98+
auto [Driver, Compilation] = buildCompilation(ArgStrs, Diags, FS, Alloc);
9799
if (!Compilation)
98100
return false;
99101
for (const driver::Command &Job : Compilation->getJobs()) {

clang/test/ClangScanDeps/response-file.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
// Check that the scanner can handle a response file input.
1+
// Check that the scanner can handle a response file input. Uses -verbatim-args
2+
// to ensure response files are expanded by the scanner library and not the
3+
// argumeent adjuster in clang-scan-deps.
24

35
// RUN: rm -rf %t
46
// RUN: split-file %s %t
57
// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
68

7-
// RUN: clang-scan-deps -format experimental-full -compilation-database %t/cdb.json > %t/deps.json
9+
// RUN: clang-scan-deps -verbatim-args -format experimental-full -compilation-database %t/cdb.json > %t/deps.json
810

911
// RUN: cat %t/deps.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s
1012

clang/tools/clang-scan-deps/ClangScanDeps.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ static constexpr bool DoRoundTripDefault = false;
121121
#endif
122122

123123
static bool RoundTripArgs = DoRoundTripDefault;
124+
static bool VerbatimArgs = false;
124125

125126
static void ParseArgs(int argc, char **argv) {
126127
ScanDepsOptTable Tbl;
@@ -277,6 +278,8 @@ static void ParseArgs(int argc, char **argv) {
277278

278279
RoundTripArgs = Args.hasArg(OPT_round_trip_args);
279280

281+
VerbatimArgs = Args.hasArg(OPT_verbatim_args);
282+
280283
if (const llvm::opt::Arg *A = Args.getLastArgNoClaim(OPT_DASH_DASH))
281284
CommandLine.assign(A->getValues().begin(), A->getValues().end());
282285
}
@@ -1167,22 +1170,24 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
11671170

11681171
llvm::cl::PrintOptionValues();
11691172

1170-
// Expand response files in advance, so that we can "see" all the arguments
1171-
// when adjusting below.
1172-
Compilations = expandResponseFiles(std::move(Compilations),
1173-
llvm::vfs::getRealFileSystem());
1173+
if (!VerbatimArgs) {
1174+
// Expand response files in advance, so that we can "see" all the arguments
1175+
// when adjusting below.
1176+
Compilations = expandResponseFiles(std::move(Compilations),
1177+
llvm::vfs::getRealFileSystem());
11741178

1175-
Compilations = inferTargetAndDriverMode(std::move(Compilations));
1179+
Compilations = inferTargetAndDriverMode(std::move(Compilations));
11761180

1177-
Compilations = inferToolLocation(std::move(Compilations));
1181+
Compilations = inferToolLocation(std::move(Compilations));
1182+
}
11781183

11791184
// The command options are rewritten to run Clang in preprocessor only mode.
11801185
auto AdjustingCompilations =
11811186
std::make_unique<tooling::ArgumentsAdjustingCompilations>(
11821187
std::move(Compilations));
11831188
ResourceDirectoryCache ResourceDirCache;
11841189

1185-
AdjustingCompilations->appendArgumentsAdjuster(
1190+
auto ArgsAdjuster =
11861191
[&ResourceDirCache](const tooling::CommandLineArguments &Args,
11871192
StringRef FileName) {
11881193
if (EmitCASCompDB)
@@ -1255,7 +1260,10 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
12551260
AdjustedArgs.push_back("-fdepscan-prefix-map=" + std::string(Map));
12561261
}
12571262
return AdjustedArgs;
1258-
});
1263+
};
1264+
1265+
if (!VerbatimArgs)
1266+
AdjustingCompilations->appendArgumentsAdjuster(ArgsAdjuster);
12591267

12601268
SharedStream Errs(llvm::errs());
12611269

clang/tools/clang-scan-deps/Opts.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,6 @@ def verbose : F<"v", "Use verbose output">;
5959

6060
def round_trip_args : F<"round-trip-args", "verify that command-line arguments are canonical by parsing and re-serializing">;
6161

62+
def verbatim_args : F<"verbatim-args", "Pass commands to the scanner verbatim without adjustments">;
63+
6264
def DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>;

0 commit comments

Comments
 (0)