From: Willy Tarreau Date: Fri, 24 Jul 2026 09:31:12 +0000 (+0200) Subject: DEBUG: fd: catch access attempts to closed FDs X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=d77f75b508d9781174c9f145f600c809b886f03d;p=thirdparty%2Fhaproxy.git DEBUG: fd: catch access attempts to closed FDs Certain rare bugs may cause an fd_want_recv() or any of the other operations being done on a closed FD. This triggers a BUG_ON() on the next call trying to insert the FD but it's too late to figure when this happened. Let's just add some BUG_ON_HOT() to detect an attempt to modify the state of a closed FD so that the culprit is detected. It will only be enabled with DEBUG_STRICT=2, since by design this may never happen so it's not needed to enable it in default builds. It was verified not to trigger on various tests. --- diff --git a/include/haproxy/fd.h b/include/haproxy/fd.h index 029883d08..07e132523 100644 --- a/include/haproxy/fd.h +++ b/include/haproxy/fd.h @@ -199,6 +199,7 @@ static inline int fd_active(const int fd) /* Disable processing recv events on fd */ static inline void fd_stop_recv(int fd) { + BUG_ON_HOT(fdtab[fd].owner == NULL); if (!(fdtab[fd].state & FD_EV_ACTIVE_R) || !HA_ATOMIC_BTR(&fdtab[fd].state, FD_EV_ACTIVE_R_BIT)) return; @@ -207,6 +208,7 @@ static inline void fd_stop_recv(int fd) /* Disable processing send events on fd */ static inline void fd_stop_send(int fd) { + BUG_ON_HOT(fdtab[fd].owner == NULL); if (!(fdtab[fd].state & FD_EV_ACTIVE_W) || !HA_ATOMIC_BTR(&fdtab[fd].state, FD_EV_ACTIVE_W_BIT)) return; @@ -217,6 +219,7 @@ static inline void fd_stop_both(int fd) { uint old, new; + BUG_ON_HOT(fdtab[fd].owner == NULL); old = fdtab[fd].state; do { if (!(old & FD_EV_ACTIVE_RW)) @@ -229,6 +232,7 @@ static inline void fd_stop_both(int fd) static inline void fd_cant_recv(const int fd) { /* marking ready never changes polled status */ + BUG_ON_HOT(fdtab[fd].owner == NULL); if (!(fdtab[fd].state & FD_EV_READY_R) || !HA_ATOMIC_BTR(&fdtab[fd].state, FD_EV_READY_R_BIT)) return; @@ -238,6 +242,7 @@ static inline void fd_cant_recv(const int fd) static inline void fd_may_recv(const int fd) { /* marking ready never changes polled status */ + BUG_ON_HOT(fdtab[fd].owner == NULL); if ((fdtab[fd].state & FD_EV_READY_R) || HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_READY_R_BIT)) return; @@ -249,6 +254,7 @@ static inline void fd_may_recv(const int fd) */ static inline void fd_cond_recv(const int fd) { + BUG_ON_HOT(fdtab[fd].owner == NULL); if ((fdtab[fd].state & (FD_EV_ACTIVE_R|FD_EV_READY_R)) == 0) HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_READY_R_BIT); } @@ -259,6 +265,7 @@ static inline void fd_cond_recv(const int fd) */ static inline void fd_cond_send(const int fd) { + BUG_ON_HOT(fdtab[fd].owner == NULL); if ((fdtab[fd].state & (FD_EV_ACTIVE_W|FD_EV_READY_W)) == 0) HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_READY_W_BIT); } @@ -268,6 +275,7 @@ static inline void fd_cond_send(const int fd) */ static inline void fd_may_both(const int fd) { + BUG_ON_HOT(fdtab[fd].owner == NULL); HA_ATOMIC_OR(&fdtab[fd].state, FD_EV_READY_RW); } @@ -284,6 +292,7 @@ static inline void fd_cant_send(const int fd) static inline void fd_may_send(const int fd) { /* marking ready never changes polled status */ + BUG_ON_HOT(fdtab[fd].owner == NULL); if ((fdtab[fd].state & FD_EV_READY_W) || HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_READY_W_BIT)) return; @@ -292,6 +301,7 @@ static inline void fd_may_send(const int fd) /* Prepare FD to try to receive */ static inline void fd_want_recv(int fd) { + BUG_ON_HOT(fdtab[fd].owner == NULL); if ((fdtab[fd].state & FD_EV_ACTIVE_R) || HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_ACTIVE_R_BIT)) return; @@ -303,6 +313,7 @@ static inline void fd_want_recv(int fd) */ static inline void fd_want_recv_safe(int fd) { + BUG_ON_HOT(fdtab[fd].owner == NULL); if ((fdtab[fd].state & FD_EV_ACTIVE_R) || HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_ACTIVE_R_BIT)) return; @@ -313,6 +324,7 @@ static inline void fd_want_recv_safe(int fd) /* Prepare FD to try to send */ static inline void fd_want_send(int fd) { + BUG_ON_HOT(fdtab[fd].owner == NULL); if ((fdtab[fd].state & FD_EV_ACTIVE_W) || HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_ACTIVE_W_BIT)) return;