]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix WaitEventSet resource leak in WaitLatchOrSocket().
authorEtsuro Fujita <efujita@postgresql.org>
Thu, 11 Apr 2024 10:05:07 +0000 (19:05 +0900)
committerEtsuro Fujita <efujita@postgresql.org>
Thu, 11 Apr 2024 10:05:07 +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 d35b7ee7d1044ad0f89df5e25e0d8232a8c4ae64..d5f7f8d6366c31d6065c2b8d032141df309d3794 100644 (file)
@@ -374,46 +374,55 @@ 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_CATCH();
        {
-               ret |= event.events & (WL_LATCH_SET |
-                                                          WL_POSTMASTER_DEATH |
-                                                          WL_SOCKET_MASK);
+               FreeWaitEventSet(set);
+               PG_RE_THROW();
        }
+       PG_END_TRY();
 
        FreeWaitEventSet(set);