From 4a170ee9e0ebd7021cb1190fabd5b0cbe2effb8e Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Fri, 4 Apr 2014 14:27:18 +0300 Subject: [PATCH] Add an Assertion that you don't palloc within a critical section. This caught a bunch of cases doing that already, which I just fixed in previous commit. This is the assertion itself. Per Tom Lane's idea. --- src/backend/utils/mmgr/mcxt.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index a7ca44dd86..132b04d7c9 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -24,6 +24,7 @@ #include "postgres.h" +#include "miscadmin.h" #include "utils/memdebug.h" #include "utils/memutils.h" @@ -55,6 +56,19 @@ MemoryContext PortalContext = NULL; static void MemoryContextStatsInternal(MemoryContext context, int level); +/* + * You should not do memory allocations within a critical section, because + * an out-of-memory error will be escalated to a PANIC. To enforce that + * rule, the allocation functions Assert that. + * + * There are a two exceptions: 1) error recovery uses ErrorContext, which + * has some memory set aside so that you don't run out. And 2) checkpointer + * currently just hopes for the best, which is wrong and ought to be fixed, + * but it's a known issue so let's not complain about in the meanwhile. + */ +#define AssertNotInCriticalSection(context) \ + Assert(CritSectionCount == 0 || (context) == ErrorContext || \ + AmCheckpointerProcess()) /***************************************************************************** * EXPORTED ROUTINES * @@ -519,6 +533,8 @@ MemoryContextCreate(NodeTag tag, Size size, MemoryContext node; Size needed = size + strlen(name) + 1; + Assert(CritSectionCount == 0); + /* Get space for node and name */ if (TopMemoryContext != NULL) { @@ -575,6 +591,7 @@ MemoryContextAlloc(MemoryContext context, Size size) void *ret; AssertArg(MemoryContextIsValid(context)); + AssertNotInCriticalSection(context); if (!AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); @@ -600,6 +617,7 @@ MemoryContextAllocZero(MemoryContext context, Size size) void *ret; AssertArg(MemoryContextIsValid(context)); + AssertNotInCriticalSection(context); if (!AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); @@ -627,6 +645,7 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size) void *ret; AssertArg(MemoryContextIsValid(context)); + AssertNotInCriticalSection(context); if (!AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); @@ -648,6 +667,7 @@ palloc(Size size) void *ret; AssertArg(MemoryContextIsValid(CurrentMemoryContext)); + AssertNotInCriticalSection(CurrentMemoryContext); if (!AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); @@ -667,6 +687,7 @@ palloc0(Size size) void *ret; AssertArg(MemoryContextIsValid(CurrentMemoryContext)); + AssertNotInCriticalSection(CurrentMemoryContext); if (!AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); @@ -738,6 +759,7 @@ repalloc(void *pointer, Size size) ((char *) pointer - STANDARDCHUNKHEADERSIZE))->context; AssertArg(MemoryContextIsValid(context)); + AssertNotInCriticalSection(context); /* isReset must be false already */ Assert(!context->isReset); @@ -760,6 +782,7 @@ MemoryContextAllocHuge(MemoryContext context, Size size) void *ret; AssertArg(MemoryContextIsValid(context)); + AssertNotInCriticalSection(context); if (!AllocHugeSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); @@ -801,6 +824,7 @@ repalloc_huge(void *pointer, Size size) ((char *) pointer - STANDARDCHUNKHEADERSIZE))->context; AssertArg(MemoryContextIsValid(context)); + AssertNotInCriticalSection(context); /* isReset must be false already */ Assert(!context->isReset); -- 2.40.0