[llvm] r338745 - [Support] fix TempFile infinite loop and permission denied errors
Bob Haarman via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 2 10:41:38 PDT 2018
Author: inglorion
Date: Thu Aug 2 10:41:38 2018
New Revision: 338745
URL: http://llvm.org/viewvc/llvm-project?rev=338745&view=rev
Log:
[Support] fix TempFile infinite loop and permission denied errors
Summary:
On Windows, TempFile::create() was prone to failing with permission
denied errors when a process created many tempfiles without providing
a model large enough to accommodate them. There was also a problem
with createUniqueEntity getting into an infinite loop when all names
permitted by the model are in use. This change fixes both of these
problems and adds a unit test for them.
Reviewers: pcc, rnk, zturner
Reviewed By: zturner
Subscribers: inglorion, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D50126
Modified:
llvm/trunk/lib/Support/Path.cpp
llvm/trunk/unittests/Support/Path.cpp
Modified: llvm/trunk/lib/Support/Path.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Path.cpp?rev=338745&r1=338744&r2=338745&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Path.cpp (original)
+++ llvm/trunk/lib/Support/Path.cpp Thu Aug 2 10:41:38 2018
@@ -190,48 +190,55 @@ createUniqueEntity(const Twine &Model, i
ResultPath.push_back(0);
ResultPath.pop_back();
-retry_random_path:
- // Replace '%' with random chars.
- for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) {
- if (ModelStorage[i] == '%')
- ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15];
- }
-
- // Try to open + create the file.
- switch (Type) {
- case FS_File: {
- if (std::error_code EC =
- sys::fs::openFileForReadWrite(Twine(ResultPath.begin()), ResultFD,
- sys::fs::CD_CreateNew, Flags, Mode)) {
- if (EC == errc::file_exists)
- goto retry_random_path;
- return EC;
+ // Limit the number of attempts we make, so that we don't infinite loop when
+ // we run out of filenames that fit the model.
+ std::error_code EC;
+ for (int Retries = 128; Retries > 0; --Retries) {
+ // Replace '%' with random chars.
+ for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) {
+ if (ModelStorage[i] == '%')
+ ResultPath[i] =
+ "0123456789abcdef"[sys::Process::GetRandomNumber() & 15];
}
- return std::error_code();
- }
+ // Try to open + create the file.
+ switch (Type) {
+ case FS_File: {
+ EC = sys::fs::openFileForReadWrite(Twine(ResultPath.begin()), ResultFD,
+ sys::fs::CD_CreateNew, Flags, Mode);
+ if (EC) {
+ // errc::permission_denied happens on Windows when we try to open a file
+ // that has been marked for deletion.
+ if (EC == errc::file_exists || EC == errc::permission_denied)
+ continue;
+ return EC;
+ }
- case FS_Name: {
- std::error_code EC =
- sys::fs::access(ResultPath.begin(), sys::fs::AccessMode::Exist);
- if (EC == errc::no_such_file_or_directory)
return std::error_code();
- if (EC)
- return EC;
- goto retry_random_path;
- }
+ }
- case FS_Dir: {
- if (std::error_code EC =
- sys::fs::create_directory(ResultPath.begin(), false)) {
- if (EC == errc::file_exists)
- goto retry_random_path;
- return EC;
+ case FS_Name: {
+ EC = sys::fs::access(ResultPath.begin(), sys::fs::AccessMode::Exist);
+ if (EC == errc::no_such_file_or_directory)
+ return std::error_code();
+ if (EC)
+ return EC;
+ continue;
}
- return std::error_code();
- }
+
+ case FS_Dir: {
+ EC = sys::fs::create_directory(ResultPath.begin(), false);
+ if (EC) {
+ if (EC == errc::file_exists)
+ continue;
+ return EC;
+ }
+ return std::error_code();
+ }
+ }
+ llvm_unreachable("Invalid Type");
}
- llvm_unreachable("Invalid Type");
+ return EC;
}
namespace llvm {
Modified: llvm/trunk/unittests/Support/Path.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Path.cpp?rev=338745&r1=338744&r2=338745&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/Path.cpp (original)
+++ llvm/trunk/unittests/Support/Path.cpp Thu Aug 2 10:41:38 2018
@@ -681,6 +681,37 @@ TEST_F(FileSystemTest, TempFiles) {
#endif
}
+TEST_F(FileSystemTest, TempFileCollisions) {
+ SmallString<128> TestDirectory;
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("CreateUniqueFileTest", TestDirectory));
+ FileRemover Cleanup(TestDirectory);
+ SmallString<128> Model = TestDirectory;
+ path::append(Model, "%.tmp");
+ SmallString<128> Path;
+ std::vector<fs::TempFile> TempFiles;
+
+ auto TryCreateTempFile = [&]() {
+ Expected<fs::TempFile> T = fs::TempFile::create(Model);
+ if (T) {
+ TempFiles.push_back(std::move(*T));
+ return true;
+ } else {
+ logAllUnhandledErrors(T.takeError(), errs(),
+ "Failed to create temporary file: ");
+ return false;
+ }
+ };
+
+ // We should be able to create exactly 16 temporary files.
+ for (int i = 0; i < 16; ++i)
+ EXPECT_TRUE(TryCreateTempFile());
+ EXPECT_FALSE(TryCreateTempFile());
+
+ for (fs::TempFile &T : TempFiles)
+ cantFail(T.discard());
+}
+
TEST_F(FileSystemTest, CreateDir) {
ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo"));
ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo"));
More information about the llvm-commits
mailing list