forked from OSchip/llvm-project
Remove temoprary files.
Previously, we created temporary files using llvm::sys::fs::createTemporaryFile and removed them using llvm::FileRemover. This is error-prone as it is easy to forget creating FileRemover instances after creating temporary files. There is actually a temporary file leak bug. This patch introduces a new class, TemporaryFile, to manage temporary files in the RAII style. Differential Revision: https://reviews.llvm.org/D24176 llvm-svn: 280510
This commit is contained in:
parent
31b88cb030
commit
fa12b8bd1a
|
@ -279,18 +279,54 @@ static void quoteAndPrint(raw_ostream &Out, StringRef S) {
|
|||
}
|
||||
}
|
||||
|
||||
// An RAII temporary file class that automatically removes a temporary file.
|
||||
namespace {
|
||||
class TemporaryFile {
|
||||
public:
|
||||
TemporaryFile(StringRef Prefix, StringRef Extn) {
|
||||
SmallString<128> S;
|
||||
if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
|
||||
fatal(EC, "cannot create a temporary file");
|
||||
Path = S.str();
|
||||
}
|
||||
|
||||
TemporaryFile(TemporaryFile &&Obj) {
|
||||
std::swap(Path, Obj.Path);
|
||||
}
|
||||
|
||||
~TemporaryFile() {
|
||||
if (Path.empty())
|
||||
return;
|
||||
if (sys::fs::remove(Path))
|
||||
fatal("failed to remove " + Path);
|
||||
}
|
||||
|
||||
// Returns a memory buffer of this temporary file.
|
||||
// Note that this function does not leave the file open,
|
||||
// so it is safe to remove the file immediately after this function
|
||||
// is called (you cannot remove an opened file on Windows.)
|
||||
std::unique_ptr<MemoryBuffer> getMemoryBuffer() {
|
||||
// IsVolatileSize=true forces MemoryBuffer to not use mmap().
|
||||
return check(MemoryBuffer::getFile(Path, /*FileSize=*/-1,
|
||||
/*RequiresNullTerminator=*/false,
|
||||
/*IsVolatileSize=*/true),
|
||||
"could not open " + Path);
|
||||
}
|
||||
|
||||
std::string Path;
|
||||
};
|
||||
}
|
||||
|
||||
// Create the default manifest file as a temporary file.
|
||||
static std::string createDefaultXml() {
|
||||
TemporaryFile createDefaultXml() {
|
||||
// Create a temporary file.
|
||||
SmallString<128> Path;
|
||||
if (auto EC = sys::fs::createTemporaryFile("tmp", "manifest", Path))
|
||||
fatal(EC, "cannot create a temporary file");
|
||||
TemporaryFile File("defaultxml", "manifest");
|
||||
|
||||
// Open the temporary file for writing.
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream OS(Path, EC, sys::fs::F_Text);
|
||||
llvm::raw_fd_ostream OS(File.Path, EC, sys::fs::F_Text);
|
||||
if (EC)
|
||||
fatal(EC, "failed to open " + Path);
|
||||
fatal(EC, "failed to open " + File.Path);
|
||||
|
||||
// Emit the XML. Note that we do *not* verify that the XML attributes are
|
||||
// syntactically correct. This is intentional for link.exe compatibility.
|
||||
|
@ -316,56 +352,48 @@ static std::string createDefaultXml() {
|
|||
}
|
||||
OS << "</assembly>\n";
|
||||
OS.close();
|
||||
return StringRef(Path);
|
||||
return File;
|
||||
}
|
||||
|
||||
static std::string readFile(StringRef Path) {
|
||||
std::unique_ptr<MemoryBuffer> MB =
|
||||
check(MemoryBuffer::getFile(Path), "could not open " + Path);
|
||||
std::unique_ptr<MemoryBuffer> Buf(std::move(MB));
|
||||
return Buf->getBuffer();
|
||||
return MB->getBuffer();
|
||||
}
|
||||
|
||||
static std::string createManifestXml() {
|
||||
// Create the default manifest file.
|
||||
std::string Path1 = createDefaultXml();
|
||||
TemporaryFile File1 = createDefaultXml();
|
||||
if (Config->ManifestInput.empty())
|
||||
return readFile(Path1);
|
||||
return readFile(File1.Path);
|
||||
|
||||
// If manifest files are supplied by the user using /MANIFESTINPUT
|
||||
// option, we need to merge them with the default manifest.
|
||||
SmallString<128> Path2;
|
||||
if (auto EC = sys::fs::createTemporaryFile("tmp", "manifest", Path2))
|
||||
fatal(EC, "cannot create a temporary file");
|
||||
FileRemover Remover1(Path1);
|
||||
FileRemover Remover2(Path2);
|
||||
TemporaryFile File2("user", "manifest");
|
||||
|
||||
Executor E("mt.exe");
|
||||
E.add("/manifest");
|
||||
E.add(Path1);
|
||||
E.add(File1.Path);
|
||||
for (StringRef Filename : Config->ManifestInput) {
|
||||
E.add("/manifest");
|
||||
E.add(Filename);
|
||||
}
|
||||
E.add("/nologo");
|
||||
E.add("/out:" + StringRef(Path2));
|
||||
E.add("/out:" + StringRef(File2.Path));
|
||||
E.run();
|
||||
return readFile(Path2);
|
||||
return readFile(File2.Path);
|
||||
}
|
||||
|
||||
// Create a resource file containing a manifest XML.
|
||||
std::unique_ptr<MemoryBuffer> createManifestRes() {
|
||||
// Create a temporary file for the resource script file.
|
||||
SmallString<128> RCPath;
|
||||
if (auto EC = sys::fs::createTemporaryFile("tmp", "rc", RCPath))
|
||||
fatal(EC, "cannot create a temporary file");
|
||||
FileRemover RCRemover(RCPath);
|
||||
TemporaryFile RCFile("manifest", "rc");
|
||||
|
||||
// Open the temporary file for writing.
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream Out(RCPath, EC, sys::fs::F_Text);
|
||||
llvm::raw_fd_ostream Out(RCFile.Path, EC, sys::fs::F_Text);
|
||||
if (EC)
|
||||
fatal(EC, "failed to open " + RCPath);
|
||||
fatal(EC, "failed to open " + RCFile.Path);
|
||||
|
||||
// Write resource script to the RC file.
|
||||
Out << "#define LANG_ENGLISH 9\n"
|
||||
|
@ -379,17 +407,15 @@ std::unique_ptr<MemoryBuffer> createManifestRes() {
|
|||
Out.close();
|
||||
|
||||
// Create output resource file.
|
||||
SmallString<128> ResPath;
|
||||
if (auto EC = sys::fs::createTemporaryFile("tmp", "res", ResPath))
|
||||
fatal(EC, "cannot create a temporary file");
|
||||
TemporaryFile ResFile("output-resource", "res");
|
||||
|
||||
Executor E("rc.exe");
|
||||
E.add("/fo");
|
||||
E.add(ResPath.str());
|
||||
E.add(ResFile.Path);
|
||||
E.add("/nologo");
|
||||
E.add(RCPath.str());
|
||||
E.add(RCFile.Path);
|
||||
E.run();
|
||||
return check(MemoryBuffer::getFile(ResPath), "could not open " + ResPath);
|
||||
return ResFile.getMemoryBuffer();
|
||||
}
|
||||
|
||||
void createSideBySideManifest() {
|
||||
|
@ -555,20 +581,18 @@ void checkFailIfMismatch(StringRef Arg) {
|
|||
std::unique_ptr<MemoryBuffer>
|
||||
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
|
||||
// Create an output file path.
|
||||
SmallString<128> Path;
|
||||
if (auto EC = llvm::sys::fs::createTemporaryFile("resource", "obj", Path))
|
||||
fatal(EC, "could not create temporary file");
|
||||
TemporaryFile File("resource-file", "obj");
|
||||
|
||||
// Execute cvtres.exe.
|
||||
Executor E("cvtres.exe");
|
||||
E.add("/machine:" + machineToStr(Config->Machine));
|
||||
E.add("/readonly");
|
||||
E.add("/nologo");
|
||||
E.add("/out:" + Path);
|
||||
E.add("/out:" + Twine(File.Path));
|
||||
for (MemoryBufferRef MB : MBs)
|
||||
E.add(MB.getBufferIdentifier());
|
||||
E.run();
|
||||
return check(MemoryBuffer::getFile(Path), "could not open " + Path);
|
||||
return File.getMemoryBuffer();
|
||||
}
|
||||
|
||||
// Create OptTable
|
||||
|
|
Loading…
Reference in New Issue