![]() |
|
Message-ID: <20250710185131.186-2-mailto.luca.kellermann@gmail.com> Date: Thu, 10 Jul 2025 20:51:29 +0200 From: Luca Kellermann <mailto.luca.kellermann@...il.com> To: musl@...ts.openwall.com Subject: [PATCH 2/4] scandir: don't examine errno after closedir() when closedir() set errno, scandir() misinterpreted this as a failure. this was wrong for two reasons: * if closedir() succeeds, errno could still have been set, e.g. by __aio_close(). * even if closedir() "fails", it always closes the file descriptor and frees memory, so there is no reason to free all directory entries and return from scandir() with a failure. the following program demonstrates the issue with aio: #include <aio.h> #include <dirent.h> #include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> static void die(const char *msg) { perror(msg); exit(EXIT_FAILURE); } int main(void) { struct aiocb cb = { .aio_fildes = STDIN_FILENO, .aio_buf = &(char){0}, .aio_nbytes = 1, .aio_sigevent.sigev_notify = SIGEV_NONE, }; if (aio_read(&cb)) die("aio_read"); struct dirent **es = 0; int e, n = scandir(".", &es, 0, alphasort); if (n == -1) die("scandir"); while (n > 0) free(es[--n]); free(es); if (aio_suspend(&(const struct aiocb *){&cb}, 1, 0)) die("aio_suspend"); if ((e = aio_error(&cb)) == -1) die("aio_error"); if (aio_return(&cb) == -1) { if (!e) die("aio_return"); errno = e; die("read"); } } $ ./scandir-aio scandir: No such file or directory --- src/dirent/scandir.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/dirent/scandir.c b/src/dirent/scandir.c index eead7e50..cf668535 100644 --- a/src/dirent/scandir.c +++ b/src/dirent/scandir.c @@ -12,7 +12,7 @@ int scandir(const char *path, struct dirent ***res, DIR *d = opendir(path); struct dirent *de, **names=0, **tmp; size_t cnt=0, len=0; - int old_errno = errno; + int old_errno = errno, err; if (!d) return -1; @@ -33,12 +33,18 @@ int scandir(const char *path, struct dirent ***res, if (!names[cnt]) break; memcpy(names[cnt++], de, de->d_reclen); } + /* closedir() might set errno via __aio_close(). It might also "fail" + * (return -1 and set errno). But even then, the file descriptor is + * closed and memory is freed, so there is no reason to report the + * "failure" of closedir() as a failure of scandir(). */ + err = errno; closedir(d); - if (errno) { + if (err) { if (names) while (cnt-->0) free(names[cnt]); free(names); + errno = err; return -1; } /* cmp() and caller must not observe that errno was set to 0. */ -- 2.43.0
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.