1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-19 17:02:53 +03:00

Add guard to prevent recursive memory context logging.

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 <robertmhaas@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Atsushi Torikoshi <torikoshia@oss.nttdata.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Artem Gavrilov <artem.gavrilov@percona.com>
Discussion: https://postgr.es/m/CA+TgmoZMrv32tbNRrFTvF9iWLnTGqbhYSLVcrHGuwZvCtph0NA@mail.gmail.com
Backpatch-through: 14
This commit is contained in:
Fujii Masao
2025-12-19 12:05:37 +09:00
parent 573e679a26
commit b863d8d87f

View File

@@ -157,6 +157,9 @@ MemoryContext CurTransactionContext = NULL;
/* This is a transient link to the active portal's memory context: */ /* This is a transient link to the active portal's memory context: */
MemoryContext PortalContext = NULL; MemoryContext PortalContext = NULL;
/* Is memory context logging currently in progress? */
static bool LogMemoryContextInProgress = false;
static void MemoryContextDeleteOnly(MemoryContext context); static void MemoryContextDeleteOnly(MemoryContext context);
static void MemoryContextCallResetCallbacks(MemoryContext context); static void MemoryContextCallResetCallbacks(MemoryContext context);
static void MemoryContextStatsInternal(MemoryContext context, int level, static void MemoryContextStatsInternal(MemoryContext context, int level,
@@ -1294,6 +1297,18 @@ ProcessLogMemoryContextInterrupt(void)
{ {
LogMemoryContextPending = false; LogMemoryContextPending = false;
/*
* 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.
*/
if (LogMemoryContextInProgress)
return;
LogMemoryContextInProgress = true;
PG_TRY();
{
/* /*
* Use LOG_SERVER_ONLY to prevent this message from being sent to the * Use LOG_SERVER_ONLY to prevent this message from being sent to the
* connected client. * connected client.
@@ -1304,18 +1319,25 @@ ProcessLogMemoryContextInterrupt(void)
errmsg("logging memory contexts of PID %d", MyProcPid))); errmsg("logging memory contexts of PID %d", MyProcPid)));
/* /*
* When a backend process is consuming huge memory, logging all its memory * When a backend process is consuming huge memory, logging all its
* contexts might overrun available disk space. To prevent this, we limit * memory contexts might overrun available disk space. To prevent
* the depth of the hierarchy, as well as the number of child contexts to * this, we limit the depth of the hierarchy, as well as the number of
* log per parent to 100. * child contexts to log per parent to 100.
* *
* As with MemoryContextStats(), we suppose that practical cases where the * As with MemoryContextStats(), we suppose that practical cases where
* dump gets long will typically be huge numbers of siblings under the * the dump gets long will typically be huge numbers of siblings under
* same parent context; while the additional debugging value from seeing * the same parent context; while the additional debugging value from
* details about individual siblings beyond 100 will not be large. * seeing details about individual siblings beyond 100 will not be
* large.
*/ */
MemoryContextStatsDetail(TopMemoryContext, 100, 100, false); MemoryContextStatsDetail(TopMemoryContext, 100, 100, false);
} }
PG_FINALLY();
{
LogMemoryContextInProgress = false;
}
PG_END_TRY();
}
void * void *
palloc(Size size) palloc(Size size)