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

>From a86a5164b800301962270e8f03f742e263d2ff86 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 357073f61962b..e71e3bf3e4ddf 100644
--- a/libc/src/stdlib/linux/CMakeLists.txt
+++ b/libc/src/stdlib/linux/CMakeLists.txt
@@ -30,6 +30,7 @@ add_entrypoint_object(
     libc.src.__support.libc_errno
     libc.src.__support.macros.config
     libc.src.__support.OSUtil.linux.stat.kernel_statx_types
+    libc.src.__support.OSUtil.linux.syscall_wrappers.getcwd
     libc.src.__support.OSUtil.linux.syscall_wrappers.statx
     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 bebfc14f3d256..4c6a1e14e8e47 100644
--- a/libc/src/stdlib/linux/realpath.cpp
+++ b/libc/src/stdlib/linux/realpath.cpp
@@ -22,6 +22,7 @@
 #include "src/__support/CPP/string.h"
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/OSUtil/linux/stat/kernel_statx_types.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getcwd.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/statx.h"
 #include "src/__support/OSUtil/path.h"
 #include "src/__support/common.h"
@@ -46,7 +47,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 bc55bc502f310..ab9cafcf62968 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -400,7 +400,9 @@ add_libc_test(
     libc.src.stdlib.realpath
     libc.src.string.strdup
     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 f0827bf260567..e9d101ac9b490 100644
--- a/libc/test/src/stdlib/realpath_test.cpp
+++ b/libc/test/src/stdlib/realpath_test.cpp
@@ -27,7 +27,9 @@
 #include "src/stdlib/realpath.h"
 #include "src/string/strdup.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"
@@ -36,6 +38,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;
 
@@ -154,10 +157,23 @@ class TestDir {
   }
 };
 
-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) {
@@ -190,7 +206,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) {
@@ -384,3 +404,64 @@ TEST_F(LlvmLibcRealpathTest, 
ErrorsWithNoAccesWhenDirectoryNotSearchable) {
   ASSERT_STREQ(realpath_buffered(test_dir.abspath("a/b")), nullptr);
   ASSERT_ERRNO_EQ(EACCES);
 }
+
+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.abspath("a").c_str());
+}
+
+// Creates a directory with the desired_size and then chdir's into it.
+// Returns true on success.
+[[nodiscard]] bool chdir_to_abspath_with_size(TestDir &test_dir,
+                                              size_t desired_size,
+                                              cpp::string &out) {
+  if (!create_abspath_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 relpath 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_abspath_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_abspath_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