From 5f05814fe5f555c9f707f77761067c531e223fcb Mon Sep 17 00:00:00 2001 From: Fabien Romano Date: Wed, 21 Oct 2026 22:54:30 +0100 Subject: [PATCH] Fix file descriptor cleanup on OpenBSD OpenBSD's /dev/fd contains static device nodes rather than a list of open descriptors. Enumerating it can encounter closed descriptors and miss open descriptors beyond the available nodes. In Process v2, use close() between retained descriptors and closefrom() above the last one, avoiding /dev/fd enumeration. For Process v1, deliberately keep the fix minimal: ignore EBADF and retry close() on EINTR, rather than rewriting the cleanup algorithm to follow the v2 approach. This prevents limit_handles failures but leaves descriptors missing from /dev/fd unhandled. --- .../boost/process/v1/detail/posix/handles.hpp | 4 +- src/posix/close_handles.cpp | 40 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/include/boost/process/v1/detail/posix/handles.hpp b/include/boost/process/v1/detail/posix/handles.hpp index bd1b498e4..88b26f69b 100644 --- a/include/boost/process/v1/detail/posix/handles.hpp +++ b/include/boost/process/v1/detail/posix/handles.hpp @@ -133,7 +133,9 @@ struct limit_handles_ : handler_base_ext if (std::find(used_handles.begin(), used_handles.end(), conv) != used_handles.end()) continue; - if (::close(conv) != 0) + int error; + while ((error = ::close(conv)) == -1 && errno == EINTR); + if (error == -1 && errno != EBADF) { exec.set_error(::boost::process::v1::detail::get_last_error(), "close() failed"); return; diff --git a/src/posix/close_handles.cpp b/src/posix/close_handles.cpp index 5795a3b1c..8de6a8978 100644 --- a/src/posix/close_handles.cpp +++ b/src/posix/close_handles.cpp @@ -24,12 +24,20 @@ // // gives us // -// int closefrom(int fd); +// void closefrom(int lowfd); // int close_range(u_int lowfd, u_int highfd, int flags); #include #define BOOST_PROCESS_V2_HAS_CLOSE_RANGE_AND_CLOSEFROM 1 +#elif defined(__OpenBSD__) + +// https://man.openbsd.org/closefrom.2 +// int closefrom(int fd); + +#include +#define BOOST_PROCESS_V2_HAS_CLOSEFROM_WITH_ERRNO 1 + #elif defined(__sun) /*https://docs.oracle.com/cd/E36784_01/html/E36874/closefrom-3c.html @@ -113,6 +121,36 @@ void close_all(const std::vector & whitelist, error_code & ec) ec = BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(); } +#elif defined(BOOST_PROCESS_V2_HAS_CLOSEFROM_WITH_ERRNO) + +// OpenBSD impl - whitelist must be ordered +void close_all(const std::vector & whitelist, error_code & /*ec*/) +{ + //the most common scenario is whitelist = {0,1,2} + if (!whitelist.empty()) + { + if (whitelist.front() != 0) { + for (int fd = 0; fd < whitelist.front(); fd++) + while (::close(fd) == -1 && errno == EINTR); + } + for (std::size_t idx = 0u; + idx < (whitelist.size() - 1u); + idx++) + { + const auto mine = whitelist[idx]; + const auto next = whitelist[idx + 1]; + if ((mine + 1) != next && (mine != next)) + { + for (int fd = mine + 1; fd < next; fd++) + while (::close(fd) == -1 && errno == EINTR); + } + } + while (::closefrom(whitelist.back() + 1) == -1 && errno == EINTR); + } + else + while (::closefrom(0) == -1 && errno == EINTR); +} + #elif defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE_AND_CLOSEFROM) // freeBSD impl - whitelist must be ordered