Commit 1bb9e731 authored by Tom Lane's avatar Tom Lane

Improve out-of-memory error reports by including memory context name.

Add the target context's name to the errdetail field of "out of memory"
errors in mcxt.c.  Per discussion, this seems likely to be useful to
help narrow down the cause of a reported failure, and it costs little.
Also, now that context names are required to be compile-time constants
in all cases, there's little reason to be concerned about security
issues from exposing these names to users.  (Because of such concerns,
we are *not* including the context "ident" field.)

In passing, add unlikely() markers to the allocation-failed tests,
just to be sure the compiler is on the right page about that.
Also, in palloc and friends, copy CurrentMemoryContext into a local
variable, as that's almost surely cheaper to reference than a global.

Discussion: https://postgr.es/m/1099.1522285628@sss.pgh.pa.us
parent c79f6df7
...@@ -781,13 +781,21 @@ MemoryContextAlloc(MemoryContext context, Size size) ...@@ -781,13 +781,21 @@ MemoryContextAlloc(MemoryContext context, Size size)
context->isReset = false; context->isReset = false;
ret = context->methods->alloc(context, size); ret = context->methods->alloc(context, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
MemoryContextStats(TopMemoryContext); MemoryContextStats(TopMemoryContext);
/*
* Here, and elsewhere in this module, we show the target context's
* "name" but not its "ident" (if any) in user-visible error messages.
* The "ident" string might contain security-sensitive data, such as
* values in SQL commands.
*/
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
VALGRIND_MEMPOOL_ALLOC(context, ret, size); VALGRIND_MEMPOOL_ALLOC(context, ret, size);
...@@ -816,13 +824,14 @@ MemoryContextAllocZero(MemoryContext context, Size size) ...@@ -816,13 +824,14 @@ MemoryContextAllocZero(MemoryContext context, Size size)
context->isReset = false; context->isReset = false;
ret = context->methods->alloc(context, size); ret = context->methods->alloc(context, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
MemoryContextStats(TopMemoryContext); MemoryContextStats(TopMemoryContext);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
VALGRIND_MEMPOOL_ALLOC(context, ret, size); VALGRIND_MEMPOOL_ALLOC(context, ret, size);
...@@ -853,13 +862,14 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size) ...@@ -853,13 +862,14 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size)
context->isReset = false; context->isReset = false;
ret = context->methods->alloc(context, size); ret = context->methods->alloc(context, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
MemoryContextStats(TopMemoryContext); MemoryContextStats(TopMemoryContext);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
VALGRIND_MEMPOOL_ALLOC(context, ret, size); VALGRIND_MEMPOOL_ALLOC(context, ret, size);
...@@ -888,7 +898,7 @@ MemoryContextAllocExtended(MemoryContext context, Size size, int flags) ...@@ -888,7 +898,7 @@ MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
context->isReset = false; context->isReset = false;
ret = context->methods->alloc(context, size); ret = context->methods->alloc(context, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
if ((flags & MCXT_ALLOC_NO_OOM) == 0) if ((flags & MCXT_ALLOC_NO_OOM) == 0)
{ {
...@@ -896,7 +906,8 @@ MemoryContextAllocExtended(MemoryContext context, Size size, int flags) ...@@ -896,7 +906,8 @@ MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
return NULL; return NULL;
} }
...@@ -914,26 +925,28 @@ palloc(Size size) ...@@ -914,26 +925,28 @@ palloc(Size size)
{ {
/* duplicates MemoryContextAlloc to avoid increased overhead */ /* duplicates MemoryContextAlloc to avoid increased overhead */
void *ret; void *ret;
MemoryContext context = CurrentMemoryContext;
AssertArg(MemoryContextIsValid(CurrentMemoryContext)); AssertArg(MemoryContextIsValid(context));
AssertNotInCriticalSection(CurrentMemoryContext); AssertNotInCriticalSection(context);
if (!AllocSizeIsValid(size)) if (!AllocSizeIsValid(size))
elog(ERROR, "invalid memory alloc request size %zu", size); elog(ERROR, "invalid memory alloc request size %zu", size);
CurrentMemoryContext->isReset = false; context->isReset = false;
ret = CurrentMemoryContext->methods->alloc(CurrentMemoryContext, size); ret = context->methods->alloc(context, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
MemoryContextStats(TopMemoryContext); MemoryContextStats(TopMemoryContext);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size); VALGRIND_MEMPOOL_ALLOC(context, ret, size);
return ret; return ret;
} }
...@@ -943,26 +956,28 @@ palloc0(Size size) ...@@ -943,26 +956,28 @@ palloc0(Size size)
{ {
/* duplicates MemoryContextAllocZero to avoid increased overhead */ /* duplicates MemoryContextAllocZero to avoid increased overhead */
void *ret; void *ret;
MemoryContext context = CurrentMemoryContext;
AssertArg(MemoryContextIsValid(CurrentMemoryContext)); AssertArg(MemoryContextIsValid(context));
AssertNotInCriticalSection(CurrentMemoryContext); AssertNotInCriticalSection(context);
if (!AllocSizeIsValid(size)) if (!AllocSizeIsValid(size))
elog(ERROR, "invalid memory alloc request size %zu", size); elog(ERROR, "invalid memory alloc request size %zu", size);
CurrentMemoryContext->isReset = false; context->isReset = false;
ret = CurrentMemoryContext->methods->alloc(CurrentMemoryContext, size); ret = context->methods->alloc(context, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
MemoryContextStats(TopMemoryContext); MemoryContextStats(TopMemoryContext);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size); VALGRIND_MEMPOOL_ALLOC(context, ret, size);
MemSetAligned(ret, 0, size); MemSetAligned(ret, 0, size);
...@@ -974,18 +989,19 @@ palloc_extended(Size size, int flags) ...@@ -974,18 +989,19 @@ palloc_extended(Size size, int flags)
{ {
/* duplicates MemoryContextAllocExtended to avoid increased overhead */ /* duplicates MemoryContextAllocExtended to avoid increased overhead */
void *ret; void *ret;
MemoryContext context = CurrentMemoryContext;
AssertArg(MemoryContextIsValid(CurrentMemoryContext)); AssertArg(MemoryContextIsValid(context));
AssertNotInCriticalSection(CurrentMemoryContext); AssertNotInCriticalSection(context);
if (((flags & MCXT_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) || if (((flags & MCXT_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) ||
((flags & MCXT_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size))) ((flags & MCXT_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size)))
elog(ERROR, "invalid memory alloc request size %zu", size); elog(ERROR, "invalid memory alloc request size %zu", size);
CurrentMemoryContext->isReset = false; context->isReset = false;
ret = CurrentMemoryContext->methods->alloc(CurrentMemoryContext, size); ret = context->methods->alloc(context, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
if ((flags & MCXT_ALLOC_NO_OOM) == 0) if ((flags & MCXT_ALLOC_NO_OOM) == 0)
{ {
...@@ -993,12 +1009,13 @@ palloc_extended(Size size, int flags) ...@@ -993,12 +1009,13 @@ palloc_extended(Size size, int flags)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
return NULL; return NULL;
} }
VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size); VALGRIND_MEMPOOL_ALLOC(context, ret, size);
if ((flags & MCXT_ALLOC_ZERO) != 0) if ((flags & MCXT_ALLOC_ZERO) != 0)
MemSetAligned(ret, 0, size); MemSetAligned(ret, 0, size);
...@@ -1038,13 +1055,14 @@ repalloc(void *pointer, Size size) ...@@ -1038,13 +1055,14 @@ repalloc(void *pointer, Size size)
Assert(!context->isReset); Assert(!context->isReset);
ret = context->methods->realloc(context, pointer, size); ret = context->methods->realloc(context, pointer, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
MemoryContextStats(TopMemoryContext); MemoryContextStats(TopMemoryContext);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size); VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
...@@ -1072,13 +1090,14 @@ MemoryContextAllocHuge(MemoryContext context, Size size) ...@@ -1072,13 +1090,14 @@ MemoryContextAllocHuge(MemoryContext context, Size size)
context->isReset = false; context->isReset = false;
ret = context->methods->alloc(context, size); ret = context->methods->alloc(context, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
MemoryContextStats(TopMemoryContext); MemoryContextStats(TopMemoryContext);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
VALGRIND_MEMPOOL_ALLOC(context, ret, size); VALGRIND_MEMPOOL_ALLOC(context, ret, size);
...@@ -1106,13 +1125,14 @@ repalloc_huge(void *pointer, Size size) ...@@ -1106,13 +1125,14 @@ repalloc_huge(void *pointer, Size size)
Assert(!context->isReset); Assert(!context->isReset);
ret = context->methods->realloc(context, pointer, size); ret = context->methods->realloc(context, pointer, size);
if (ret == NULL) if (unlikely(ret == NULL))
{ {
MemoryContextStats(TopMemoryContext); MemoryContextStats(TopMemoryContext);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"), errmsg("out of memory"),
errdetail("Failed on request of size %zu.", size))); errdetail("Failed on request of size %zu in memory context \"%s\".",
size, context->name)));
} }
VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size); VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment