https://github.com/jtstogel updated 
https://github.com/llvm/llvm-project/pull/209374

>From a9b80740a5ced9d90f81ba5d63d7a92231d0a0c0 Mon Sep 17 00:00:00 2001
From: jtstogel <[email protected]>
Date: Fri, 3 Jul 2026 18:52:42 -0700
Subject: [PATCH] [libc][realpath] Support relative paths

---
 libc/src/stdlib/linux/CMakeLists.txt   |  1 +
 libc/src/stdlib/linux/realpath.cpp     | 17 ++++-
 libc/test/src/stdlib/CMakeLists.txt    |  2 +
 libc/test/src/stdlib/realpath_test.cpp | 87 +++++++++++++++++++++++++-
 4 files changed, 103 insertions(+), 4 deletions(-)

diff --git a/libc/src/stdlib/linux/CMakeLists.txt 
b/libc/src/stdlib/linux/CMakeLists.txt
index 9189c985d9a27..5c91de4135c84 100644
--- a/libc/src/stdlib/linux/CMakeLists.txt
+++ b/libc/src/stdlib/linux/CMakeLists.txt
@@ -26,6 +26,7 @@ add_entrypoint_object(
     libc.src.__support.error_or
     libc.src.__support.libc_errno
     libc.src.__support.macros.config
+    libc.src.__support.OSUtil.linux.syscall_wrappers.getcwd
     libc.src.__support.OSUtil.path
     libc.src.string.memory_utils.inline_memcpy
 )
diff --git a/libc/src/stdlib/linux/realpath.cpp 
b/libc/src/stdlib/linux/realpath.cpp
index 63e9676ad3cae..b91033f9b9f60 100644
--- a/libc/src/stdlib/linux/realpath.cpp
+++ b/libc/src/stdlib/linux/realpath.cpp
@@ -18,6 +18,7 @@
 #include "src/__support/CPP/optional.h"
 #include "src/__support/CPP/string.h"
 #include "src/__support/CPP/string_view.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getcwd.h"
 #include "src/__support/OSUtil/path.h"
 #include "src/__support/common.h"
 #include "src/__support/error_or.h"
@@ -41,7 +42,21 @@ class ResolvedPath {
 
   void set_to_root() { path_ = path::SEPARATOR; }
 
-  cpp::optional<Error> set_to_cwd() { return Error(ENOSYS); }
+  cpp::optional<Error> set_to_cwd() {
+    char buf[PATH_MAX];
+    ErrorOr<ssize_t> ret = linux_syscalls::getcwd(buf, PATH_MAX);
+    if (!ret) {
+      if (ret.error() == ERANGE)
+        return Error(ENAMETOOLONG);
+      return Error(ret.error());
+    }
+
+    if (*ret <= 0)
+      return Error(EIO);
+
+    path_ = cpp::string_view(buf, *ret - 1);
+    return cpp::nullopt;
+  }
 
   // Removes the trailing path component.
   void set_to_parent() {
diff --git a/libc/test/src/stdlib/CMakeLists.txt 
b/libc/test/src/stdlib/CMakeLists.txt
index 55f63d82bea46..761aa4f792e29 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -401,7 +401,9 @@ add_libc_test(
     libc.src.string.strdup
     libc.src.sys.random.getrandom
     libc.src.sys.stat.mkdirat
+    libc.src.unistd.chdir
     libc.src.unistd.close
+    libc.src.unistd.getcwd
     libc.src.unistd.getpid
     libc.src.unistd.unlinkat
     libc.test.UnitTest.ErrnoCheckingTest
diff --git a/libc/test/src/stdlib/realpath_test.cpp 
b/libc/test/src/stdlib/realpath_test.cpp
index d95126ccef099..5e4a8931acc04 100644
--- a/libc/test/src/stdlib/realpath_test.cpp
+++ b/libc/test/src/stdlib/realpath_test.cpp
@@ -28,7 +28,9 @@
 #include "src/string/strdup.h"
 #include "src/sys/random/getrandom.h"
 #include "src/sys/stat/mkdirat.h"
+#include "src/unistd/chdir.h"
 #include "src/unistd/close.h"
+#include "src/unistd/getcwd.h"
 #include "src/unistd/getpid.h"
 #include "src/unistd/unlinkat.h"
 #include "test/UnitTest/ErrnoCheckingTest.h"
@@ -37,6 +39,7 @@
 namespace cpp = LIBC_NAMESPACE::cpp;
 namespace path = LIBC_NAMESPACE::path;
 using LIBC_NAMESPACE::FixedVector;
+using LIBC_NAMESPACE::testing::ErrnoCheckingTest;
 using LIBC_NAMESPACE::testing::tlog;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 
@@ -170,10 +173,23 @@ cpp::string unique_id() {
   return id;
 }
 
-class LlvmLibcRealpathTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest 
{
+class LlvmLibcRealpathTest : public ErrnoCheckingTest {
 public:
+  void SetUp() override {
+    ErrnoCheckingTest::SetUp();
+
+    (void)LIBC_NAMESPACE::getcwd(start_dir, sizeof(start_dir));
+    ASSERT_ERRNO_SUCCESS();
+  }
+
+  void TearDown() override {
+    ASSERT_THAT(LIBC_NAMESPACE::chdir(start_dir), Succeeds());
+
+    ErrnoCheckingTest::TearDown();
+  }
+
   char *realpath_buffered(const char *path) {
-    return LIBC_NAMESPACE::realpath(path, buf_);
+    return LIBC_NAMESPACE::realpath(path, realpath_buf);
   }
 
   char *realpath_buffered(const cpp::string &path) {
@@ -206,7 +222,11 @@ class LlvmLibcRealpathTest : public 
LIBC_NAMESPACE::testing::ErrnoCheckingTest {
   }
 
 private:
-  char buf_[PATH_MAX];
+  // Buffer for storing realpath output.
+  char realpath_buf[PATH_MAX];
+
+  // Current working dir at test SetUp.
+  char start_dir[PATH_MAX];
 };
 
 TEST_F(LlvmLibcRealpathTest, ErrorsWithInvalidArgIfNullPath) {
@@ -352,3 +372,64 @@ TEST_F(LlvmLibcRealpathTest, 
AllocatesResultWhenBufferIsNull) {
   ASSERT_STREQ(result, "/");
   ::free(result);
 }
+
+TEST_F(LlvmLibcRealpathTest, RelativePathResolvesToCurrentWorkingDir) {
+  TestDir test_dir;
+  ASSERT_TRUE(
+      create_test_dir("RelativePathResolvesToCurrentWorkingDir", test_dir));
+
+  ASSERT_THAT(LIBC_NAMESPACE::chdir(test_dir.c_str()), Succeeds());
+  ASSERT_STREQ(realpath_buffered("."), test_dir.c_str());
+
+  ASSERT_THAT(test_dir.mkdir("a"), Succeeds());
+  ASSERT_STREQ(realpath_buffered("a"), test_dir.absolute_path("a").c_str());
+}
+
+// Creates a directory with the desired_size and then chdir's into it.
+// Returns true on success.
+[[nodiscard]] bool chdir_to_absolute_path_with_size(TestDir &test_dir,
+                                                    size_t desired_size,
+                                                    cpp::string &out) {
+  if (!create_absolute_path_with_size(test_dir, desired_size, out))
+    return false;
+
+  // Convert the directory to be relative to test_dir.
+  const char *test_dir_relative_path =
+      out.c_str() + test_dir.view().size() + PATH_SEP_SIZE;
+
+  // Change directories into the path iteratively.
+  // This allows us to chdir into paths longer than PATH_MAX, as long as each
+  // of test_dir and test_dir_relative_path are shorter than PATH_MAX.
+  if (LIBC_NAMESPACE::chdir(test_dir.c_str()))
+    return false;
+  if (LIBC_NAMESPACE::chdir(test_dir_relative_path))
+    return false;
+  return true;
+}
+
+TEST_F(LlvmLibcRealpathTest, RelativeRealpathAcceptsPathExactlyMaxSize) {
+  TestDir test_dir;
+  ASSERT_TRUE(
+      create_test_dir("RelativeRealpathAcceptsPathExactlyMaxSize", test_dir));
+
+  cpp::string path;
+  ASSERT_TRUE(chdir_to_absolute_path_with_size(test_dir, PATH_MAX - 1, path));
+
+  ASSERT_STREQ(realpath_buffered("."), path.c_str());
+}
+
+TEST_F(LlvmLibcRealpathTest, RelativeRealpathRejectsPathExceedingMaxSize) {
+  TestDir test_dir;
+  ASSERT_TRUE(
+      create_test_dir("RelativeRealpathRejectsPathExceedingMaxSize", 
test_dir));
+
+  cpp::string path;
+  if (!chdir_to_absolute_path_with_size(test_dir, PATH_MAX, path)) {
+    // Skip the test if the system didn't allow creating the path.
+    ASSERT_ERRNO_EQ(ENAMETOOLONG);
+    return;
+  }
+
+  ASSERT_EQ(realpath_buffered("."), nullptr);
+  ASSERT_ERRNO_EQ(ENAMETOOLONG);
+}

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to