+2025-12-02 KO Myung-Hun <komh78@gmail.com>
+
+ dup2, fcntl: Fix the race condition on OS/2 kLIBC
+ dup2() may return an fd other than the desired fd if other threads are
+ involved. fcntl() may close the fd used by other threads accidentally.
+ * lib/dup2.c (klibc_dup2dirfd): Ensure duplication to the desired fd.
+ (klibd_dup2): Do not close the desired fd.
+ * lib/fcntl.c (klibc_dupdirfd): New.
+ (klibc_fcntl): Use klibc_dupdirfd() instead of dup2().
+
2025-12-02 Bruno Haible <bruno@clisp.org>
Fix compilation error in C++ mode on FreeBSD 15.
if (tempfd == -1)
return -1;
- if (tempfd == desired_fd)
+ if (tempfd >= desired_fd)
{
close (tempfd);
if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
return -1;
- return open(path, O_RDONLY);
+ for (;;)
+ {
+ close (desired_fd);
+
+ dupfd = open (path, O_RDONLY);
+ if (dupfd == -1)
+ return -1;
+
+ if (dupfd == desired_fd)
+ return dupfd;
+
+ /* If lower FD was closed by other threads, fill again. */
+ if (dupfd < desired_fd)
+ {
+ tempfd = dupfd;
+ break;
+ }
+
+ /* desired_fd was opened by other threads. Try again. */
+ /* FIXME: Closing desired_fd opened by other threads may lead to
+ unexpected behavior. */
+ close (dupfd);
+ }
}
dupfd = klibc_dup2dirfd (fd, desired_fd);
dupfd = dup2 (fd, desired_fd);
if (dupfd == -1 && errno == ENOTSUP \
&& !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
- {
- close (desired_fd);
-
- return klibc_dup2dirfd (fd, desired_fd);
- }
+ return klibc_dup2dirfd (fd, desired_fd);
return dupfd;
}
#ifdef __KLIBC__
# include <emx/io.h>
+# include <InnoTekLIBC/backend.h>
#endif
#if defined _WIN32 && ! defined __CYGWIN__
#undef fcntl
#ifdef __KLIBC__
+static int
+klibc_dupdirfd (int fd, int minfd)
+{
+ int tempfd;
+ int dupfd;
+
+ tempfd = open ("NUL", O_RDONLY);
+ if (tempfd == -1)
+ return -1;
+
+ if (tempfd >= minfd)
+ {
+ close (tempfd);
+
+ char path[_MAX_PATH];
+ if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
+ return -1;
+
+ dupfd = open (path, O_RDONLY);
+ if (dupfd == -1)
+ return -1;
+
+ if (dupfd >= minfd)
+ return dupfd;
+
+ /* Lower FD was closed by other threads. Fill again. */
+ tempfd = dupfd;
+ }
+
+ dupfd = klibc_dupdirfd (fd, minfd);
+
+ close (tempfd);
+
+ return dupfd;
+}
static int
klibc_fcntl (int fd, int action, /* arg */...)
switch (action)
{
case F_DUPFD:
- /* Find available fd */
- while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
- arg++;
-
- result = dup2 (fd, arg);
+ result = klibc_dupdirfd (fd, arg);
break;
case F_GETFD: