diff options
-rw-r--r-- | llvm/lib/Support/CommandLine.cpp | 10 | ||||
-rw-r--r-- | llvm/unittests/Support/CommandLineTest.cpp | 37 |
2 files changed, 43 insertions, 4 deletions
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 98d06f65c79..0050002ff05 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -1040,7 +1040,7 @@ static bool ExpandResponseFile(StringRef FName, StringSaver &Saver, bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, SmallVectorImpl<const char *> &Argv, bool MarkEOLs, bool RelativeNames) { - unsigned RspFiles = 0; + unsigned ExpandedRspFiles = 0; bool AllExpanded = true; // Don't cache Argv.size() because it can change. @@ -1058,14 +1058,16 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, // If we have too many response files, leave some unexpanded. This avoids // crashing on self-referential response files. - if (RspFiles++ > 20) + if (ExpandedRspFiles > 20) return false; // Replace this response file argument with the tokenization of its // contents. Nested response files are expanded in subsequent iterations. SmallVector<const char *, 0> ExpandedArgv; - if (!ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv, - MarkEOLs, RelativeNames)) { + if (ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv, MarkEOLs, + RelativeNames)) { + ++ExpandedRspFiles; + } else { // We couldn't read this file, so we leave it in the argument stream and // move on. AllExpanded = false; diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp index 263d0e30191..b648600b908 100644 --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -816,6 +816,43 @@ TEST(CommandLineTest, RecursiveResponseFiles) { EXPECT_STREQ(Argv[i], ResponseFileRef.c_str()); } +TEST(CommandLineTest, ResponseFilesAtArguments) { + SmallString<128> TestDir; + std::error_code EC = sys::fs::createUniqueDirectory("unittest", TestDir); + EXPECT_TRUE(!EC); + + SmallString<128> ResponseFilePath; + sys::path::append(ResponseFilePath, TestDir, "test.rsp"); + + std::ofstream ResponseFile(ResponseFilePath.c_str()); + EXPECT_TRUE(ResponseFile.is_open()); + ResponseFile << "-foo" << "\n"; + ResponseFile << "-bar" << "\n"; + ResponseFile.close(); + + // Ensure we expand rsp files after lots of non-rsp arguments starting with @. + constexpr size_t NON_RSP_AT_ARGS = 64; + SmallVector<const char *, 4> Argv = {"test/test"}; + Argv.append(NON_RSP_AT_ARGS, "@non_rsp_at_arg"); + std::string ResponseFileRef = std::string("@") + ResponseFilePath.c_str(); + Argv.push_back(ResponseFileRef.c_str()); + + BumpPtrAllocator A; + StringSaver Saver(A); + bool Res = cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv, + false, false); + EXPECT_FALSE(Res); + + // ASSERT instead of EXPECT to prevent potential out-of-bounds access. + ASSERT_EQ(Argv.size(), 1 + NON_RSP_AT_ARGS + 2); + size_t i = 0; + EXPECT_STREQ(Argv[i++], "test/test"); + for (; i < 1 + NON_RSP_AT_ARGS; ++i) + EXPECT_STREQ(Argv[i], "@non_rsp_at_arg"); + EXPECT_STREQ(Argv[i++], "-foo"); + EXPECT_STREQ(Argv[i++], "-bar"); +} + TEST(CommandLineTest, SetDefautValue) { cl::ResetCommandLineParser(); |