[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