summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/CommandLine.cpp
diff options
context:
space:
mode:
authorShoaib Meenai <smeenai@fb.com>2019-06-10 23:24:02 +0000
committerShoaib Meenai <smeenai@fb.com>2019-06-10 23:24:02 +0000
commit5062cf599ca2602f03c42404f3951449d24c5c8b (patch)
tree6807adaad11757b1d4be385a1f8527986fc0b819 /llvm/lib/Support/CommandLine.cpp
parent7ea131c20c113b78085301a1acd7b28884ec131e (diff)
downloadbcm5719-llvm-5062cf599ca2602f03c42404f3951449d24c5c8b.tar.gz
bcm5719-llvm-5062cf599ca2602f03c42404f3951449d24c5c8b.zip
[Support] Explicitly detect recursive response files
Previous detection relied upon an arbitrary hard coded limit of 21 response files, which some code bases were running up against. The new detection maintains a stack of processing response files and explicitly checks if a newly encountered file is in the current stack. Some bookkeeping data is necessary in order to detect when to pop the stack. Patch by Chris Glover. Differential Revision: https://reviews.llvm.org/D62798 llvm-svn: 363005
Diffstat (limited to 'llvm/lib/Support/CommandLine.cpp')
-rw-r--r--llvm/lib/Support/CommandLine.cpp59
1 files changed, 50 insertions, 9 deletions
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index 3d82f159701..25510fa58ff 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -1097,43 +1097,84 @@ static bool ExpandResponseFile(StringRef FName, StringSaver &Saver,
bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
SmallVectorImpl<const char *> &Argv,
bool MarkEOLs, bool RelativeNames) {
- unsigned ExpandedRspFiles = 0;
bool AllExpanded = true;
+ struct ResponseFileRecord {
+ const char *File;
+ size_t End;
+ };
+
+ // To detect recursive response files, we maintain a stack of files and the
+ // position of the last argument in the file. This position is updated
+ // dynamically as we recursively expand files.
+ SmallVector<ResponseFileRecord, 3> FileStack;
+
+ // Push a dummy entry that represents the initial command line, removing
+ // the need to check for an empty list.
+ FileStack.push_back({"", Argv.size()});
// Don't cache Argv.size() because it can change.
for (unsigned I = 0; I != Argv.size();) {
+ while (I == FileStack.back().End) {
+ // Passing the end of a file's argument list, so we can remove it from the
+ // stack.
+ FileStack.pop_back();
+ }
+
const char *Arg = Argv[I];
// Check if it is an EOL marker
if (Arg == nullptr) {
++I;
continue;
}
+
if (Arg[0] != '@') {
++I;
continue;
}
- // If we have too many response files, leave some unexpanded. This avoids
- // crashing on self-referential response files.
- if (ExpandedRspFiles > 20)
- return false;
+ const char *FName = Arg + 1;
+ auto IsEquivalent = [FName](const ResponseFileRecord &RFile) {
+ return sys::fs::equivalent(RFile.File, FName);
+ };
+
+ // Check for recursive response files.
+ if (std::any_of(FileStack.begin() + 1, FileStack.end(), IsEquivalent)) {
+ // This file is recursive, so we leave it in the argument stream and
+ // move on.
+ AllExpanded = false;
+ ++I;
+ continue;
+ }
// 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)) {
- ++ExpandedRspFiles;
- } else {
+ if (!ExpandResponseFile(FName, Saver, Tokenizer, ExpandedArgv, MarkEOLs,
+ RelativeNames)) {
// We couldn't read this file, so we leave it in the argument stream and
// move on.
AllExpanded = false;
++I;
continue;
}
+
+ for (ResponseFileRecord &Record : FileStack) {
+ // Increase the end of all active records by the number of newly expanded
+ // arguments, minus the response file itself.
+ Record.End += ExpandedArgv.size() - 1;
+ }
+
+ FileStack.push_back({FName, I + ExpandedArgv.size()});
Argv.erase(Argv.begin() + I);
Argv.insert(Argv.begin() + I, ExpandedArgv.begin(), ExpandedArgv.end());
}
+
+ // If successful, the top of the file stack will mark the end of the Argv
+ // stream. A failure here indicates a bug in the stack popping logic above.
+ // Note that FileStack may have more than one element at this point because we
+ // don't have a chance to pop the stack when encountering recursive files at
+ // the end of the stream, so seeing that doesn't indicate a bug.
+ assert(FileStack.size() > 0 && Argv.size() == FileStack.back().End);
return AllExpanded;
}
OpenPOWER on IntegriCloud