Add guard to prevent recursive memory context logging. REL_16_STABLE github/REL_16_STABLE
authorFujii Masao <[email protected]>
Fri, 19 Dec 2025 03:08:20 +0000 (12:08 +0900)
committerFujii Masao <[email protected]>
Fri, 19 Dec 2025 03:08:20 +0000 (12:08 +0900)
Previously, if memory context logging was triggered repeatedly and
rapidly while a previous request was still being processed, it could
result in recursive calls to ProcessLogMemoryContextInterrupt().
This could lead to infinite recursion and potentially crash the process.

This commit adds a guard to prevent such recursion.
If ProcessLogMemoryContextInterrupt() is already in progress and
logging memory contexts, subsequent calls will exit immediately,
avoiding unintended recursive calls.

While this scenario is unlikely in practice, it's not impossible.
This change adds a safety check to prevent such failures.

Back-patch to v14, where memory context logging was introduced.

Reported-by: Robert Haas <[email protected]>
Author: Fujii Masao <[email protected]>
Reviewed-by: Atsushi Torikoshi <[email protected]>
Reviewed-by: Robert Haas <[email protected]>
Reviewed-by: Artem Gavrilov <[email protected]>
Discussion: https://postgr.es/m/CA+TgmoZMrv32tbNRrFTvF9iWLnTGqbhYSLVcrHGuwZvCtph0NA@mail.gmail.com
Backpatch-through: 14

src/backend/utils/mmgr/mcxt.c

index 9fc83f11f6f1ff6b56d62eaf4a28af7cfd54779f..30286a3ff337ffbe528132cf4659c33afe7eefe1 100644 (file)
@@ -149,6 +149,9 @@ MemoryContext CurTransactionContext = NULL;
 /* This is a transient link to the active portal's memory context: */
 MemoryContext PortalContext = NULL;
 
+/* Is memory context logging currently in progress? */
+static bool LogMemoryContextInProgress = false;
+
 static void MemoryContextCallResetCallbacks(MemoryContext context);
 static void MemoryContextStatsInternal(MemoryContext context, int level,
                                       bool print, int max_children,
@@ -1201,25 +1204,45 @@ ProcessLogMemoryContextInterrupt(void)
    LogMemoryContextPending = false;
 
    /*
-    * Use LOG_SERVER_ONLY to prevent this message from being sent to the
-    * connected client.
+    * Exit immediately if memory context logging is already in progress. This
+    * prevents recursive calls, which could occur if logging is requested
+    * repeatedly and rapidly, potentially leading to infinite recursion and a
+    * crash.
     */
-   ereport(LOG_SERVER_ONLY,
-           (errhidestmt(true),
-            errhidecontext(true),
-            errmsg("logging memory contexts of PID %d", MyProcPid)));
+   if (LogMemoryContextInProgress)
+       return;
+   LogMemoryContextInProgress = true;
 
-   /*
-    * When a backend process is consuming huge memory, logging all its memory
-    * contexts might overrun available disk space. To prevent this, we limit
-    * the number of child contexts to log per parent to 100.
-    *
-    * As with MemoryContextStats(), we suppose that practical cases where the
-    * dump gets long will typically be huge numbers of siblings under the
-    * same parent context; while the additional debugging value from seeing
-    * details about individual siblings beyond 100 will not be large.
-    */
-   MemoryContextStatsDetail(TopMemoryContext, 100, false);
+   PG_TRY();
+   {
+       /*
+        * Use LOG_SERVER_ONLY to prevent this message from being sent to the
+        * connected client.
+        */
+       ereport(LOG_SERVER_ONLY,
+               (errhidestmt(true),
+                errhidecontext(true),
+                errmsg("logging memory contexts of PID %d", MyProcPid)));
+
+       /*
+        * When a backend process is consuming huge memory, logging all its
+        * memory contexts might overrun available disk space. To prevent
+        * this, we limit the number of child contexts to log per parent to
+        * 100.
+        *
+        * As with MemoryContextStats(), we suppose that practical cases where
+        * the dump gets long will typically be huge numbers of siblings under
+        * the same parent context; while the additional debugging value from
+        * seeing details about individual siblings beyond 100 will not be
+        * large.
+        */
+       MemoryContextStatsDetail(TopMemoryContext, 100, false);
+   }
+   PG_FINALLY();
+   {
+       LogMemoryContextInProgress = false;
+   }
+   PG_END_TRY();
 }
 
 void *