[llvm] [llvm][Support] Stop using PWD in current_path (PR #94544)
IƱaki Amatria Barral via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 5 16:05:25 PDT 2024
https://github.com/inaki-amatria created https://github.com/llvm/llvm-project/pull/94544
In a filesystem structured as follows:
```
r/
|- a/
`- b -> a/
```
If current directory is set to `r/b` (a symbolic link to `r/a`) and then changed to `r/a` using `set_current_path()`, subsequent calls to `current_path()` incorrectly return `r/b`. This is because `current_path()` reads the `PWD` environment variable, which still points to the symbolic link `r/b` instead of the actual directory `r/a`.
This issue leads to inaccurate path reporting, causing confusion and potential errors in applications that rely on `current_path()`.
This issue is reproducible with bind mounts too.
>From ed167da84dd9ad59a5b2c61bd237d041efa9d4fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?I=C3=B1aki=20Amatria=20Barral?= <inaki.amatria at appentra.com>
Date: Thu, 6 Jun 2024 00:52:30 +0200
Subject: [PATCH] [llvm][Support] Stop using PWD in current_path
In a filesystem structured as follows:
```
r/
|- a/
`- b -> a/
```
If current directory is set to `r/b` (a symbolic link to `r/a`) and then
changed to `r/a` using `set_current_path()`, subsequent calls to
`current_path()` incorrectly return `r/b`. This is because
`current_path()` reads the `PWD` environment variable, which still
points to the symbolic link `r/b` instead of the actual directory `r/a`.
This issue leads to inaccurate path reporting, causing confusion and
potential errors in applications that rely on `current_path()`.
This issue is reproducible with bind mounts too.
---
.../llvm/Testing/Support/SupportHelpers.h | 24 ++++++++++++++
llvm/lib/Support/Unix/Path.inc | 10 ------
llvm/test/MC/ELF/comp-dir.s | 8 -----
llvm/unittests/Support/Path.cpp | 32 +++----------------
.../Support/VirtualFileSystemTest.cpp | 17 ++++++++++
5 files changed, 46 insertions(+), 45 deletions(-)
diff --git a/llvm/include/llvm/Testing/Support/SupportHelpers.h b/llvm/include/llvm/Testing/Support/SupportHelpers.h
index 95c2765027ba0..49e44e42a1dc1 100644
--- a/llvm/include/llvm/Testing/Support/SupportHelpers.h
+++ b/llvm/include/llvm/Testing/Support/SupportHelpers.h
@@ -248,6 +248,30 @@ class TempFile {
StringRef path() const { return Path; }
};
+#ifndef _WIN32
+// RAII helper to set and restore an environment variable.
+class WithEnv {
+ const char *Var;
+ std::optional<std::string> OriginalValue;
+
+public:
+ WithEnv(const char *Var, const char *Value) : Var(Var) {
+ if (const char *V = ::getenv(Var))
+ OriginalValue.emplace(V);
+ if (Value)
+ ::setenv(Var, Value, 1);
+ else
+ ::unsetenv(Var);
+ }
+ ~WithEnv() {
+ if (OriginalValue)
+ ::setenv(Var, OriginalValue->c_str(), 1);
+ else
+ ::unsetenv(Var);
+ }
+};
+#endif
+
} // namespace unittest
} // namespace llvm
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 6e679f74869f0..01af15ebfa52b 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -369,16 +369,6 @@ ErrorOr<space_info> disk_space(const Twine &Path) {
std::error_code current_path(SmallVectorImpl<char> &result) {
result.clear();
- const char *pwd = ::getenv("PWD");
- llvm::sys::fs::file_status PWDStatus, DotStatus;
- if (pwd && llvm::sys::path::is_absolute(pwd) &&
- !llvm::sys::fs::status(pwd, PWDStatus) &&
- !llvm::sys::fs::status(".", DotStatus) &&
- PWDStatus.getUniqueID() == DotStatus.getUniqueID()) {
- result.append(pwd, pwd + strlen(pwd));
- return std::error_code();
- }
-
result.resize_for_overwrite(PATH_MAX);
while (true) {
diff --git a/llvm/test/MC/ELF/comp-dir.s b/llvm/test/MC/ELF/comp-dir.s
index 59edce1ca5452..729f41e872781 100644
--- a/llvm/test/MC/ELF/comp-dir.s
+++ b/llvm/test/MC/ELF/comp-dir.s
@@ -6,13 +6,5 @@
// CHECK: DW_AT_comp_dir [DW_FORM_string] ("{{([A-Za-z]:.*)?}}/test/comp/dir")
-// RUN: mkdir -p %t.foo
-// RUN: ln -sf %t.foo %t.bar
-// RUN: cd %t.foo
-// RUN: env PWD=%t.bar llvm-mc -triple=x86_64-linux-unknown -g %s -filetype=obj -o %t.o
-// RUN: llvm-dwarfdump -v -debug-info %t.o | FileCheck --check-prefix=PWD %s
-// PWD: DW_AT_comp_dir [DW_FORM_string] ("{{.*}}.bar")
-
-
f:
nop
diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp
index bdae7a8ee4b55..02c34ea632aa4 100644
--- a/llvm/unittests/Support/Path.cpp
+++ b/llvm/unittests/Support/Path.cpp
@@ -451,28 +451,6 @@ std::string getEnvWin(const wchar_t *Var) {
}
return expected;
}
-#else
-// RAII helper to set and restore an environment variable.
-class WithEnv {
- const char *Var;
- std::optional<std::string> OriginalValue;
-
-public:
- WithEnv(const char *Var, const char *Value) : Var(Var) {
- if (const char *V = ::getenv(Var))
- OriginalValue.emplace(V);
- if (Value)
- ::setenv(Var, Value, 1);
- else
- ::unsetenv(Var);
- }
- ~WithEnv() {
- if (OriginalValue)
- ::setenv(Var, OriginalValue->c_str(), 1);
- else
- ::unsetenv(Var);
- }
-};
#endif
TEST(Support, HomeDirectory) {
@@ -496,7 +474,7 @@ TEST(Support, HomeDirectory) {
// Apple has their own solution for this.
#if defined(LLVM_ON_UNIX) && !defined(__APPLE__)
TEST(Support, HomeDirectoryWithNoEnv) {
- WithEnv Env("HOME", nullptr);
+ unittest::WithEnv Env("HOME", nullptr);
// Don't run the test if we have nothing to compare against.
struct passwd *pw = getpwuid(getuid());
@@ -510,7 +488,7 @@ TEST(Support, HomeDirectoryWithNoEnv) {
}
TEST(Support, ConfigDirectoryWithEnv) {
- WithEnv Env("XDG_CONFIG_HOME", "/xdg/config");
+ unittest::WithEnv Env("XDG_CONFIG_HOME", "/xdg/config");
SmallString<128> ConfigDir;
EXPECT_TRUE(path::user_config_directory(ConfigDir));
@@ -518,7 +496,7 @@ TEST(Support, ConfigDirectoryWithEnv) {
}
TEST(Support, ConfigDirectoryNoEnv) {
- WithEnv Env("XDG_CONFIG_HOME", nullptr);
+ unittest::WithEnv Env("XDG_CONFIG_HOME", nullptr);
SmallString<128> Fallback;
ASSERT_TRUE(path::home_directory(Fallback));
@@ -530,7 +508,7 @@ TEST(Support, ConfigDirectoryNoEnv) {
}
TEST(Support, CacheDirectoryWithEnv) {
- WithEnv Env("XDG_CACHE_HOME", "/xdg/cache");
+ unittest::WithEnv Env("XDG_CACHE_HOME", "/xdg/cache");
SmallString<128> CacheDir;
EXPECT_TRUE(path::cache_directory(CacheDir));
@@ -538,7 +516,7 @@ TEST(Support, CacheDirectoryWithEnv) {
}
TEST(Support, CacheDirectoryNoEnv) {
- WithEnv Env("XDG_CACHE_HOME", nullptr);
+ unittest::WithEnv Env("XDG_CACHE_HOME", nullptr);
SmallString<128> Fallback;
ASSERT_TRUE(path::home_directory(Fallback));
diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp
index e9fd9671ea6ab..5d9386ba347dd 100644
--- a/llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -479,6 +479,23 @@ TEST(VirtualFileSystemTest, BasicRealFSIteration) {
}
#ifdef LLVM_ON_UNIX
+TEST(VirtualFileSystemTest, ChangeCWDToDirFromASymbolicLinkToDir) {
+ // r/
+ // |- a/
+ // `- b -> a/
+ TempDir Root("r", /*Unique=*/true);
+ TempDir ADir(Root.path("a"));
+ TempLink B(ADir.path(), Root.path("b"));
+
+ // PWD points to `/r/b`
+ unittest::WithEnv Env("PWD", B.path().str().c_str());
+
+ // Navigate to `/r/a` from `/r/b`
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
+ ASSERT_FALSE(FS->setCurrentWorkingDirectory(ADir.path()));
+ EXPECT_EQ(ADir.path(), *FS->getCurrentWorkingDirectory());
+}
+
TEST(VirtualFileSystemTest, MultipleWorkingDirs) {
// Our root contains a/aa, b/bb, c, where c is a link to a/.
// Run tests both in root/b/ and root/c/ (to test "normal" and symlink dirs).
More information about the llvm-commits
mailing list