[lld] r241988 - elf: Make error output from AtomSection<ELFT>::write() deterministic.

Nico Weber nicolasweber at gmx.de
Sat Jul 11 21:45:35 PDT 2015


Author: nico
Date: Sat Jul 11 23:45:35 2015
New Revision: 241988

URL: http://llvm.org/viewvc/llvm-project?rev=241988&view=rev
Log:
elf: Make error output from AtomSection<ELFT>::write() deterministic.

The function uses parallel_for() and then writes error messages from the
parallel loop's body.  This produces nondetermistic error messages.  Instead,
copy error messages to a vector and sort it by the atom's file offsets before
printing all error messages after the parallel_for().  This results in a few
string copies, but only in the error case.  (And passing tests seem more
important than performance.)

This makes tests elf/AArch64/rel-prel16-overflow.test and
elf/AArch64/rel-prel32-overflow.test pass on Windows: Both tests check that
atom error messages are emitted in a certain order, and on Windows they
happened to be emitted in a different order before this patch.

Modified:
    lld/trunk/lib/ReaderWriter/ELF/SectionChunks.cpp
    lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h

Modified: lld/trunk/lib/ReaderWriter/ELF/SectionChunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SectionChunks.cpp?rev=241988&r1=241987&r2=241988&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SectionChunks.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SectionChunks.cpp Sat Jul 11 23:45:35 2015
@@ -118,26 +118,22 @@ AtomSection<ELFT>::findAtomLayoutByName(
 }
 
 template <class ELFT>
-void AtomSection<ELFT>::printError(const std::string &errorStr,
-                                   const AtomLayout &atom,
-                                   const Reference &ref) const {
+std::string AtomSection<ELFT>::formatError(const std::string &errorStr,
+                                           const AtomLayout &atom,
+                                           const Reference &ref) const {
   StringRef kindValStr;
   if (!this->_ctx.registry().referenceKindToString(
           ref.kindNamespace(), ref.kindArch(), ref.kindValue(), kindValStr)) {
     kindValStr = "unknown";
   }
 
-  std::string errStr =
+  return
       (Twine(errorStr) + " in file " + atom._atom->file().path() +
        ": reference from " + atom._atom->name() + "+" +
        Twine(ref.offsetInAtom()) + " to " + ref.target()->name() + "+" +
        Twine(ref.addend()) + " of type " + Twine(ref.kindValue()) + " (" +
        kindValStr + ")\n")
           .str();
-
-  // Take the lock to prevent output getting interleaved between threads
-  std::lock_guard<std::mutex> lock(_outputMutex);
-  llvm::errs() << errStr;
 }
 
 /// Align the offset to the required modulus defined by the atom alignment
@@ -249,6 +245,11 @@ void AtomSection<ELFT>::write(ELFWriter
                               llvm::FileOutputBuffer &buffer) {
   uint8_t *chunkBuffer = buffer.getBufferStart();
   bool success = true;
+
+  // parallel_for_each() doesn't have deterministic order.  To guarantee
+  // deterministic error output, collect errors in this vector and sort it
+  // by atom file offset before printing all errors.
+  std::vector<std::pair<size_t, std::string>> errors;
   parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
     DEBUG_WITH_TYPE("Section", llvm::dbgs()
                                    << "Writing atom: " << ai->_atom->name()
@@ -268,13 +269,19 @@ void AtomSection<ELFT>::write(ELFWriter
     for (const auto ref : *definedAtom) {
       if (std::error_code ec =
               relHandler.applyRelocation(*writer, buffer, *ai, *ref)) {
-        printError(ec.message(), *ai, *ref);
+        std::lock_guard<std::mutex> lock(_outputMutex);
+        errors.push_back(std::make_pair(ai->_fileOffset,
+                                        formatError(ec.message(), *ai, *ref)));
         success = false;
       }
     }
   });
-  if (!success)
+  if (!success) {
+    std::sort(errors.begin(), errors.end());
+    for (auto &&error : errors)
+      llvm::errs() << error.second;
     llvm::report_fatal_error("relocating output");
+  }
 }
 
 template <class ELFT>

Modified: lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h?rev=241988&r1=241987&r2=241988&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h Sat Jul 11 23:45:35 2015
@@ -195,8 +195,8 @@ protected:
   std::vector<AtomLayout *> _atoms;
   mutable std::mutex _outputMutex;
 
-  void printError(const std::string &errorStr, const AtomLayout &atom,
-                  const Reference &ref) const;
+  std::string formatError(const std::string &errorStr, const AtomLayout &atom,
+                          const Reference &ref) const;
 };
 
 /// \brief A OutputSection represents a set of sections grouped by the same





More information about the llvm-commits mailing list