Skip to content

Commit 5437a4c

Browse files
committed
[llvm][vfs] Avoid silent fallback to process-wide working directory
In createPhysicalFileSystem, preserve the per-instance working directory, even after the first call to getcwd fails. rdar://108213753 Differential Revision: https://reviews.llvm.org/D149173
1 parent 64888d4 commit 5437a4c

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

llvm/lib/Support/VirtualFileSystem.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,12 @@ class RealFileSystem : public FileSystem {
257257
explicit RealFileSystem(bool LinkCWDToProcess) {
258258
if (!LinkCWDToProcess) {
259259
SmallString<128> PWD, RealPWD;
260-
if (llvm::sys::fs::current_path(PWD))
261-
return; // Awful, but nothing to do here.
262-
if (llvm::sys::fs::real_path(PWD, RealPWD))
263-
WD = {PWD, PWD};
260+
if (std::error_code EC = llvm::sys::fs::current_path(PWD))
261+
WD = EC;
262+
else if (llvm::sys::fs::real_path(PWD, RealPWD))
263+
WD = WorkingDirectory{PWD, PWD};
264264
else
265-
WD = {PWD, RealPWD};
265+
WD = WorkingDirectory{PWD, RealPWD};
266266
}
267267
}
268268

@@ -284,10 +284,10 @@ class RealFileSystem : public FileSystem {
284284
// If this FS has its own working dir, use it to make Path absolute.
285285
// The returned twine is safe to use as long as both Storage and Path live.
286286
Twine adjustPath(const Twine &Path, SmallVectorImpl<char> &Storage) const {
287-
if (!WD)
287+
if (!WD || !*WD)
288288
return Path;
289289
Path.toVector(Storage);
290-
sys::fs::make_absolute(WD->Resolved, Storage);
290+
sys::fs::make_absolute(WD->get().Resolved, Storage);
291291
return Storage;
292292
}
293293

@@ -297,7 +297,7 @@ class RealFileSystem : public FileSystem {
297297
// The current working directory, with links resolved. (readlink .).
298298
SmallString<128> Resolved;
299299
};
300-
std::optional<WorkingDirectory> WD;
300+
std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
301301
};
302302

303303
} // namespace
@@ -323,8 +323,10 @@ RealFileSystem::openFileForRead(const Twine &Name) {
323323
}
324324

325325
llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
326+
if (WD && *WD)
327+
return std::string(WD->get().Specified.str());
326328
if (WD)
327-
return std::string(WD->Specified.str());
329+
return WD->getError();
328330

329331
SmallString<128> Dir;
330332
if (std::error_code EC = llvm::sys::fs::current_path(Dir))
@@ -345,7 +347,7 @@ std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
345347
return std::make_error_code(std::errc::not_a_directory);
346348
if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved))
347349
return Err;
348-
WD = {Absolute, Resolved};
350+
WD = WorkingDirectory{Absolute, Resolved};
349351
return std::error_code();
350352
}
351353

llvm/unittests/Support/VirtualFileSystemTest.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/Support/VirtualFileSystem.h"
10+
#include "llvm/ADT/ScopeExit.h"
1011
#include "llvm/Config/llvm-config.h"
1112
#include "llvm/Support/Errc.h"
1213
#include "llvm/Support/MemoryBuffer.h"
@@ -526,6 +527,31 @@ TEST(VirtualFileSystemTest, MultipleWorkingDirs) {
526527
ASSERT_EQ(CIt, vfs::directory_iterator());
527528
}
528529

530+
TEST(VirtualFileSystemTest, PhysicalFileSystemWorkingDirFailure) {
531+
TempDir D2("d2", /*Unique*/ true);
532+
SmallString<128> WD, PrevWD;
533+
ASSERT_EQ(sys::fs::current_path(PrevWD), std::error_code());
534+
ASSERT_EQ(sys::fs::createUniqueDirectory("d1", WD), std::error_code());
535+
ASSERT_EQ(sys::fs::set_current_path(WD), std::error_code());
536+
auto Restore =
537+
llvm::make_scope_exit([&] { sys::fs::set_current_path(PrevWD); });
538+
539+
// Delete the working directory to create an error.
540+
ASSERT_EQ(sys::fs::remove_directories(WD), std::error_code());
541+
542+
// Verify that we still get two separate working directories.
543+
auto FS1 = vfs::createPhysicalFileSystem();
544+
auto FS2 = vfs::createPhysicalFileSystem();
545+
ASSERT_EQ(FS1->getCurrentWorkingDirectory().getError(),
546+
errc::no_such_file_or_directory);
547+
ASSERT_EQ(FS1->setCurrentWorkingDirectory(D2.path()), std::error_code());
548+
ASSERT_EQ(FS1->getCurrentWorkingDirectory().get(), D2.path());
549+
EXPECT_EQ(FS2->getCurrentWorkingDirectory().getError(),
550+
errc::no_such_file_or_directory);
551+
SmallString<128> WD2;
552+
EXPECT_EQ(sys::fs::current_path(WD2), errc::no_such_file_or_directory);
553+
}
554+
529555
TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
530556
TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
531557
IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();

0 commit comments

Comments
 (0)