[libc-commits] [libc] [libc] Use the dup2 syscall wrapper in posix_spawn (PR #207879)
Mikhail R. Gadelha via libc-commits
libc-commits at lists.llvm.org
Mon Jul 6 18:17:09 PDT 2026
https://github.com/mikhailramalho created https://github.com/llvm/llvm-project/pull/207879
posix_spawn's local dup2 helper fell back to a bare dup3 on targets without SYS_dup2. dup3 fails with EINVAL when oldfd == newfd, where dup2 must instead return oldfd if it is valid, so posix_spawn_file_actions_adddup2 with equal fds misbehaved on those targets. linux_syscalls::dup2 already implements the correct fallback, so call it directly and drop the local helper.
>From 3a6256780b2a30e5bf6a1039d4a75f6d56133d30 Mon Sep 17 00:00:00 2001
From: "Mikhail R. Gadelha" <mikhail at igalia.com>
Date: Mon, 6 Jul 2026 22:15:30 -0300
Subject: [PATCH] [libc] Use the dup2 syscall wrapper in posix_spawn
posix_spawn's local dup2 helper fell back to a bare dup3 on targets
without SYS_dup2 (riscv32, aarch64). dup3 fails with EINVAL when
oldfd == newfd, where dup2 must instead return oldfd if it is valid,
so posix_spawn_file_actions_adddup2 with equal fds misbehaved on
those targets. linux_syscalls::dup2 already implements the correct
fallback, so call it directly and drop the local helper.
---
libc/src/spawn/linux/CMakeLists.txt | 1 +
libc/src/spawn/linux/posix_spawn.cpp | 18 ++++--------------
2 files changed, 5 insertions(+), 14 deletions(-)
diff --git a/libc/src/spawn/linux/CMakeLists.txt b/libc/src/spawn/linux/CMakeLists.txt
index 42057e9f12fec..910705af85b3d 100644
--- a/libc/src/spawn/linux/CMakeLists.txt
+++ b/libc/src/spawn/linux/CMakeLists.txt
@@ -11,6 +11,7 @@ add_entrypoint_object(
libc.include.sys_syscall
libc.include.signal
libc.src.__support.OSUtil.osutil
+ libc.src.__support.OSUtil.linux.syscall_wrappers.dup2
libc.src.__support.OSUtil.linux.syscall_wrappers.open
libc.src.spawn.file_actions
libc.src.signal.linux.signal_utils
diff --git a/libc/src/spawn/linux/posix_spawn.cpp b/libc/src/spawn/linux/posix_spawn.cpp
index 301be6d7c8762..2961dd5c6b82c 100644
--- a/libc/src/spawn/linux/posix_spawn.cpp
+++ b/libc/src/spawn/linux/posix_spawn.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/spawn/posix_spawn.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/dup2.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
@@ -41,18 +42,6 @@ pid_t fork() {
void close(int fd) { LIBC_NAMESPACE::syscall_impl<long>(SYS_close, fd); }
-// We use dup3 if dup2 is not available, similar to our implementation of dup2
-bool dup2(int fd, int newfd) {
-#ifdef SYS_dup2
- int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_dup2, fd, newfd);
-#elif defined(SYS_dup3)
- int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_dup3, fd, newfd, 0);
-#else
-#error "dup2 and dup3 syscalls not available."
-#endif
- return ret < 0 ? false : true;
-}
-
// All exits from child_process are error exits. So, we use a simple
// exit implementation which exits with code 127.
void exit() {
@@ -84,7 +73,8 @@ void child_process(const char *__restrict path,
exit();
int actual_fd = *fd;
if (actual_fd != open_act->fd) {
- bool dup2_result = dup2(actual_fd, open_act->fd);
+ bool dup2_result =
+ linux_syscalls::dup2(actual_fd, open_act->fd).has_value();
close(actual_fd); // The old fd is not needed anymore.
if (!dup2_result)
exit();
@@ -98,7 +88,7 @@ void child_process(const char *__restrict path,
}
case BaseSpawnFileAction::DUP2: {
auto *dup2_act = reinterpret_cast<SpawnFileDup2Action *>(act);
- if (!dup2(dup2_act->fd, dup2_act->newfd))
+ if (!linux_syscalls::dup2(dup2_act->fd, dup2_act->newfd).has_value())
exit();
break;
}
More information about the libc-commits
mailing list