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
