diff options
author | Shoaib Meenai <smeenai@fb.com> | 2019-06-10 23:24:02 +0000 |
---|---|---|
committer | Shoaib Meenai <smeenai@fb.com> | 2019-06-10 23:24:02 +0000 |
commit | 5062cf599ca2602f03c42404f3951449d24c5c8b (patch) | |
tree | 6807adaad11757b1d4be385a1f8527986fc0b819 /llvm/lib/Support/CommandLine.cpp | |
parent | 7ea131c20c113b78085301a1acd7b28884ec131e (diff) | |
download | bcm5719-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.cpp | 59 |
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; } |