[lld] r280510 - Remove temoprary files.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 2 10:34:18 PDT 2016


Author: ruiu
Date: Fri Sep  2 12:34:17 2016
New Revision: 280510

URL: http://llvm.org/viewvc/llvm-project?rev=280510&view=rev
Log:
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

Modified:
    lld/trunk/COFF/DriverUtils.cpp

Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=280510&r1=280509&r2=280510&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Fri Sep  2 12:34:17 2016
@@ -279,18 +279,54 @@ static void quoteAndPrint(raw_ostream &O
   }
 }
 
+// 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> createMani
   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




More information about the llvm-commits mailing list