]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
DEBUG: fd: catch access attempts to closed FDs
authorWilly Tarreau <w@1wt.eu>
Fri, 24 Jul 2026 09:31:12 +0000 (11:31 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 24 Jul 2026 09:33:44 +0000 (11:33 +0200)
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.

include/haproxy/fd.h

index 029883d087ed9c6d6c3478c5c4b7f924a548f9e7..07e1325239f85cb5e16d11832e67351c0c48346a 100644 (file)
@@ -199,6 +199,7 @@ static inline int fd_active(const int fd)
 /* Disable processing recv events on fd <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 <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 <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 <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;