[llvm] r268916 - Fix bug where temporary file would be left behind every time an archive was updated.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Mon May 9 06:31:12 PDT 2016


Author: rafael
Date: Mon May  9 08:31:11 2016
New Revision: 268916

URL: http://llvm.org/viewvc/llvm-project?rev=268916&view=rev
Log:
Fix  bug where temporary file would be left behind every time an archive was updated.

When updating an existing archive, llvm-ar opens the old archive into a
`MemoryBuffer`, does its thing, and writes the results to a temporary
file. That file is then renamed to the original archive filename, thus
replacing it with the updated contents. However, on Windows at least,
what would happen is that the `MemoryBuffer` for the old archive would
actually be an mmap'ed view of the file, so when it came time to do the
rename via Win32's `ReplaceFile`, it would succeed but would be unable
to fully replace the file since there would still be a handle open on
it; instead, the old version got renamed to a random temporary name and
left behind.

Patch by Cameron!

Modified:
    llvm/trunk/include/llvm/Object/ArchiveWriter.h
    llvm/trunk/lib/Object/ArchiveWriter.cpp
    llvm/trunk/tools/llvm-ar/llvm-ar.cpp

Modified: llvm/trunk/include/llvm/Object/ArchiveWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/ArchiveWriter.h?rev=268916&r1=268915&r2=268916&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/ArchiveWriter.h (original)
+++ llvm/trunk/include/llvm/Object/ArchiveWriter.h Mon May  9 08:31:11 2016
@@ -42,7 +42,7 @@ public:
 std::pair<StringRef, std::error_code>
 writeArchive(StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers,
              bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic,
-             bool Thin);
+             bool Thin, std::unique_ptr<MemoryBuffer> OldArchiveBuf = nullptr);
 }
 
 #endif

Modified: llvm/trunk/lib/Object/ArchiveWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/ArchiveWriter.cpp?rev=268916&r1=268915&r2=268916&view=diff
==============================================================================
--- llvm/trunk/lib/Object/ArchiveWriter.cpp (original)
+++ llvm/trunk/lib/Object/ArchiveWriter.cpp Mon May  9 08:31:11 2016
@@ -307,7 +307,8 @@ std::pair<StringRef, std::error_code>
 llvm::writeArchive(StringRef ArcName,
                    std::vector<NewArchiveIterator> &NewMembers,
                    bool WriteSymtab, object::Archive::Kind Kind,
-                   bool Deterministic, bool Thin) {
+                   bool Deterministic, bool Thin,
+                   std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
   assert((!Thin || Kind == object::Archive::K_GNU) &&
          "Only the gnu format has a thin mode");
   SmallString<128> TmpArchive;
@@ -443,6 +444,19 @@ llvm::writeArchive(StringRef ArcName,
 
   Output.keep();
   Out.close();
+
+  // At this point, we no longer need whatever backing memory
+  // was used to generate the NewMembers. On Windows, this buffer
+  // could be a mapped view of the file we want to replace (if
+  // we're updating an existing archive, say). In that case, the
+  // rename would still succeed, but it would leave behind a
+  // temporary file (actually the original file renamed) because
+  // a file cannot be deleted while there's a handle open on it,
+  // only renamed. So by freeing this buffer, this ensures that
+  // the last open handle on the destination file, if any, is
+  // closed before we attempt to rename.
+  OldArchiveBuf.reset();
+
   sys::fs::rename(TmpArchive, ArcName);
   return std::make_pair("", std::error_code());
 }

Modified: llvm/trunk/tools/llvm-ar/llvm-ar.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/llvm-ar.cpp?rev=268916&r1=268915&r2=268916&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-ar/llvm-ar.cpp (original)
+++ llvm/trunk/tools/llvm-ar/llvm-ar.cpp Mon May  9 08:31:11 2016
@@ -576,7 +576,9 @@ computeNewArchiveMembers(ArchiveOperatio
 }
 
 static void
-performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive,
+performWriteOperation(ArchiveOperation Operation,
+                      object::Archive *OldArchive,
+                      std::unique_ptr<MemoryBuffer> OldArchiveBuf,
                       std::vector<NewArchiveIterator> *NewMembersP) {
   object::Archive::Kind Kind;
   switch (FormatOpt) {
@@ -599,14 +601,16 @@ performWriteOperation(ArchiveOperation O
   }
   if (NewMembersP) {
     std::pair<StringRef, std::error_code> Result = writeArchive(
-        ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin);
+        ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin,
+        std::move(OldArchiveBuf));
     failIfError(Result.second, Result.first);
     return;
   }
   std::vector<NewArchiveIterator> NewMembers =
       computeNewArchiveMembers(Operation, OldArchive);
   auto Result =
-      writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin);
+      writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin,
+      std::move(OldArchiveBuf));
   failIfError(Result.second, Result.first);
 }
 
@@ -620,11 +624,12 @@ static void createSymbolTable(object::Ar
   if (OldArchive->hasSymbolTable())
     return;
 
-  performWriteOperation(CreateSymTab, OldArchive, nullptr);
+  performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr);
 }
 
 static void performOperation(ArchiveOperation Operation,
                              object::Archive *OldArchive,
+                             std::unique_ptr<MemoryBuffer> OldArchiveBuf,
                              std::vector<NewArchiveIterator> *NewMembers) {
   switch (Operation) {
   case Print:
@@ -637,7 +642,8 @@ static void performOperation(ArchiveOper
   case Move:
   case QuickAppend:
   case ReplaceOrInsert:
-    performWriteOperation(Operation, OldArchive, NewMembers);
+    performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf),
+                          NewMembers);
     return;
   case CreateSymTab:
     createSymbolTable(OldArchive);
@@ -659,7 +665,7 @@ static int performOperation(ArchiveOpera
     object::Archive Archive(Buf.get()->getMemBufferRef(), EC);
     failIfError(EC,
                 "error loading '" + ArchiveName + "': " + EC.message() + "!");
-    performOperation(Operation, &Archive, NewMembers);
+    performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers);
     return 0;
   }
 
@@ -674,7 +680,7 @@ static int performOperation(ArchiveOpera
     }
   }
 
-  performOperation(Operation, nullptr, NewMembers);
+  performOperation(Operation, nullptr, nullptr, NewMembers);
   return 0;
 }
 




More information about the llvm-commits mailing list