aboutsummaryrefslogtreecommitdiff
path: root/lib/Frontend
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-07-21 18:44:49 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-07-21 18:44:49 +0000
commit9cca68dbfc42f7778f8db0bcfe8b3e575599ac0f (patch)
tree9216dcd89d3be88e2d46e89c4be668585d975204 /lib/Frontend
parentbc9d5a3ace7cb75e4bff3dd4a3999a3fc04f4d45 (diff)
For ASTUnit::Save, write the AST to a temporary and then rename it to the actual filename.
Should avoid race conditions. Addresses rdar://9788943. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135691 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend')
-rw-r--r--lib/Frontend/ASTUnit.cpp30
1 files changed, 26 insertions, 4 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 89bc0919e5..c50dea6aa3 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -45,6 +45,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include <cstdlib>
#include <cstdio>
@@ -2304,18 +2305,39 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
CXSaveError ASTUnit::Save(llvm::StringRef File) {
if (getDiagnostics().hasUnrecoverableErrorOccurred())
return CXSaveError_TranslationErrors;
-
+
+ // Write to a temporary file and later rename it to the actual file, to avoid
+ // possible race conditions.
+ llvm::sys::Path TempPath(File);
+ if (TempPath.makeUnique(/*reuse_current=*/false, /*ErrMsg*/0))
+ return CXSaveError_Unknown;
+ // makeUnique may or may not have created the file. Try deleting before
+ // opening so that we can use F_Excl for exclusive access.
+ TempPath.eraseFromDisk();
+
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
// unconditionally create a stat cache when we parse the file?
std::string ErrorInfo;
- llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo,
- llvm::raw_fd_ostream::F_Binary);
+ llvm::raw_fd_ostream Out(TempPath.c_str(), ErrorInfo,
+ llvm::raw_fd_ostream::F_Binary |
+ // if TempPath already exists, we should not try to
+ // overwrite it, we want to avoid race conditions.
+ llvm::raw_fd_ostream::F_Excl);
if (!ErrorInfo.empty() || Out.has_error())
return CXSaveError_Unknown;
serialize(Out);
Out.close();
- return Out.has_error()? CXSaveError_Unknown : CXSaveError_None;
+ if (Out.has_error())
+ return CXSaveError_Unknown;
+
+ if (llvm::error_code ec = llvm::sys::fs::rename(TempPath.str(), File)) {
+ bool exists;
+ llvm::sys::fs::remove(TempPath.str(), exists);
+ return CXSaveError_Unknown;
+ }
+
+ return CXSaveError_None;
}
bool ASTUnit::serialize(llvm::raw_ostream &OS) {