[cfe-commits] r114187 - in /cfe/trunk: include/clang/Basic/DiagnosticFrontendKinds.td include/clang/Frontend/CompilerInstance.h lib/Frontend/CompilerInstance.cpp test/CodeGen/2008-07-17-no-emit-on-error.c

Argyrios Kyrtzidis akyrtzi at gmail.com
Fri Sep 17 10:38:48 PDT 2010


Author: akirtzidis
Date: Fri Sep 17 12:38:48 2010
New Revision: 114187

URL: http://llvm.org/viewvc/llvm-project?rev=114187&view=rev
Log:
Use a temporary file for output which gets renamed after all the writing is finished.

This mainly prevents failures and/or crashes when multiple processes try to read/write the same PCH file. (rdar://8392711&8294781); suggestion & review by Daniel!

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/include/clang/Frontend/CompilerInstance.h
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/test/CodeGen/2008-07-17-no-emit-on-error.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=114187&r1=114186&r2=114187&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Fri Sep 17 12:38:48 2010
@@ -69,6 +69,8 @@
     DefaultFatal;
 def err_fe_unable_to_open_output : Error<
     "unable to open output file '%0': '%1'">;
+def err_fe_unable_to_rename_temp : Error<
+    "unable to rename temporary '%0' to output file '%1': '%2'">;
 def err_fe_unable_to_open_logfile : Error<
     "unable to open logfile file '%0': '%1'">;
 def err_fe_pth_file_has_no_source_header : Error<

Modified: cfe/trunk/include/clang/Frontend/CompilerInstance.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CompilerInstance.h?rev=114187&r1=114186&r2=114187&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/CompilerInstance.h (original)
+++ cfe/trunk/include/clang/Frontend/CompilerInstance.h Fri Sep 17 12:38:48 2010
@@ -95,8 +95,23 @@
   /// The frontend timer
   llvm::OwningPtr<llvm::Timer> FrontendTimer;
 
+  /// \brief Holds information about the output file.
+  ///
+  /// If TempFilename is not empty we must rename it to Filename at the end.
+  /// TempFilename may be empty and Filename non empty if creating the temporary
+  /// failed.
+  struct OutputFile {
+    std::string Filename;
+    std::string TempFilename;
+    llvm::raw_ostream *OS;
+
+    OutputFile(const std::string &filename, const std::string &tempFilename,
+               llvm::raw_ostream *os)
+      : Filename(filename), TempFilename(tempFilename), OS(os) { }
+  };
+
   /// The list of active output files.
-  std::list< std::pair<std::string, llvm::raw_ostream*> > OutputFiles;
+  std::list<OutputFile> OutputFiles;
 
   void operator=(const CompilerInstance &);  // DO NOT IMPLEMENT
   CompilerInstance(const CompilerInstance&); // DO NOT IMPLEMENT
@@ -442,9 +457,8 @@
 
   /// addOutputFile - Add an output file onto the list of tracked output files.
   ///
-  /// \param Path - The path to the output file, or empty.
-  /// \param OS - The output stream, which should be non-null.
-  void addOutputFile(llvm::StringRef Path, llvm::raw_ostream *OS);
+  /// \param OutFile - The output file info.
+  void addOutputFile(const OutputFile &OutFile);
 
   /// clearOutputFiles - Clear the output file list, destroying the contained
   /// output streams.
@@ -565,7 +579,8 @@
   ///
   /// If \arg OutputPath is empty, then createOutputFile will derive an output
   /// path location as \arg BaseInput, with any suffix removed, and \arg
-  /// Extension appended.
+  /// Extension appended. If OutputPath is not stdout createOutputFile will
+  /// create a new temporary file that must be renamed to OutputPath in the end.
   ///
   /// \param OutputPath - If given, the path to the output file.
   /// \param Error [out] - On failure, the error message.
@@ -575,11 +590,14 @@
   /// \param Binary - The mode to open the file in.
   /// \param ResultPathName [out] - If given, the result path name will be
   /// stored here on success.
+  /// \param TempPathName [out] - If given, the temporary file path name
+  /// will be stored here on success.
   static llvm::raw_fd_ostream *
   createOutputFile(llvm::StringRef OutputPath, std::string &Error,
                    bool Binary = true, llvm::StringRef BaseInput = "",
                    llvm::StringRef Extension = "",
-                   std::string *ResultPathName = 0);
+                   std::string *ResultPathName = 0,
+                   std::string *TempPathName = 0);
 
   /// }
   /// @name Initialization Utility Methods

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=114187&r1=114186&r2=114187&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Fri Sep 17 12:38:48 2010
@@ -35,6 +35,7 @@
 #include "llvm/System/Host.h"
 #include "llvm/System/Path.h"
 #include "llvm/System/Program.h"
+#include "llvm/System/Signals.h"
 using namespace clang;
 
 CompilerInstance::CompilerInstance()
@@ -370,18 +371,30 @@
 
 // Output Files
 
-void CompilerInstance::addOutputFile(llvm::StringRef Path,
-                                     llvm::raw_ostream *OS) {
-  assert(OS && "Attempt to add empty stream to output list!");
-  OutputFiles.push_back(std::make_pair(Path, OS));
+void CompilerInstance::addOutputFile(const OutputFile &OutFile) {
+  assert(OutFile.OS && "Attempt to add empty stream to output list!");
+  OutputFiles.push_back(OutFile);
 }
 
 void CompilerInstance::clearOutputFiles(bool EraseFiles) {
-  for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator
+  for (std::list<OutputFile>::iterator
          it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
-    delete it->second;
-    if (EraseFiles && !it->first.empty())
-      llvm::sys::Path(it->first).eraseFromDisk();
+    delete it->OS;
+    if (!it->TempFilename.empty()) {
+      llvm::sys::Path TempPath(it->TempFilename);
+      if (EraseFiles)
+        TempPath.eraseFromDisk();
+      else {
+        std::string Error;
+        if (TempPath.renamePathOnDisk(llvm::sys::Path(it->Filename), &Error)) {
+          getDiagnostics().Report(diag::err_fe_unable_to_rename_temp)
+            << it->TempFilename << it->Filename << Error;
+          TempPath.eraseFromDisk();
+        }
+      }
+    } else if (!it->Filename.empty() && EraseFiles)
+      llvm::sys::Path(it->Filename).eraseFromDisk();
+      
   }
   OutputFiles.clear();
 }
@@ -399,10 +412,11 @@
                                    bool Binary,
                                    llvm::StringRef InFile,
                                    llvm::StringRef Extension) {
-  std::string Error, OutputPathName;
+  std::string Error, OutputPathName, TempPathName;
   llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
                                               InFile, Extension,
-                                              &OutputPathName);
+                                              &OutputPathName,
+                                              &TempPathName);
   if (!OS) {
     getDiagnostics().Report(diag::err_fe_unable_to_open_output)
       << OutputPath << Error;
@@ -411,7 +425,8 @@
 
   // Add the output file -- but don't try to remove "-", since this means we are
   // using stdin.
-  addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS);
+  addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "",
+                TempPathName, OS));
 
   return OS;
 }
@@ -422,8 +437,9 @@
                                    bool Binary,
                                    llvm::StringRef InFile,
                                    llvm::StringRef Extension,
-                                   std::string *ResultPathName) {
-  std::string OutFile;
+                                   std::string *ResultPathName,
+                                   std::string *TempPathName) {
+  std::string OutFile, TempFile;
   if (!OutputPath.empty()) {
     OutFile = OutputPath;
   } else if (InFile == "-") {
@@ -436,15 +452,37 @@
   } else {
     OutFile = "-";
   }
+  
+  if (OutFile != "-") {
+    llvm::sys::Path OutPath(OutFile);
+    // Only create the temporary if we can actually write to OutPath, otherwise
+    // we want to fail early.
+    if (!OutPath.exists() ||
+        (OutPath.isRegularFile() && OutPath.canWrite())) {
+      // Create a temporary file.
+      llvm::sys::Path TempPath(OutFile);
+      if (!TempPath.createTemporaryFileOnDisk())
+        TempFile = TempPath.str();
+    }
+  }
+
+  std::string OSFile = OutFile;
+  if (!TempFile.empty())
+    OSFile = TempFile;
 
   llvm::OwningPtr<llvm::raw_fd_ostream> OS(
-    new llvm::raw_fd_ostream(OutFile.c_str(), Error,
+    new llvm::raw_fd_ostream(OSFile.c_str(), Error,
                              (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
   if (!Error.empty())
     return 0;
 
+  // Make sure the out stream file gets removed if we crash.
+  llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile));
+
   if (ResultPathName)
     *ResultPathName = OutFile;
+  if (TempPathName)
+    *TempPathName = TempFile;
 
   return OS.take();
 }

Modified: cfe/trunk/test/CodeGen/2008-07-17-no-emit-on-error.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/2008-07-17-no-emit-on-error.c?rev=114187&r1=114186&r2=114187&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/2008-07-17-no-emit-on-error.c (original)
+++ cfe/trunk/test/CodeGen/2008-07-17-no-emit-on-error.c Fri Sep 17 12:38:48 2010
@@ -1,6 +1,7 @@
 // RUN: rm -f %t1.bc
 // RUN: %clang_cc1 -DPASS %s -emit-llvm-bc -o %t1.bc
 // RUN: test -f %t1.bc
+// RUN: rm -f %t1.bc
 // RUN: not %clang_cc1 %s -emit-llvm-bc -o %t1.bc
 // RUN: not test -f %t1.bc
 





More information about the cfe-commits mailing list