On 2025/05/05 23:57, Robert Haas wrote:
On Fri, May 2, 2025 at 9:54 PM Fujii Masao <masao.fu...@oss.nttdata.com> wrote:
Thanks for the review and testing! I've fixed the issue you pointed out.
Updated patch attached.

Thanks for addressing this. However, I believe this commit may need to
take note of the following comment from elog.h:

Thanks for the review!


  * Note: if a local variable of the function containing PG_TRY is modified
  * in the PG_TRY section and used in the PG_CATCH section, that variable
  * must be declared "volatile" for POSIX compliance.  This is not mere
  * pedantry; we have seen bugs from compilers improperly optimizing code
  * away when such a variable was not marked.  Beware that gcc's -Wclobbered
  * warnings are just about entirely useless for catching such oversights.

Based on this comment, I believe in_progress must be declared volatile.

You're right. OTOH, setting the flag inside the PG_TRY() block isn't necessary,
so I've moved it outside instead of leaving it inside and marking the flag 
volatile.


As a stylistic comment, I think I would prefer making in_progress a
file-level global and giving it a less generic name (e.g.
LogMemoryContextInProgress). However, perhaps others will disagree.

I'm fine with this. I've renamed the flag and made it a file-level global
variable as suggested. Updated patch is attached.

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION
From c5870f8b41118d1208d111101b9a360f1abc7e53 Mon Sep 17 00:00:00 2001
From: Fujii Masao <fu...@postgresql.org>
Date: Wed, 7 May 2025 17:45:02 +0900
Subject: [PATCH v3] Add guard to prevent recursive memory context logging.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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 <robertmh...@gmail.com>
Author: Fujii Masao <masao.fu...@gmail.com>
Reviewed-by: Atsushi Torikoshi <torikos...@oss.nttdata.com>
Reviewed-by: Robert Haas <robertmh...@gmail.com>
Discussion: 
https://postgr.es/m/ca+tgmozmrv32tbnrrftvf9iwlntgqbhyslvcrhguwzvctph...@mail.gmail.com
Backpatch-through: 14
---
 src/backend/utils/mmgr/mcxt.c | 57 ++++++++++++++++++++++++-----------
 1 file changed, 40 insertions(+), 17 deletions(-)

diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 9fc83f11f6f..30286a3ff33 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -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 *
-- 
2.49.0

From 92a0fc0397831849f6e1443b010733a69e1d4b1d Mon Sep 17 00:00:00 2001
From: Fujii Masao <fu...@postgresql.org>
Date: Wed, 7 May 2025 16:49:31 +0900
Subject: [PATCH v3] Add guard to prevent recursive memory context logging.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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 <robertmh...@gmail.com>
Author: Fujii Masao <masao.fu...@gmail.com>
Reviewed-by: Atsushi Torikoshi <torikos...@oss.nttdata.com>
Reviewed-by: Robert Haas <robertmh...@gmail.com>
Discussion: 
https://postgr.es/m/ca+tgmozmrv32tbnrrftvf9iwlntgqbhyslvcrhguwzvctph...@mail.gmail.com
Backpatch-through: 14
---
 src/backend/utils/mmgr/mcxt.c | 58 ++++++++++++++++++++++++-----------
 1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 7d28ca706eb..4690d039011 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -174,6 +174,9 @@ MemoryContext CurTransactionContext = NULL;
 MemoryContext PortalContext = NULL;
 dsa_area   *MemoryStatsDsaArea = NULL;
 
+/* Is memory context logging currently in progress? */
+static bool LogMemoryContextInProgress = false;
+
 static void MemoryContextDeleteOnly(MemoryContext context);
 static void MemoryContextCallResetCallbacks(MemoryContext context);
 static void MemoryContextStatsInternal(MemoryContext context, int level,
@@ -1386,26 +1389,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 depth of the hierarchy, as well as 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, 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 depth of the hierarchy, as well as 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, 100, false);
+       }
+       PG_FINALLY();
+       {
+               LogMemoryContextInProgress = false;
+       }
+       PG_END_TRY();
 }
 
 /*
-- 
2.49.0

Reply via email to