Skip to content

Commit

Permalink
[dsymutil] Simplify temporary file handling.
Browse files Browse the repository at this point in the history
Dsymutil's update functionality was broken on Windows because we tried
to rename a file while we're holding open handles to that file. TempFile
provides a solution for this through its keep(Twine) method. This patch
changes dsymutil to make use of that functionality.

Differential revision: https://reviews.llvm.org/D49860

llvm-svn: 338216
  • Loading branch information
JDevlieghere committed Jul 29, 2018
1 parent f52eeb1 commit ae1727e
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 62 deletions.
10 changes: 7 additions & 3 deletions llvm/lib/Support/Path.cpp
Expand Up @@ -1157,9 +1157,13 @@ Error TempFile::keep(const Twine &Name) {
setDeleteDisposition(H, true);
#else
std::error_code RenameEC = fs::rename(TmpName, Name);
// If we can't rename, discard the temporary file.
if (RenameEC)
remove(TmpName);
if (RenameEC) {
// If we can't rename, try to copy to work around cross-device link issues.
RenameEC = sys::fs::copy_file(TmpName, Name);
// If we can't rename or copy, discard the temporary file.
if (RenameEC)
remove(TmpName);
}
sys::DontRemoveFileOnSignal(TmpName);
#endif

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Support/Windows/Path.inc
Expand Up @@ -450,7 +450,7 @@ static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) {
if (std::error_code EC2 = realPathFromHandle(FromHandle, WideFrom))
return EC2;
if (::MoveFileExW(WideFrom.begin(), WideTo.begin(),
MOVEFILE_REPLACE_EXISTING))
MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
return std::error_code();
return mapWindowsError(GetLastError());
}
Expand Down
4 changes: 0 additions & 4 deletions llvm/test/tools/dsymutil/X86/accelerator.test
@@ -1,7 +1,3 @@
UNSUPPORTED: system-windows
Windows does not like renaming files that have open handles to them. We
need to use TempFile::keep to move them in a portable way.

RUN: dsymutil -accelerator=Dwarf -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 -o %t.dwarf.dSYM
RUN: dsymutil -accelerator=Apple -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 -o %t.apple.dSYM

Expand Down
4 changes: 0 additions & 4 deletions llvm/test/tools/dsymutil/X86/update-one-CU.test
@@ -1,7 +1,3 @@
UNSUPPORTED: system-windows
Windows does not like renaming files that have open handles to them. We
need to use TempFile::keep to move them in a portable way.

RUN: dsymutil -oso-prepend-path=%p/.. %p/../Inputs/objc.macho.x86_64 -o %t.dSYM
RUN: dsymutil -update %t.dSYM
RUN: llvm-dwarfdump -apple-types -apple-objc %t.dSYM | FileCheck %s
Expand Down
4 changes: 0 additions & 4 deletions llvm/test/tools/dsymutil/X86/update.test
@@ -1,7 +1,3 @@
UNSUPPORTED: system-windows
Windows does not like renaming files that have open handles to them. We
need to use TempFile::keep to move them in a portable way.

RUN: rm -rf %t.dir
RUN: mkdir -p %t.dir
RUN: cat %p/../Inputs/basic.macho.x86_64 > %t.dir/basic
Expand Down
42 changes: 29 additions & 13 deletions llvm/tools/dsymutil/MachOUtils.cpp
Expand Up @@ -27,6 +27,27 @@ namespace llvm {
namespace dsymutil {
namespace MachOUtils {

llvm::Error ArchAndFile::createTempFile() {
llvm::SmallString<128> TmpModel;
llvm::sys::path::system_temp_directory(true, TmpModel);
llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf");
Expected<sys::fs::TempFile> T = sys::fs::TempFile::create(TmpModel);

if (!T)
return T.takeError();

File = llvm::Optional<sys::fs::TempFile>(std::move(*T));
return Error::success();
}

llvm::StringRef ArchAndFile::path() const { return File->TmpName; }

ArchAndFile::~ArchAndFile() {
if (File)
if (auto E = File->discard())
llvm::consumeError(std::move(E));
}

std::string getArchName(StringRef Arch) {
if (Arch.startswith("thumb"))
return (llvm::Twine("arm") + Arch.drop_front(5)).str();
Expand All @@ -53,21 +74,16 @@ static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) {
return true;
}

bool generateUniversalBinary(SmallVectorImpl<ArchAndFilename> &ArchFiles,
bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
StringRef OutputFileName,
const LinkOptions &Options, StringRef SDKPath) {
// No need to merge one file into a universal fat binary. First, try
// to move it (rename) to the final location. If that fails because
// of cross-device link issues then copy and delete.
// No need to merge one file into a universal fat binary.
if (ArchFiles.size() == 1) {
StringRef From(ArchFiles.front().Path);
if (sys::fs::rename(From, OutputFileName)) {
if (std::error_code EC = sys::fs::copy_file(From, OutputFileName)) {
WithColor::error() << "while copying " << From << " to "
<< OutputFileName << ": " << EC.message() << "\n";
return false;
}
sys::fs::remove(From);
if (auto E = ArchFiles.front().File->keep(OutputFileName)) {
WithColor::error() << "while keeping " << ArchFiles.front().path()
<< " as " << OutputFileName << ": "
<< toString(std::move(E)) << "\n";
return false;
}
return true;
}
Expand All @@ -77,7 +93,7 @@ bool generateUniversalBinary(SmallVectorImpl<ArchAndFilename> &ArchFiles,
Args.push_back("-create");

for (auto &Thin : ArchFiles)
Args.push_back(Thin.Path);
Args.push_back(Thin.path());

// Align segments to match dsymutil-classic alignment
for (auto &Thin : ArchFiles) {
Expand Down
17 changes: 13 additions & 4 deletions llvm/tools/dsymutil/MachOUtils.h
Expand Up @@ -10,6 +10,7 @@
#define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
#include <string>

namespace llvm {
Expand All @@ -20,12 +21,20 @@ class DebugMap;
struct LinkOptions;
namespace MachOUtils {

struct ArchAndFilename {
std::string Arch, Path;
ArchAndFilename(StringRef Arch, StringRef Path) : Arch(Arch), Path(Path) {}
struct ArchAndFile {
std::string Arch;
// Optional because TempFile has no default constructor.
Optional<llvm::sys::fs::TempFile> File;

llvm::Error createTempFile();
llvm::StringRef path() const;

ArchAndFile(StringRef Arch) : Arch(Arch) {}
ArchAndFile(ArchAndFile &&A) = default;
~ArchAndFile();
};

bool generateUniversalBinary(SmallVectorImpl<ArchAndFilename> &ArchFiles,
bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
StringRef OutputFileName, const LinkOptions &,
StringRef SDKPath);

Expand Down
40 changes: 11 additions & 29 deletions llvm/tools/dsymutil/dsymutil.cpp
Expand Up @@ -313,13 +313,6 @@ static std::string getOutputFileName(llvm::StringRef InputFile) {
return BundleDir.str();
}

static Expected<sys::fs::TempFile> createTempFile() {
llvm::SmallString<128> TmpModel;
llvm::sys::path::system_temp_directory(true, TmpModel);
llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf");
return sys::fs::TempFile::create(TmpModel);
}

/// Parses the command line options into the LinkOptions struct and performs
/// some sanity checking. Returns an error in case the latter fails.
static Expected<LinkOptions> getOptions() {
Expand Down Expand Up @@ -400,18 +393,6 @@ static Expected<std::vector<std::string>> getInputs(bool DsymAsInput) {
return Inputs;
}

namespace {
struct TempFileVector {
std::vector<sys::fs::TempFile> Files;
~TempFileVector() {
for (sys::fs::TempFile &Tmp : Files) {
if (Error E = Tmp.discard())
errs() << toString(std::move(E));
}
}
};
} // namespace

int main(int argc, char **argv) {
InitLLVM X(argc, argv);

Expand Down Expand Up @@ -523,8 +504,7 @@ int main(int argc, char **argv) {
!DumpDebugMap && (OutputFileOpt != "-") &&
(DebugMapPtrsOrErr->size() != 1 || OptionsOrErr->Update);

llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
TempFileVector TempFileStore;
llvm::SmallVector<MachOUtils::ArchAndFile, 4> TempFiles;
std::atomic_char AllOK(1);
for (auto &Map : *DebugMapPtrsOrErr) {
if (Verbose || DumpDebugMap)
Expand All @@ -543,16 +523,18 @@ int main(int argc, char **argv) {
std::shared_ptr<raw_fd_ostream> OS;
std::string OutputFile = getOutputFileName(InputFile);
if (NeedsTempFiles) {
Expected<sys::fs::TempFile> T = createTempFile();
if (!T) {
errs() << toString(T.takeError());
TempFiles.emplace_back(Map->getTriple().getArchName().str());

auto E = TempFiles.back().createTempFile();
if (E) {
errs() << toString(std::move(E));
return 1;
}
OS = std::make_shared<raw_fd_ostream>(T->FD, /*shouldClose*/ false);
OutputFile = T->TmpName;
TempFileStore.Files.push_back(std::move(*T));
TempFiles.emplace_back(Map->getTriple().getArchName().str(),
OutputFile);

auto &TempFile = *(TempFiles.back().File);
OS = std::make_shared<raw_fd_ostream>(TempFile.FD,
/*shouldClose*/ false);
OutputFile = TempFile.TmpName;
} else {
std::error_code EC;
OS = std::make_shared<raw_fd_ostream>(NoOutput ? "-" : OutputFile, EC,
Expand Down

0 comments on commit ae1727e

Please sign in to comment.