Fix WaitEventSet resource leak in WaitLatchOrSocket().
authorEtsuro Fujita <[email protected]>
Thu, 11 Apr 2024 10:05:00 +0000 (19:05 +0900)
committerEtsuro Fujita <[email protected]>
Thu, 11 Apr 2024 10:05:00 +0000 (19:05 +0900)
This function would have the same issue we solved in commit 501cfd07d:
If an error is thrown after calling CreateWaitEventSet(), the file
descriptor (on epoll- or kqueue-based systems) or handles (on Windows)
that the WaitEventSet contains are leaked.

Like that commit, use PG_TRY-PG_FINALLY (PG_TRY-PG_CATCH in v12) to make
sure the WaitEventSet is freed properly.

Back-patch to all supported versions, but as we do not have this issue
in HEAD (cf. commit 50c67c201), no need to apply this patch to it.

Discussion: https://postgr.es/m/CAPmGK16MqdDoD8oatp8SQWaEa4vS3nfQqDN_Sj9YRuu5J3Lj9g%40mail.gmail.com

src/backend/storage/ipc/latch.c

index cdb95c1931add95c9d9ce0d9da73c17727e0b711..767328039e3d00da5803a07d273ad75b4995d190 100644 (file)
@@ -545,48 +545,54 @@ WaitLatchOrSocket(Latch *latch, int wakeEvents, pgsocket sock,
    WaitEvent   event;
    WaitEventSet *set = CreateWaitEventSet(CurrentMemoryContext, 3);
 
-   if (wakeEvents & WL_TIMEOUT)
-       Assert(timeout >= 0);
-   else
-       timeout = -1;
+   PG_TRY();
+   {
+       if (wakeEvents & WL_TIMEOUT)
+           Assert(timeout >= 0);
+       else
+           timeout = -1;
 
-   if (wakeEvents & WL_LATCH_SET)
-       AddWaitEventToSet(set, WL_LATCH_SET, PGINVALID_SOCKET,
-                         latch, NULL);
+       if (wakeEvents & WL_LATCH_SET)
+           AddWaitEventToSet(set, WL_LATCH_SET, PGINVALID_SOCKET,
+                             latch, NULL);
 
-   /* Postmaster-managed callers must handle postmaster death somehow. */
-   Assert(!IsUnderPostmaster ||
-          (wakeEvents & WL_EXIT_ON_PM_DEATH) ||
-          (wakeEvents & WL_POSTMASTER_DEATH));
+       /* Postmaster-managed callers must handle postmaster death somehow. */
+       Assert(!IsUnderPostmaster ||
+              (wakeEvents & WL_EXIT_ON_PM_DEATH) ||
+              (wakeEvents & WL_POSTMASTER_DEATH));
 
-   if ((wakeEvents & WL_POSTMASTER_DEATH) && IsUnderPostmaster)
-       AddWaitEventToSet(set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
-                         NULL, NULL);
+       if ((wakeEvents & WL_POSTMASTER_DEATH) && IsUnderPostmaster)
+           AddWaitEventToSet(set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
+                             NULL, NULL);
 
-   if ((wakeEvents & WL_EXIT_ON_PM_DEATH) && IsUnderPostmaster)
-       AddWaitEventToSet(set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
-                         NULL, NULL);
+       if ((wakeEvents & WL_EXIT_ON_PM_DEATH) && IsUnderPostmaster)
+           AddWaitEventToSet(set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
+                             NULL, NULL);
 
-   if (wakeEvents & WL_SOCKET_MASK)
-   {
-       int         ev;
+       if (wakeEvents & WL_SOCKET_MASK)
+       {
+           int         ev;
 
-       ev = wakeEvents & WL_SOCKET_MASK;
-       AddWaitEventToSet(set, ev, sock, NULL, NULL);
-   }
+           ev = wakeEvents & WL_SOCKET_MASK;
+           AddWaitEventToSet(set, ev, sock, NULL, NULL);
+       }
 
-   rc = WaitEventSetWait(set, timeout, &event, 1, wait_event_info);
+       rc = WaitEventSetWait(set, timeout, &event, 1, wait_event_info);
 
-   if (rc == 0)
-       ret |= WL_TIMEOUT;
-   else
+       if (rc == 0)
+           ret |= WL_TIMEOUT;
+       else
+       {
+           ret |= event.events & (WL_LATCH_SET |
+                                  WL_POSTMASTER_DEATH |
+                                  WL_SOCKET_MASK);
+       }
+   }
+   PG_FINALLY();
    {
-       ret |= event.events & (WL_LATCH_SET |
-                              WL_POSTMASTER_DEATH |
-                              WL_SOCKET_MASK);
+       FreeWaitEventSet(set);
    }
-
-   FreeWaitEventSet(set);
+   PG_END_TRY();
 
    return ret;
 }