diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-09-17 17:38:48 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-09-17 17:38:48 +0000 |
commit | dc24572a44575e07a5d8bb6de52641a69f1bab27 (patch) | |
tree | 621e35daa5260e40b3c8c928e31090959ca96040 /lib/Frontend/CompilerInstance.cpp | |
parent | a83c6be907b2a6b9ccc979c79b3a24a7e48b2c54 (diff) |
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!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114187 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend/CompilerInstance.cpp')
-rw-r--r-- | lib/Frontend/CompilerInstance.cpp | 66 |
1 files changed, 52 insertions, 14 deletions
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index ce0b07243b..212a1cf9f2 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -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 @@ void CompilerInstance::createSema(bool CompleteTranslationUnit, // 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 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 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 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, // 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 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 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 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, } 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(); } |