According to Fable 5, this overflow check can be defeated in two ways:
1. size_t underflow lets the aggregate check pass. When ipc_bind + ipc_max_connections lands exactly on MAX_IPC_FDS, the right side becomes 0 - 1 → SIZE_MAX, so any further entry is accepted and the static_cast<int> below wraps negative:
./build/bin/bitcoin-node -regtest -ipcbind=unix:/tmp/a.sock:max-connections=2147483646 -ipcbind=unix:/tmp/b.sock:max-connections=2147483646
...
2026-07-22T20:29:26Z Reserving -2 file descriptors for IPC (2 listening sockets, -4 accepted connections)
The node starts up with min_required_fds reduced by 2 instead of failing with "Too many IPC file descriptors requested".
2. Even a single entry that passes the check crashes at startup. Keeping the IPC total ≤ int max is not sufficient, because min_required_fds adds MIN_CORE_FDS + MAX_ADDNODE_CONNECTIONS + nBind on top, so the addition on L1101 overflows int (UB) and dies on an assert instead of a clean InitError:
./build/bin/bitcoin-node -regtest -ipcbind=unix:/tmp/a.sock:max-connections=2147483646
util/fs_helpers.cpp:161 int RaiseFileDescriptorLimit(int): Assertion `min_fd >= 0' failed.
Both would be solved by making MAX_IPC_FDS conservatively small instead of int max — even something like 1 << 20 is far beyond any realistic deployment and leaves all the downstream int arithmetic trivially safe — together with rearranging the check so the subtraction can't go below zero:
- if (bind->max_connections > MAX_IPC_FDS - ipc_bind - ipc_max_connections - 1) {
+ if (bind->max_connections + 1 > MAX_IPC_FDS - ipc_bind - ipc_max_connections) {
(max_connections is parse-capped at 2147483647, so the + 1 cannot overflow.)
I verified the diff locally and:
- Repro 1 now fails with "Too many IPC file descriptors requested" and the tests pass.
- Repro 2 however still hits the assertion. It needs a smaller
MAX_IPC_FDS, and the parse-level cap in ParseIpcBindAddress may want to match the chosen bound so users get the clearer "max-connections must be at most N" error at parse time.