[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