Skip to content

Commit f4ae919

Browse files
benlangmuirdvbuka
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
1 parent e58065e commit f4ae919

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
@@ -382,7 +382,8 @@ DignosticsEngineWithDiagOpts::DignosticsEngineWithDiagOpts(
382382

383383
std::pair<std::unique_ptr<driver::Driver>, std::unique_ptr<driver::Compilation>>
384384
buildCompilation(ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
385-
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
385+
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
386+
llvm::BumpPtrAllocator &Alloc) {
386387
SmallVector<const char *, 256> Argv;
387388
Argv.reserve(ArgStrs.size());
388389
for (const std::string &Arg : ArgStrs)
@@ -393,7 +394,6 @@ buildCompilation(ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
393394
"clang LLVM compiler", FS);
394395
Driver->setTitle("clang_based_tool");
395396

396-
llvm::BumpPtrAllocator Alloc;
397397
bool CLMode = driver::IsClangCL(
398398
driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
399399

clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h

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

106106
std::pair<std::unique_ptr<driver::Driver>, std::unique_ptr<driver::Compilation>>
107107
buildCompilation(ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
108-
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);
108+
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
109+
llvm::BumpPtrAllocator &Alloc);
109110

110111
std::unique_ptr<CompilerInvocation>
111112
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
@@ -78,8 +78,10 @@ static bool forEachDriverJob(
7878
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
7979
llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
8080
// Compilation holds a non-owning a reference to the Driver, hence we need to
81-
// keep the Driver alive when we use Compilation.
82-
auto [Driver, Compilation] = buildCompilation(ArgStrs, Diags, FS);
81+
// keep the Driver alive when we use Compilation. Arguments to commands may be
82+
// owned by Alloc when expanded from response files.
83+
llvm::BumpPtrAllocator Alloc;
84+
auto [Driver, Compilation] = buildCompilation(ArgStrs, Diags, FS, Alloc);
8385
if (!Compilation)
8486
return false;
8587
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
@@ -106,6 +106,7 @@ static constexpr bool DoRoundTripDefault = false;
106106
#endif
107107

108108
static bool RoundTripArgs = DoRoundTripDefault;
109+
static bool VerbatimArgs = false;
109110

110111
static void ParseArgs(int argc, char **argv) {
111112
ScanDepsOptTable Tbl;
@@ -239,6 +240,8 @@ static void ParseArgs(int argc, char **argv) {
239240

240241
RoundTripArgs = Args.hasArg(OPT_round_trip_args);
241242

243+
VerbatimArgs = Args.hasArg(OPT_verbatim_args);
244+
242245
if (const llvm::opt::Arg *A = Args.getLastArgNoClaim(OPT_DASH_DASH))
243246
CommandLine.assign(A->getValues().begin(), A->getValues().end());
244247
}
@@ -883,22 +886,24 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
883886

884887
llvm::cl::PrintOptionValues();
885888

886-
// Expand response files in advance, so that we can "see" all the arguments
887-
// when adjusting below.
888-
Compilations = expandResponseFiles(std::move(Compilations),
889-
llvm::vfs::getRealFileSystem());
889+
if (!VerbatimArgs) {
890+
// Expand response files in advance, so that we can "see" all the arguments
891+
// when adjusting below.
892+
Compilations = expandResponseFiles(std::move(Compilations),
893+
llvm::vfs::getRealFileSystem());
890894

891-
Compilations = inferTargetAndDriverMode(std::move(Compilations));
895+
Compilations = inferTargetAndDriverMode(std::move(Compilations));
892896

893-
Compilations = inferToolLocation(std::move(Compilations));
897+
Compilations = inferToolLocation(std::move(Compilations));
898+
}
894899

895900
// The command options are rewritten to run Clang in preprocessor only mode.
896901
auto AdjustingCompilations =
897902
std::make_unique<tooling::ArgumentsAdjustingCompilations>(
898903
std::move(Compilations));
899904
ResourceDirectoryCache ResourceDirCache;
900905

901-
AdjustingCompilations->appendArgumentsAdjuster(
906+
auto ArgsAdjuster =
902907
[&ResourceDirCache](const tooling::CommandLineArguments &Args,
903908
StringRef FileName) {
904909
std::string LastO;
@@ -960,7 +965,10 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
960965
}
961966
AdjustedArgs.insert(AdjustedArgs.end(), FlagsEnd, Args.end());
962967
return AdjustedArgs;
963-
});
968+
};
969+
970+
if (!VerbatimArgs)
971+
AdjustingCompilations->appendArgumentsAdjuster(ArgsAdjuster);
964972

965973
SharedStream Errs(llvm::errs());
966974

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

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

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

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

0 commit comments

Comments
 (0)