ListenConnections stops listening for good after one temporary accept() failure such as EMFILE
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 57/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- cpp
- Área
- backend, networking
Línea de trabajo
Start with _Listen() in include/mp/proxy-io.h and the accept error handler in src/mp/proxy.cpp; then read listen_tests.cpp and its ListenSetup helper. Add a test that wraps the receiver so its first accept() returns OVERLOADED, then confirm a later client is served after retry. Done means temporary overloads retry after a delay while other accept errors still stop the listener.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
If accept() fails once in ListenConnections, even with a temporary error like running out of file descriptors (EMFILE), the listener stops for good: nothing accepts new clients again until the process restarts. If other IPC connections are open, the listening socket stays open and new clients connect but are never served; once those connections close, or right away if there were none, the socket is closed and clients get "connection refused". Temporary errors should be retried after a short delay.
Where
_Listen() adds receiver->accept().then(...) to the event loop's task set and only schedules the next accept from inside the success continuation. A failed accept goes to the task set's error handler, which logs "Uncaught exception in daemonized task" and drops the task. Nothing schedules another accept, and the dropped continuation held a std::shared_ptr<Listener>. The only other references are in the disconnect callbacks of open connections, so the receiver and its socket are destroyed when the last of those closes, or right away if there are none.
kj reports EMFILE, ENFILE, ENOBUFS and ENOMEM from accept() as kj::Exception::Type::OVERLOADED, so these errors are recognizable as temporary.
Origin
The missing retry has been there since ListenConnections was added in bitcoin-core/libmultiprocess@d519e1885990 (2019). The accept continuation was then the receiver's only owner, so a failed accept closed the socket at once. #269 (connection limit, merged 2026-07-08) moved the receiver into a shared Listener that open connections also reference, which is why new clients now hang until those connections close. In Bitcoin Core the listener is reachable since -ipcbind was added (bitcoin/bitcoin#30509, v30.0); the hanging variant arrived with the subtree update bitcoin/bitcoin#35684 and is in v32.0.
Impact on Bitcoin Core
An -ipcbind listener in bitcoin-node stops serving new IPC clients until restart (they hang while an existing client such as a mining client stays connected, and are refused after that) if the process runs out of descriptors while a client is connecting. The node itself keeps running. bitcoin/bitcoin#35037 now counts IPC listeners and connection slots in the node's descriptor budget, so this needs a descriptor leak or other open files, but the listener should survive it. Other users of the library have no such budget.
Possible fix
Catch only OVERLOADED errors from the accept, log a warning once per run of failures (including the error text, so EMFILE can be told apart from ENOMEM), wait briefly on the event loop's timer, and call _Listen() again. Other errors keep ending the listener as they do now, so a permanent failure cannot become a busy loop. A capped backoff (start small, double up to about a second) would be a little friendlier than a fixed delay.
This is not the blanket retry rejected in #310 (review). That concern was an immediate retry on every error, which would spin on permanent failures and on resource exhaustion; a delayed retry limited to OVERLOADED errors does neither.
Test
No descriptor limits need to change. Wrap the real listening socket in a kj::ConnectionReceiver whose first accept() returns an OVERLOADED exception and forwards later calls, pass it to _Listen(), connect a client and check it is served:
class FailFirstAccept final : public kj::ConnectionReceiver
{
public:
FailFirstAccept(kj::Own<kj::ConnectionReceiver> inner, kj::Exception::Type type)
: m_inner(kj::mv(inner)), m_type(type) {}
kj::Promise<kj::Own<kj::AsyncIoStream>> accept() override
{
if (m_fail) {
m_fail = false;
return kj::Exception(m_type, __FILE__, __LINE__, kj::str("simulated accept failure"));
}
return m_inner->accept();
}
uint getPort() override { return m_inner->getPort(); }
kj::Own<kj::ConnectionReceiver> m_inner;
kj::Exception::Type m_type;
bool m_fail{true};
};
With ListenSetup in listen_tests.cpp building the listener from that wrapper, the test fails at once without a fix (no other connections are open, so the socket closes and the client's connect() is refused) and passes with the retry, in about the length of the delay. Checked 2026-10-15 against Bitcoin Core master (bitcoin/bitcoin@badc9574810, which carries libmultiprocess v13 in its subtree). Full test and fix: https://ipcbugs.ofsky.org/bugs/mp-2026-accept-failure-stops-listener/#reproduction
Reported privately in an independent security review, 2026-10-15 (audit report AR-79).
Links
- ipcbugs pages: https://ipcbugs.ofsky.org/bugs/mp-2026-accept-failure-stops-listener/, https://ipcbugs.ofsky.org/audits/ar-79/
- Same failure shape, different error: bitcoin/bitcoin#35796 (macOS
setsockopterror after a queued client disconnects, fixed in Cap'n Proto), #310 - bitcoin/bitcoin#35037 (IPC connection limits and descriptor reservation)
- Lenguaje dominante
- C++
- Estrellas
- 62
- Forks
- 58
- Merge medio
- 6 d 11 h
- PR fusionados (30 d)
- 7
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de bitcoin-core/libmultiprocess
-
Listeners can't be stopped, so bitcoin-node can hang after shutdown when an IPC client reconnectsAbiertobug
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
bitcoin-core/libmultiprocess#385 ·
Los mantenedores suelen responder en 1 día
-
Calling an IPC object after or during destroy() makes the server use a null or freed implementationPosiblemente ocupada @xyzconstant la tomó hace 13 días. Abiertobug hardening
Dificultad 4/5 3-5 días Aptitud para principiantes 40/100
bitcoin-core/libmultiprocess#378 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
iwyu: --check_also=*.h ?Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
bitcoin-core/libmultiprocess#329 · 2 comentarios · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Dificultad 3/5 1-2 días Aptitud para principiantes 62/100
bitcoin-core/libmultiprocess#328 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
bitcoin-core/libmultiprocess#284 · 6 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de bitcoin-core/libmultiprocess
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
arvidn/libtorrent#9126 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Sunrisepeak/mcpp-language-server#80 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
-
#2754 make deepseek api not workAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
xiaoyifang/goldendict-ng#3148 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 91/100
triton-inference-server/server#9069 ·
Los mantenedores suelen responder en 1 día