Skip to content

Commit 1bb9e73

Browse files
committed
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
1 parent c79f6df commit 1bb9e73

File tree

1 file changed

+55
-35
lines changed

1 file changed

+55
-35
lines changed

src/backend/utils/mmgr/mcxt.c

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -781,13 +781,21 @@ MemoryContextAlloc(MemoryContext context, Size size)
781781
context->isReset = false;
782782

783783
ret = context->methods->alloc(context, size);
784-
if (ret == NULL)
784+
if (unlikely(ret == NULL))
785785
{
786786
MemoryContextStats(TopMemoryContext);
787+
788+
/*
789+
* Here, and elsewhere in this module, we show the target context's
790+
* "name" but not its "ident" (if any) in user-visible error messages.
791+
* The "ident" string might contain security-sensitive data, such as
792+
* values in SQL commands.
793+
*/
787794
ereport(ERROR,
788795
(errcode(ERRCODE_OUT_OF_MEMORY),
789796
errmsg("out of memory"),
790-
errdetail("Failed on request of size %zu.", size)));
797+
errdetail("Failed on request of size %zu in memory context \"%s\".",
798+
size, context->name)));
791799
}
792800

793801
VALGRIND_MEMPOOL_ALLOC(context, ret, size);
@@ -816,13 +824,14 @@ MemoryContextAllocZero(MemoryContext context, Size size)
816824
context->isReset = false;
817825

818826
ret = context->methods->alloc(context, size);
819-
if (ret == NULL)
827+
if (unlikely(ret == NULL))
820828
{
821829
MemoryContextStats(TopMemoryContext);
822830
ereport(ERROR,
823831
(errcode(ERRCODE_OUT_OF_MEMORY),
824832
errmsg("out of memory"),
825-
errdetail("Failed on request of size %zu.", size)));
833+
errdetail("Failed on request of size %zu in memory context \"%s\".",
834+
size, context->name)));
826835
}
827836

828837
VALGRIND_MEMPOOL_ALLOC(context, ret, size);
@@ -853,13 +862,14 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size)
853862
context->isReset = false;
854863

855864
ret = context->methods->alloc(context, size);
856-
if (ret == NULL)
865+
if (unlikely(ret == NULL))
857866
{
858867
MemoryContextStats(TopMemoryContext);
859868
ereport(ERROR,
860869
(errcode(ERRCODE_OUT_OF_MEMORY),
861870
errmsg("out of memory"),
862-
errdetail("Failed on request of size %zu.", size)));
871+
errdetail("Failed on request of size %zu in memory context \"%s\".",
872+
size, context->name)));
863873
}
864874

865875
VALGRIND_MEMPOOL_ALLOC(context, ret, size);
@@ -888,15 +898,16 @@ MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
888898
context->isReset = false;
889899

890900
ret = context->methods->alloc(context, size);
891-
if (ret == NULL)
901+
if (unlikely(ret == NULL))
892902
{
893903
if ((flags & MCXT_ALLOC_NO_OOM) == 0)
894904
{
895905
MemoryContextStats(TopMemoryContext);
896906
ereport(ERROR,
897907
(errcode(ERRCODE_OUT_OF_MEMORY),
898908
errmsg("out of memory"),
899-
errdetail("Failed on request of size %zu.", size)));
909+
errdetail("Failed on request of size %zu in memory context \"%s\".",
910+
size, context->name)));
900911
}
901912
return NULL;
902913
}
@@ -914,26 +925,28 @@ palloc(Size size)
914925
{
915926
/* duplicates MemoryContextAlloc to avoid increased overhead */
916927
void *ret;
928+
MemoryContext context = CurrentMemoryContext;
917929

918-
AssertArg(MemoryContextIsValid(CurrentMemoryContext));
919-
AssertNotInCriticalSection(CurrentMemoryContext);
930+
AssertArg(MemoryContextIsValid(context));
931+
AssertNotInCriticalSection(context);
920932

921933
if (!AllocSizeIsValid(size))
922934
elog(ERROR, "invalid memory alloc request size %zu", size);
923935

924-
CurrentMemoryContext->isReset = false;
936+
context->isReset = false;
925937

926-
ret = CurrentMemoryContext->methods->alloc(CurrentMemoryContext, size);
927-
if (ret == NULL)
938+
ret = context->methods->alloc(context, size);
939+
if (unlikely(ret == NULL))
928940
{
929941
MemoryContextStats(TopMemoryContext);
930942
ereport(ERROR,
931943
(errcode(ERRCODE_OUT_OF_MEMORY),
932944
errmsg("out of memory"),
933-
errdetail("Failed on request of size %zu.", size)));
945+
errdetail("Failed on request of size %zu in memory context \"%s\".",
946+
size, context->name)));
934947
}
935948

936-
VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size);
949+
VALGRIND_MEMPOOL_ALLOC(context, ret, size);
937950

938951
return ret;
939952
}
@@ -943,26 +956,28 @@ palloc0(Size size)
943956
{
944957
/* duplicates MemoryContextAllocZero to avoid increased overhead */
945958
void *ret;
959+
MemoryContext context = CurrentMemoryContext;
946960

947-
AssertArg(MemoryContextIsValid(CurrentMemoryContext));
948-
AssertNotInCriticalSection(CurrentMemoryContext);
961+
AssertArg(MemoryContextIsValid(context));
962+
AssertNotInCriticalSection(context);
949963

950964
if (!AllocSizeIsValid(size))
951965
elog(ERROR, "invalid memory alloc request size %zu", size);
952966

953-
CurrentMemoryContext->isReset = false;
967+
context->isReset = false;
954968

955-
ret = CurrentMemoryContext->methods->alloc(CurrentMemoryContext, size);
956-
if (ret == NULL)
969+
ret = context->methods->alloc(context, size);
970+
if (unlikely(ret == NULL))
957971
{
958972
MemoryContextStats(TopMemoryContext);
959973
ereport(ERROR,
960974
(errcode(ERRCODE_OUT_OF_MEMORY),
961975
errmsg("out of memory"),
962-
errdetail("Failed on request of size %zu.", size)));
976+
errdetail("Failed on request of size %zu in memory context \"%s\".",
977+
size, context->name)));
963978
}
964979

965-
VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size);
980+
VALGRIND_MEMPOOL_ALLOC(context, ret, size);
966981

967982
MemSetAligned(ret, 0, size);
968983

@@ -974,31 +989,33 @@ palloc_extended(Size size, int flags)
974989
{
975990
/* duplicates MemoryContextAllocExtended to avoid increased overhead */
976991
void *ret;
992+
MemoryContext context = CurrentMemoryContext;
977993

978-
AssertArg(MemoryContextIsValid(CurrentMemoryContext));
979-
AssertNotInCriticalSection(CurrentMemoryContext);
994+
AssertArg(MemoryContextIsValid(context));
995+
AssertNotInCriticalSection(context);
980996

981997
if (((flags & MCXT_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) ||
982998
((flags & MCXT_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size)))
983999
elog(ERROR, "invalid memory alloc request size %zu", size);
9841000

985-
CurrentMemoryContext->isReset = false;
1001+
context->isReset = false;
9861002

987-
ret = CurrentMemoryContext->methods->alloc(CurrentMemoryContext, size);
988-
if (ret == NULL)
1003+
ret = context->methods->alloc(context, size);
1004+
if (unlikely(ret == NULL))
9891005
{
9901006
if ((flags & MCXT_ALLOC_NO_OOM) == 0)
9911007
{
9921008
MemoryContextStats(TopMemoryContext);
9931009
ereport(ERROR,
9941010
(errcode(ERRCODE_OUT_OF_MEMORY),
9951011
errmsg("out of memory"),
996-
errdetail("Failed on request of size %zu.", size)));
1012+
errdetail("Failed on request of size %zu in memory context \"%s\".",
1013+
size, context->name)));
9971014
}
9981015
return NULL;
9991016
}
10001017

1001-
VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size);
1018+
VALGRIND_MEMPOOL_ALLOC(context, ret, size);
10021019

10031020
if ((flags & MCXT_ALLOC_ZERO) != 0)
10041021
MemSetAligned(ret, 0, size);
@@ -1038,13 +1055,14 @@ repalloc(void *pointer, Size size)
10381055
Assert(!context->isReset);
10391056

10401057
ret = context->methods->realloc(context, pointer, size);
1041-
if (ret == NULL)
1058+
if (unlikely(ret == NULL))
10421059
{
10431060
MemoryContextStats(TopMemoryContext);
10441061
ereport(ERROR,
10451062
(errcode(ERRCODE_OUT_OF_MEMORY),
10461063
errmsg("out of memory"),
1047-
errdetail("Failed on request of size %zu.", size)));
1064+
errdetail("Failed on request of size %zu in memory context \"%s\".",
1065+
size, context->name)));
10481066
}
10491067

10501068
VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
@@ -1072,13 +1090,14 @@ MemoryContextAllocHuge(MemoryContext context, Size size)
10721090
context->isReset = false;
10731091

10741092
ret = context->methods->alloc(context, size);
1075-
if (ret == NULL)
1093+
if (unlikely(ret == NULL))
10761094
{
10771095
MemoryContextStats(TopMemoryContext);
10781096
ereport(ERROR,
10791097
(errcode(ERRCODE_OUT_OF_MEMORY),
10801098
errmsg("out of memory"),
1081-
errdetail("Failed on request of size %zu.", size)));
1099+
errdetail("Failed on request of size %zu in memory context \"%s\".",
1100+
size, context->name)));
10821101
}
10831102

10841103
VALGRIND_MEMPOOL_ALLOC(context, ret, size);
@@ -1106,13 +1125,14 @@ repalloc_huge(void *pointer, Size size)
11061125
Assert(!context->isReset);
11071126

11081127
ret = context->methods->realloc(context, pointer, size);
1109-
if (ret == NULL)
1128+
if (unlikely(ret == NULL))
11101129
{
11111130
MemoryContextStats(TopMemoryContext);
11121131
ereport(ERROR,
11131132
(errcode(ERRCODE_OUT_OF_MEMORY),
11141133
errmsg("out of memory"),
1115-
errdetail("Failed on request of size %zu.", size)));
1134+
errdetail("Failed on request of size %zu in memory context \"%s\".",
1135+
size, context->name)));
11161136
}
11171137

11181138
VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);

0 commit comments

Comments
 (0)