From a9c4d13717399324b96ae28a3f1cae6d4c179928 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 6 Feb 2026 01:12:23 -0600 Subject: [PATCH] Common/Network: Introduce a Safe_FD_SET function to produce an ERROR_LOG where FD_SET/select have potential to fail on Linux. --- Source/Core/Common/Network.h | 23 ++++++++++++++++++- Source/Core/Common/TraversalServer.cpp | 5 ++-- Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp | 4 ++-- .../Core/HW/EXI/BBA/TAPServerConnection.cpp | 2 +- Source/Core/Core/HW/EXI/BBA/TAP_Unix.cpp | 2 +- Source/Core/Core/IOS/Network/Socket.cpp | 10 ++++---- Source/Core/Core/PowerPC/GDBStub.cpp | 3 ++- 7 files changed, 36 insertions(+), 13 deletions(-) diff --git a/Source/Core/Common/Network.h b/Source/Core/Common/Network.h index 5e0da6559e..46e1ba870d 100644 --- a/Source/Core/Common/Network.h +++ b/Source/Core/Common/Network.h @@ -10,8 +10,13 @@ #include #include -#if defined(__linux__) || defined(__HAIKU__) +#if defined(_WIN32) +#include +#else +#include #include + +#include "Common/Logging/Log.h" #endif #include "Common/CommonTypes.h" @@ -318,4 +323,20 @@ static constexpr int SEND_FLAGS = MSG_NOSIGNAL; static constexpr int SEND_FLAGS = 0; #endif +// TODO: Don't use FD_SET and select(). +// See WARNING at https://www.man7.org/linux/man-pages/man2/select.2.html +constexpr void Safe_FD_SET(auto fd, fd_set* fds) +{ +#if !defined(_WIN32) + // On non-Windows, fd_set is a bitset and socket values must be within [0, FD_SETSIZE). + if (fd < 0 || fd >= FD_SETSIZE) + { + ERROR_LOG_FMT(COMMON, "FD_SET: Invalid socket: {}", fd); + return; + } +#endif + + FD_SET(fd, fds); +} + } // namespace Common diff --git a/Source/Core/Common/TraversalServer.cpp b/Source/Core/Common/TraversalServer.cpp index 0a9b6c0d0b..866e71e56a 100644 --- a/Source/Core/Common/TraversalServer.cpp +++ b/Source/Core/Common/TraversalServer.cpp @@ -20,6 +20,7 @@ #include #endif +#include "Common/Network.h" #include "Common/Random.h" #include "Common/TraversalProto.h" @@ -467,8 +468,8 @@ int main() tv.tv_usec = 300000; fd_set readSet; FD_ZERO(&readSet); - FD_SET(sock, &readSet); - FD_SET(sockAlt, &readSet); + Common::Safe_FD_SET(sock, &readSet); + Common::Safe_FD_SET(sockAlt, &readSet); rv = select(std::max(sock, sockAlt) + 1, &readSet, nullptr, nullptr, &tv); if (rv < 0) { diff --git a/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp b/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp index ed9cd5b488..1d1086f32d 100644 --- a/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp +++ b/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp @@ -844,8 +844,8 @@ BbaTcpSocket::ConnectingState BbaTcpSocket::Connected(StackRef* ref) FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&except_fds); - FD_SET(fd, &write_fds); - FD_SET(fd, &except_fds); + Common::Safe_FD_SET(fd, &write_fds); + Common::Safe_FD_SET(fd, &except_fds); if (select(nfds, &read_fds, &write_fds, &except_fds, &t) < 0) { diff --git a/Source/Core/Core/HW/EXI/BBA/TAPServerConnection.cpp b/Source/Core/Core/HW/EXI/BBA/TAPServerConnection.cpp index 570221c72b..0bb2e4fab2 100644 --- a/Source/Core/Core/HW/EXI/BBA/TAPServerConnection.cpp +++ b/Source/Core/Core/HW/EXI/BBA/TAPServerConnection.cpp @@ -249,7 +249,7 @@ void TAPServerConnection::ReadThreadHandler() { fd_set rfds; FD_ZERO(&rfds); - FD_SET(m_fd, &rfds); + Common::Safe_FD_SET(m_fd, &rfds); timeval timeout; timeout.tv_sec = 0; diff --git a/Source/Core/Core/HW/EXI/BBA/TAP_Unix.cpp b/Source/Core/Core/HW/EXI/BBA/TAP_Unix.cpp index a147cc7073..fa09e66b2c 100644 --- a/Source/Core/Core/HW/EXI/BBA/TAP_Unix.cpp +++ b/Source/Core/Core/HW/EXI/BBA/TAP_Unix.cpp @@ -129,7 +129,7 @@ void CEXIETHERNET::TAPNetworkInterface::ReadThreadHandler(TAPNetworkInterface* s { fd_set rfds; FD_ZERO(&rfds); - FD_SET(self->fd, &rfds); + Common::Safe_FD_SET(self->fd, &rfds); struct timeval timeout; timeout.tv_sec = 0; diff --git a/Source/Core/Core/IOS/Network/Socket.cpp b/Source/Core/Core/IOS/Network/Socket.cpp index 6baf371204..6dbb9b6080 100644 --- a/Source/Core/Core/IOS/Network/Socket.cpp +++ b/Source/Core/Core/IOS/Network/Socket.cpp @@ -773,8 +773,8 @@ WiiSocket::ConnectingState WiiSocket::GetConnectingState() const FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&except_fds); - FD_SET(fd, &write_fds); - FD_SET(fd, &except_fds); + Common::Safe_FD_SET(fd, &write_fds); + Common::Safe_FD_SET(fd, &except_fds); if (select(nfds, &read_fds, &write_fds, &except_fds, &t) < 0) { @@ -1007,9 +1007,9 @@ void WiiSockMan::Update() const WiiSocket& sock = socket_iter->second; if (sock.IsValid()) { - FD_SET(sock.fd, &read_fds); - FD_SET(sock.fd, &write_fds); - FD_SET(sock.fd, &except_fds); + Common::Safe_FD_SET(sock.fd, &read_fds); + Common::Safe_FD_SET(sock.fd, &write_fds); + Common::Safe_FD_SET(sock.fd, &except_fds); nfds = std::max(nfds, sock.fd + 1); ++socket_iter; } diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 088a74c926..b43a8887cd 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -24,6 +24,7 @@ typedef SSIZE_T ssize_t; #include "Common/Assert.h" #include "Common/Logging/Log.h" +#include "Common/Network.h" #include "Common/SocketContext.h" #include "Core/Core.h" #include "Core/HW/CPU.h" @@ -260,7 +261,7 @@ static bool IsDataAvailable() fd_set _fds, *fds = &_fds; FD_ZERO(fds); - FD_SET(s_sock, fds); + Common::Safe_FD_SET(s_sock, fds); t.tv_sec = 0; t.tv_usec = 20;