[libc-commits] [libc] ffb3458 - [libc][getcwd] Refactor getcwd to use the syscall wrapper pattern (#204000)
via libc-commits
libc-commits at lists.llvm.org
Tue Jun 16 08:54:12 PDT 2026
Author: Jackson Stogel
Date: 2026-06-16T08:54:07-07:00
New Revision: ffb3458175268cb08a97a4bdcc3ca3181cfeaf57
URL: https://github.com/llvm/llvm-project/commit/ffb3458175268cb08a97a4bdcc3ca3181cfeaf57
DIFF: https://github.com/llvm/llvm-project/commit/ffb3458175268cb08a97a4bdcc3ca3181cfeaf57.diff
LOG: [libc][getcwd] Refactor getcwd to use the syscall wrapper pattern (#204000)
Allows for re-use by other entrypoints. This PR also moves error
handling for unreachable paths in `syscall_wrappers::getcwd` since I
imagine most usages of getcwd would rather error with `ENOENT` than
receive `"(unreachable) /path/to/cwd"`.
Added:
libc/src/__support/OSUtil/linux/syscall_wrappers/getcwd.h
Modified:
libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
libc/src/unistd/linux/CMakeLists.txt
libc/src/unistd/linux/getcwd.cpp
Removed:
################################################################################
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 97848b1848660..36af7ffa898f1 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -542,6 +542,20 @@ add_header_library(
libc.include.sys_syscall
)
+add_header_library(
+ getcwd
+ HDRS
+ getcwd.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.types.ssize_t
+ libc.include.sys_syscall
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.src.__support.OSUtil.osutil
+)
+
add_header_library(
link
HDRS
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/getcwd.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/getcwd.h
new file mode 100644
index 0000000000000..f0aa9cb3fbab8
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/getcwd.h
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for getcwd.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETCWD_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETCWD_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<ssize_t> getcwd(char *buf, size_t size) {
+ ssize_t ret = syscall_impl<ssize_t>(SYS_getcwd, buf, size);
+ if (ret < 0) {
+ return Error(static_cast<int>(-ret));
+ }
+
+ // Return ENOENT for unreachable paths. This can occur, for example,
+ // when getcwd is called in a directory after `chroot` has switched
+ // the filesystem root.
+ if (ret == 0 || buf[0] != '/') {
+ return Error(ENOENT);
+ }
+
+ return ret;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETCWD_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index be057b4f80972..592349f1039fe 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -223,11 +223,13 @@ add_entrypoint_object(
../getcwd.h
DEPENDS
libc.hdr.types.size_t
- libc.hdr.fcntl_macros
- libc.include.unistd
- libc.include.sys_syscall
- libc.src.__support.OSUtil.osutil
+ libc.hdr.types.ssize_t
+ libc.src.__support.common
+ libc.src.__support.CPP.optional
+ libc.src.__support.macros.config
+ libc.src.__support.OSUtil.linux.syscall_wrappers.getcwd
libc.src.errno.errno
+ libc.src.string.allocating_string_utils
)
add_entrypoint_object(
diff --git a/libc/src/unistd/linux/getcwd.cpp b/libc/src/unistd/linux/getcwd.cpp
index c0e475dd3e8ff..4a4461ff6ca9a 100644
--- a/libc/src/unistd/linux/getcwd.cpp
+++ b/libc/src/unistd/linux/getcwd.cpp
@@ -8,33 +8,19 @@
#include "src/unistd/getcwd.h"
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getcwd.h"
#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/string/allocating_string_utils.h" // For strdup.
-#include "src/__support/libc_errno.h"
#include <linux/limits.h> // This is safe to include without any name pollution.
-#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
-namespace {
-
-bool getcwd_syscall(char *buf, size_t size) {
- int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_getcwd, buf, size);
- if (ret < 0) {
- libc_errno = -ret;
- return false;
- } else if (ret == 0 || buf[0] != '/') {
- libc_errno = ENOENT;
- return false;
- }
- return true;
-}
-
-} // anonymous namespace
-
LLVM_LIBC_FUNCTION(char *, getcwd, (char *buf, size_t size)) {
if (buf == nullptr) {
// We match glibc's behavior here and return the cwd in a malloc-ed buffer.
@@ -42,24 +28,34 @@ LLVM_LIBC_FUNCTION(char *, getcwd, (char *buf, size_t size)) {
// into it. This way, if the syscall fails, we avoid unnecessary malloc
// and free.
char pathbuf[PATH_MAX];
- if (!getcwd_syscall(pathbuf, PATH_MAX))
+
+ ErrorOr<ssize_t> bytes_written = linux_syscalls::getcwd(pathbuf, PATH_MAX);
+ if (!bytes_written) {
+ libc_errno = bytes_written.error();
return nullptr;
- auto cwd = internal::strdup(pathbuf);
+ }
+
+ cpp::optional<char *> cwd = internal::strdup(pathbuf);
if (!cwd) {
libc_errno = ENOMEM;
return nullptr;
}
return *cwd;
- } else if (size == 0) {
+ }
+
+ if (size == 0) {
libc_errno = EINVAL;
return nullptr;
}
// TODO: When buf is not sufficient, evaluate the full cwd path using
// alternate approaches.
-
- if (!getcwd_syscall(buf, size))
+ ErrorOr<ssize_t> bytes_written = linux_syscalls::getcwd(buf, size);
+ if (!bytes_written) {
+ libc_errno = bytes_written.error();
return nullptr;
+ }
+
return buf;
}
More information about the libc-commits
mailing list