[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