From 7e67d2d906d82da4621c3f3f6674e87c05c78399 Mon Sep 17 00:00:00 2001 From: yushuailong Date: Tue, 2 Jun 2026 14:34:04 +0800 Subject: [PATCH] libs/libc/dirent: preserve errno on readdir() end-of-directory readdir() returned NULL at end-of-directory without ensuring errno was clean. POSIX requires errno to be unchanged at EOF, but the underlying read() path may leave a stale errno value. Callers that follow the POSIX idiom (set errno to 0 before the call, test it after a NULL return), such as readdir_r() and scandir(), then misread this as a readdir() failure. Save errno on entry and restore it on the end-of-directory return so that EOF no longer reports a spurious error, while genuine errors (read() returning a negative value) still propagate. Signed-off-by: yushuailong --- libs/libc/dirent/lib_readdir.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libs/libc/dirent/lib_readdir.c b/libs/libc/dirent/lib_readdir.c index 80c587ea8d6..3b2136bca70 100644 --- a/libs/libc/dirent/lib_readdir.c +++ b/libs/libc/dirent/lib_readdir.c @@ -59,6 +59,7 @@ FAR struct dirent *readdir(DIR *dirp) { + int errcode; int ret; if (!dirp) @@ -67,11 +68,22 @@ FAR struct dirent *readdir(DIR *dirp) return NULL; } + /* Save errno so it can be restored on end-of-directory. POSIX requires + * errno to be unchanged at EOF, but the read() path may not preserve it. + */ + + errcode = get_errno(); + ret = read(dirp->fd, &dirp->entry, sizeof(struct dirent)); - if (ret <= 0) + if (ret == 0) { + set_errno(errcode); /* EOF: restore errno (not an error) */ return NULL; } + else if (ret < 0) + { + return NULL; /* error: read() already set errno */ + } return &dirp->entry; }