]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUILD: debug: avoid a build warning related to epoll_wait() in debug code
authorWilly Tarreau <w@1wt.eu>
Sun, 2 Jul 2023 08:49:49 +0000 (10:49 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 2 Jul 2023 09:01:37 +0000 (11:01 +0200)
Ilya reported in issue #2193 that the latest Fedora complains about us
passing NULL to epoll_wait() in the "debug dev fd" code to try to detect
an epoll FD. That was intentional to get the kernel's verifications and
make sure we're facing a poller, but since such a warning comes from the
libc, it's possible that it plans to replace the syscall with a wrapper
in the near future (e.g. epoll_pwait()), and that just hiding the NULL
(as was confirmed to work) might just postpone the problem.

Let's take another approach, instead we'll create a new dummy FD that
we'll try to remove from the epoll set using epoll_ctl(). Since we
created the FD we're certain it cannot be there.  In this case (and
only in this case) epoll_ctl() will return -ENOENT, otherwise it will
typically return EINVAL or EBADF. It was verified that it works and
doesn't return false positives for other FD types. It should be
backported to the branches that contain a backport of the commit which
introduced the feature, apparently as far as 2.4:

  5be7c198e ("DEBUG: cli: add a new "debug dev fd" expert command")

src/debug.c

index 474a6647f0bd94211e61f87028aa547e1c135cbb..89c7a53de20d78df572a0019b8be03e409631af0 100644 (file)
@@ -1384,7 +1384,27 @@ static int debug_iohandler_fd(struct appctx *appctx)
                                      S_ISLNK(statbuf.st_mode)  ? "link":
                                      S_ISSOCK(statbuf.st_mode) ? "sock":
 #ifdef USE_EPOLL
-                                     epoll_wait(fd, NULL, 0, 0) != -1 || errno != EBADF ? "epol":
+                                     /* trick: epoll_ctl() will return -ENOENT when trying
+                                      * to remove from a valid epoll FD an FD that was not
+                                      * registered against it. But we don't want to risk
+                                      * disabling a random FD. Instead we'll create a new
+                                      * one by duplicating 0 (it should be valid since
+                                      * pointing to a terminal or /dev/null), and try to
+                                      * remove it.
+                                      */
+                                     ({
+                                             int fd2 = dup(0);
+                                             int ret = fd2;
+                                             if (ret >= 0) {
+                                                     ret = epoll_ctl(fd, EPOLL_CTL_DEL, fd2, NULL);
+                                                     if (ret == -1 && errno == ENOENT)
+                                                             ret = 0; // that's a real epoll
+                                                     else
+                                                             ret = -1; // it's something else
+                                                     close(fd2);
+                                             }
+                                             ret;
+                                     }) == 0 ? "epol" :
 #endif
                                      "????",
                                      (uint)statbuf.st_mode & 07777,