[lld] c42fe24 - [lld/ELF] PR44498: Support input filename in double quote

Thomas Preud'homme via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 22 04:03:19 PST 2020


Author: Thomas Preud'homme
Date: 2020-01-22T12:03:10Z
New Revision: c42fe24754f4a2173d16b799085cec88cad6f24c

URL: https://github.com/llvm/llvm-project/commit/c42fe24754f4a2173d16b799085cec88cad6f24c
DIFF: https://github.com/llvm/llvm-project/commit/c42fe24754f4a2173d16b799085cec88cad6f24c.diff

LOG: [lld/ELF] PR44498: Support input filename in double quote

Summary:
Linker scripts allow filenames to be put in double quotes to prevent
characters in filenames that are part of the linker script syntax from
having their special meaning. Case in point the * wildcard character.

Availability of double quoting filenames also allows to fix a failure in
ELF/linkerscript/filename-spec.s when the path contain a @ which the
lexer consider as a special characters and thus break up a filename
containing it. This may happens under Jenkins which createspath such as
pipeline at 2.

To avoid the need for escaping GlobPattern metacharacters in filename
in double quotes, GlobPattern::create is augmented with a new parameter
to request literal matching instead of relying on the presence of a
wildcard character in the pattern.

Reviewers: jhenderson, MaskRay, evgeny777, espindola, alexshap

Reviewed By: MaskRay

Subscribers: peter.smith, grimar, ruiu, emaste, arichardson, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72517

Added: 
    

Modified: 
    lld/Common/Strings.cpp
    lld/ELF/LinkerScript.h
    lld/ELF/ScriptParser.cpp
    lld/ELF/SymbolTable.cpp
    lld/include/lld/Common/Strings.h
    lld/test/ELF/linkerscript/filename-spec.s

Removed: 
    


################################################################################
diff  --git a/lld/Common/Strings.cpp b/lld/Common/Strings.cpp
index 627435f141da..c5ddcc2d0566 100644
--- a/lld/Common/Strings.cpp
+++ b/lld/Common/Strings.cpp
@@ -31,18 +31,28 @@ std::string lld::demangleItanium(StringRef name) {
   return demangle(name);
 }
 
-StringMatcher::StringMatcher(ArrayRef<StringRef> pat) {
-  for (StringRef s : pat) {
-    Expected<GlobPattern> pat = GlobPattern::create(s);
-    if (!pat)
-      error(toString(pat.takeError()));
-    else
-      patterns.push_back(*pat);
+SingleStringMatcher::SingleStringMatcher(StringRef Pattern) {
+  if (Pattern.size() > 2 && Pattern.startswith("\"") &&
+      Pattern.endswith("\"")) {
+    ExactMatch = true;
+    ExactPattern = Pattern.substr(1, Pattern.size() - 2);
+  } else {
+    Expected<GlobPattern> Glob = GlobPattern::create(Pattern);
+    if (!Glob) {
+      error(toString(Glob.takeError()));
+      return;
+    }
+    ExactMatch = false;
+    GlobPatternMatcher = *Glob;
   }
 }
 
+bool SingleStringMatcher::match(StringRef s) const {
+  return ExactMatch ? (ExactPattern == s) : GlobPatternMatcher.match(s);
+}
+
 bool StringMatcher::match(StringRef s) const {
-  for (const GlobPattern &pat : patterns)
+  for (const SingleStringMatcher &pat : patterns)
     if (pat.match(s))
       return true;
   return false;

diff  --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index d57301cf3524..f43a66080e05 100644
--- a/lld/ELF/LinkerScript.h
+++ b/lld/ELF/LinkerScript.h
@@ -164,7 +164,7 @@ struct InputSectionDescription : BaseCommand {
     return c->kind == InputSectionKind;
   }
 
-  StringMatcher filePat;
+  SingleStringMatcher filePat;
 
   // Input sections that matches at least one of SectionPatterns
   // will be associated with this InputSectionDescription.

diff  --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index f62a0d133afd..a0d763eca324 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -597,10 +597,11 @@ static int precedence(StringRef op) {
 }
 
 StringMatcher ScriptParser::readFilePatterns() {
-  std::vector<StringRef> v;
+  StringMatcher Matcher;
+
   while (!errorCount() && !consume(")"))
-    v.push_back(next());
-  return StringMatcher(v);
+    Matcher.addPattern(SingleStringMatcher(next()));
+  return Matcher;
 }
 
 SortSectionPolicy ScriptParser::readSortKind() {
@@ -637,12 +638,12 @@ std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
       excludeFilePat = readFilePatterns();
     }
 
-    std::vector<StringRef> v;
+    StringMatcher SectionMatcher;
     while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE")
-      v.push_back(unquote(next()));
+      SectionMatcher.addPattern(unquote(next()));
 
-    if (!v.empty())
-      ret.push_back({std::move(excludeFilePat), StringMatcher(v)});
+    if (!SectionMatcher.empty())
+      ret.push_back({std::move(excludeFilePat), std::move(SectionMatcher)});
     else
       setError("section pattern is expected");
   }
@@ -864,7 +865,7 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
       // handle this case here as it will already have been matched by the
       // case above.
       auto *isd = make<InputSectionDescription>(tok);
-      isd->sectionPatterns.push_back({{}, StringMatcher({"*"})});
+      isd->sectionPatterns.push_back({{}, StringMatcher("*")});
       cmd->sectionCommands.push_back(isd);
     }
   }

diff  --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index f7a8a99cf8f9..1f5d5981928c 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -139,7 +139,7 @@ std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion ver) {
 
 std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion ver) {
   std::vector<Symbol *> res;
-  StringMatcher m(ver.name);
+  SingleStringMatcher m(ver.name);
 
   if (ver.isExternCpp) {
     for (auto &p : getDemangledSyms())

diff  --git a/lld/include/lld/Common/Strings.h b/lld/include/lld/Common/Strings.h
index 9d002bf336de..3940d2443cd4 100644
--- a/lld/include/lld/Common/Strings.h
+++ b/lld/include/lld/Common/Strings.h
@@ -27,16 +27,52 @@ bool isValidCIdentifier(llvm::StringRef s);
 // Write the contents of the a buffer to a file
 void saveBuffer(llvm::StringRef buffer, const llvm::Twine &path);
 
-// This class represents multiple glob patterns.
-class StringMatcher {
+// A single pattern to match against. A pattern can either be double-quoted
+// text that should be matched exactly after removing the quoting marks or a
+// glob pattern in the sense of GlobPattern.
+class SingleStringMatcher {
 public:
-  StringMatcher() = default;
-  explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> pat);
+  // Create a StringPattern from Pattern to be matched exactly irregardless
+  // of globbing characters if ExactMatch is true.
+  SingleStringMatcher(llvm::StringRef Pattern);
 
+  // Match s against this pattern, exactly if ExactMatch is true.
   bool match(llvm::StringRef s) const;
 
 private:
-  std::vector<llvm::GlobPattern> patterns;
+  // Whether to do an exact match irregardless of the presence of wildcard
+  // character.
+  bool ExactMatch;
+
+  // GlobPattern object if not doing an exact match.
+  llvm::GlobPattern GlobPatternMatcher;
+
+  // StringRef to match exactly if doing an exact match.
+  llvm::StringRef ExactPattern;
+};
+
+// This class represents multiple patterns to match against. A pattern can
+// either be a double-quoted text that should be matched exactly after removing
+// the quoted marks or a glob pattern.
+class StringMatcher {
+private:
+  // Patterns to match against.
+  std::vector<SingleStringMatcher> patterns;
+
+public:
+  StringMatcher() = default;
+
+  // Matcher for a single pattern.
+  StringMatcher(llvm::StringRef Pattern)
+      : patterns({SingleStringMatcher(Pattern)}) {}
+
+  // Add a new pattern to the existing ones to match against.
+  void addPattern(SingleStringMatcher Matcher) { patterns.push_back(Matcher); }
+
+  bool empty() { return patterns.empty(); }
+
+  // Match s against the patterns.
+  bool match(llvm::StringRef s) const;
 };
 
 } // namespace lld

diff  --git a/lld/test/ELF/linkerscript/filename-spec.s b/lld/test/ELF/linkerscript/filename-spec.s
index de9c7b6f8355..82fc4f4c7465 100644
--- a/lld/test/ELF/linkerscript/filename-spec.s
+++ b/lld/test/ELF/linkerscript/filename-spec.s
@@ -30,12 +30,12 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
 # RUN:   %p/Inputs/filename-spec.s -o %t.dir/filename-spec2.o
 
-# RUN: echo "SECTIONS{.foo :{ %/t.dir/filename-spec2.o(.foo) %/t.dir/filename-spec1.o(.foo) }}" > %t5.script
+# RUN: echo "SECTIONS{.foo :{ \"%/t.dir/filename-spec2.o\"(.foo) \"%/t.dir/filename-spec1.o\"(.foo) }}" > %t5.script
 # RUN: ld.lld -o %t5 --script %t5.script \
 # RUN:   %/t.dir/filename-spec1.o %/t.dir/filename-spec2.o
 # RUN: llvm-objdump -s %t5 | FileCheck --check-prefix=SECONDFIRST %s
 
-# RUN: echo "SECTIONS{.foo :{ %/t.dir/filename-spec1.o(.foo) %/t.dir/filename-spec2.o(.foo) }}" > %t6.script
+# RUN: echo "SECTIONS{.foo :{ \"%/t.dir/filename-spec1.o\"(.foo) \"%/t.dir/filename-spec2.o\"(.foo) }}" > %t6.script
 # RUN: ld.lld -o %t6 --script %t6.script \
 # RUN:   %/t.dir/filename-spec1.o %/t.dir/filename-spec2.o
 # RUN: llvm-objdump -s %t6 | FileCheck --check-prefix=FIRSTY %s


        


More information about the llvm-commits mailing list