[libc-commits] [libc] [libc] Improve Dir class safety, performance, and style (PR #207214)

Jeff Bailey via libc-commits libc-commits at lists.llvm.org
Thu Jul 2 09:01:15 PDT 2026


https://github.com/kaladron created https://github.com/llvm/llvm-project/pull/207214

Addressed issues in the Dir class identified during review:

* Safety: Added bounds and validation checks in Dir::read to prevent out-of-bounds reads on corrupted input.
* Performance: Aligned the internal buffer to struct dirent to prevent unaligned memory access, and increased the buffer size to 4096 to reduce syscall overhead.
* Style: Replaced the system <dirent.h> include with a new proxy header (struct_dirent.h) to avoid system dependencies, and fixed relative includes.
* Refactoring: Moved platform-specific record length access to a platform helper (platform_dir_reclen).
* CMake: Updated dependencies for the dir target.

Assisted-by: Automated tooling, human reviewed.

>From ddfaefb483af148be7ef2f799ecda45a21466b56 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Thu, 2 Jul 2026 16:48:58 +0100
Subject: [PATCH] [libc] Improve Dir class safety, performance, and style

Addressed issues in the Dir class identified during review:

* Safety: Added bounds and validation checks in Dir::read to prevent
  out-of-bounds reads on corrupted input.
* Performance: Aligned the internal buffer to struct dirent to prevent
  unaligned memory access, and increased the buffer size to 4096 to
  reduce syscall overhead.
* Style: Replaced the system <dirent.h> include with a new proxy
  header (struct_dirent.h) to avoid system dependencies, and fixed
  relative includes.
* Refactoring: Moved platform-specific record length access to a
  platform helper (platform_dir_reclen).
* CMake: Updated dependencies for the dir target.

Assisted-by: Automated tooling, human reviewed.
---
 libc/hdr/CMakeLists.txt                |  1 +
 libc/hdr/dirent_overlay.h              | 23 ++++++++++++++++++
 libc/hdr/types/CMakeLists.txt          | 10 ++++++++
 libc/hdr/types/struct_dirent.h         | 27 +++++++++++++++++++++
 libc/src/__support/File/CMakeLists.txt |  5 ++++
 libc/src/__support/File/dir.cpp        | 33 +++++++++++++++++---------
 libc/src/__support/File/dir.h          | 17 +++++++++----
 libc/src/__support/File/linux/dir.cpp  |  9 ++++++-
 8 files changed, 109 insertions(+), 16 deletions(-)
 create mode 100644 libc/hdr/dirent_overlay.h
 create mode 100644 libc/hdr/types/struct_dirent.h

diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index cf3e76d5c005b..df9f126e063a1 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -56,6 +56,7 @@ add_proxy_header_library(
     libc.include.llvm-libc-macros.generic_error_number_macros
 )
 
+add_header_library(dirent_overlay HDRS dirent_overlay.h)
 add_header_library(fcntl_overlay HDRS fcntl_overlay.h)
 add_proxy_header_library(
   fcntl_macros
diff --git a/libc/hdr/dirent_overlay.h b/libc/hdr/dirent_overlay.h
new file mode 100644
index 0000000000000..26dcace618a83
--- /dev/null
+++ b/libc/hdr/dirent_overlay.h
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Overlay header for dirent.h in overlay build mode.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_DIRENT_OVERLAY_H
+#define LLVM_LIBC_HDR_DIRENT_OVERLAY_H
+
+#ifdef LIBC_FULL_BUILD
+#error "This header should only be included in overlay mode"
+#endif
+
+#include <dirent.h>
+
+#endif // LLVM_LIBC_HDR_DIRENT_OVERLAY_H
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index a130f7ee0000a..52eba03a70da3 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -1127,3 +1127,13 @@ add_proxy_header_library(
   FULL_BUILD_DEPENDS
     libc.include.llvm-libc-types.regmatch_t
 )
+
+add_proxy_header_library(
+  struct_dirent
+  HDRS
+    struct_dirent.h
+  DEPENDS
+    libc.hdr.dirent_overlay
+  FULL_BUILD_DEPENDS
+    libc.include.llvm-libc-types.struct_dirent
+)
diff --git a/libc/hdr/types/struct_dirent.h b/libc/hdr/types/struct_dirent.h
new file mode 100644
index 0000000000000..5e9e0bf974811
--- /dev/null
+++ b/libc/hdr/types/struct_dirent.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Proxy for struct dirent.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_DIRENT_H
+#define LLVM_LIBC_HDR_TYPES_STRUCT_DIRENT_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/struct_dirent.h"
+
+#else // Overlay mode
+
+#include "hdr/dirent_overlay.h"
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_STRUCT_DIRENT_H
diff --git a/libc/src/__support/File/CMakeLists.txt b/libc/src/__support/File/CMakeLists.txt
index 68bbfe31ace31..7fcca3c139788 100644
--- a/libc/src/__support/File/CMakeLists.txt
+++ b/libc/src/__support/File/CMakeLists.txt
@@ -43,6 +43,11 @@ add_object_library(
     libc.src.__support.CPP.new
     libc.src.__support.CPP.span
     libc.src.__support.threads.mutex
+    libc.src.__support.error_or
+    libc.src.__support.macros.config
+    libc.src.__support.alloc_checker
+    libc.hdr.errno_macros
+    libc.hdr.types.struct_dirent
 )
 
 if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
diff --git a/libc/src/__support/File/dir.cpp b/libc/src/__support/File/dir.cpp
index eb33656808414..4a8c0cfd1a00d 100644
--- a/libc/src/__support/File/dir.cpp
+++ b/libc/src/__support/File/dir.cpp
@@ -1,18 +1,23 @@
-//===--- Implementation of a platform independent Dir data structure ------===//
+//===----------------------------------------------------------------------===//
 //
 // 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
+/// Implementation of the platform independent Dir class.
+///
+//===----------------------------------------------------------------------===//
 
-#include "dir.h"
+#include "src/__support/File/dir.h"
 
+#include "hdr/errno_macros.h"
 #include "src/__support/CPP/mutex.h" // lock_guard
 #include "src/__support/CPP/new.h"
 #include "src/__support/alloc-checker.h"
 #include "src/__support/error_or.h"
-#include "src/__support/libc_errno.h" // For error macros
 #include "src/__support/macros/config.h"
 
 namespace LIBC_NAMESPACE_DECL {
@@ -41,14 +46,20 @@ ErrorOr<struct ::dirent *> Dir::read() {
   if (fillsize == 0)
     return nullptr;
 
-  struct ::dirent *d = reinterpret_cast<struct ::dirent *>(buffer + readptr);
-#ifdef __linux__
-  // The d_reclen field is available on Linux but not required by POSIX.
-  readptr += d->d_reclen;
-#else
-  // Other platforms have to implement how the read pointer is to be updated.
-#error "DIR read pointer update is missing."
-#endif
+  cpp::span<uint8_t> buf_span(buffer, BUFSIZE);
+
+  if (fillsize - readptr < sizeof(struct ::dirent))
+    return LIBC_NAMESPACE::Error(EIO);
+
+  struct ::dirent *d =
+      reinterpret_cast<struct ::dirent *>(buf_span.subspan(readptr).data());
+
+  size_t reclen = platform_dir_reclen(d);
+
+  if (reclen == 0 || readptr + reclen > fillsize)
+    return LIBC_NAMESPACE::Error(EIO);
+
+  readptr += reclen;
   return d;
 }
 
diff --git a/libc/src/__support/File/dir.h b/libc/src/__support/File/dir.h
index 247ac1225ceea..2643755816815 100644
--- a/libc/src/__support/File/dir.h
+++ b/libc/src/__support/File/dir.h
@@ -1,10 +1,15 @@
-//===--- A platform independent Dir class ---------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // 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
+/// Platform independent Dir class definition.
+///
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVM_LIBC_SRC___SUPPORT_FILE_DIR_H
 #define LLVM_LIBC_SRC___SUPPORT_FILE_DIR_H
@@ -14,7 +19,7 @@
 #include "src/__support/macros/config.h"
 #include "src/__support/threads/mutex.h"
 
-#include <dirent.h>
+#include "hdr/types/struct_dirent.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
@@ -31,11 +36,14 @@ int platform_closedir(int fd);
 // failure.
 ErrorOr<size_t> platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer);
 
+// Platform specific function to get the size of the directory entry record.
+size_t platform_dir_reclen(struct ::dirent *d);
+
 // This class is designed to allow implementation of the POSIX dirent.h API.
 // By itself, it is platform independent but calls platform specific
 // functions to perform OS operations.
 class Dir {
-  static constexpr size_t BUFSIZE = 1024;
+  static constexpr size_t BUFSIZE = 4096;
   int fd;
   size_t readptr = 0;  // The current read pointer.
   size_t fillsize = 0; // The number of valid bytes availabe in the buffer.
@@ -43,7 +51,8 @@ class Dir {
   // This is a buffer of struct dirent values which will be fetched
   // from the OS. Since the d_name of struct dirent can be of a variable
   // size, we store the data in a byte array.
-  uint8_t buffer[BUFSIZE];
+  // We align the buffer to struct dirent to avoid unaligned accesses.
+  alignas(struct ::dirent) uint8_t buffer[BUFSIZE];
 
   Mutex mutex;
 
diff --git a/libc/src/__support/File/linux/dir.cpp b/libc/src/__support/File/linux/dir.cpp
index 8412b42348559..b764f5482663b 100644
--- a/libc/src/__support/File/linux/dir.cpp
+++ b/libc/src/__support/File/linux/dir.cpp
@@ -1,10 +1,15 @@
-//===--- Linux implementation of the Dir helpers --------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // 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
+/// Linux implementation of the Dir helpers.
+///
+//===----------------------------------------------------------------------===//
 
 #include "src/__support/File/dir.h"
 
@@ -44,4 +49,6 @@ int platform_closedir(int fd) {
   return 0;
 }
 
+size_t platform_dir_reclen(struct ::dirent *d) { return d->d_reclen; }
+
 } // namespace LIBC_NAMESPACE_DECL



More information about the libc-commits mailing list