2424
2525#include "postgres.h"
2626
27+ #include "miscadmin.h"
2728#include "utils/memdebug.h"
2829#include "utils/memutils.h"
2930
@@ -55,6 +56,19 @@ MemoryContext PortalContext = NULL;
5556
5657static void MemoryContextStatsInternal (MemoryContext context ,int level );
5758
59+ /*
60+ * You should not do memory allocations within a critical section, because
61+ * an out-of-memory error will be escalated to a PANIC. To enforce that
62+ * rule, the allocation functions Assert that.
63+ *
64+ * There are a two exceptions: 1) error recovery uses ErrorContext, which
65+ * has some memory set aside so that you don't run out. And 2) checkpointer
66+ * currently just hopes for the best, which is wrong and ought to be fixed,
67+ * but it's a known issue so let's not complain about in the meanwhile.
68+ */
69+ #define AssertNotInCriticalSection (context ) \
70+ Assert(CritSectionCount == 0 || (context) == ErrorContext || \
71+ AmCheckpointerProcess())
5872
5973/*****************************************************************************
6074 * EXPORTED ROUTINES *
@@ -519,6 +533,8 @@ MemoryContextCreate(NodeTag tag, Size size,
519533MemoryContext node ;
520534Size needed = size + strlen (name )+ 1 ;
521535
536+ Assert (CritSectionCount == 0 );
537+
522538/* Get space for node and name */
523539if (TopMemoryContext != NULL )
524540{
@@ -575,6 +591,7 @@ MemoryContextAlloc(MemoryContext context, Size size)
575591void * ret ;
576592
577593AssertArg (MemoryContextIsValid (context ));
594+ AssertNotInCriticalSection (context );
578595
579596if (!AllocSizeIsValid (size ))
580597elog (ERROR ,"invalid memory alloc request size %zu" ,size );
@@ -600,6 +617,7 @@ MemoryContextAllocZero(MemoryContext context, Size size)
600617void * ret ;
601618
602619AssertArg (MemoryContextIsValid (context ));
620+ AssertNotInCriticalSection (context );
603621
604622if (!AllocSizeIsValid (size ))
605623elog (ERROR ,"invalid memory alloc request size %zu" ,size );
@@ -627,6 +645,7 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size)
627645void * ret ;
628646
629647AssertArg (MemoryContextIsValid (context ));
648+ AssertNotInCriticalSection (context );
630649
631650if (!AllocSizeIsValid (size ))
632651elog (ERROR ,"invalid memory alloc request size %zu" ,size );
@@ -648,6 +667,7 @@ palloc(Size size)
648667void * ret ;
649668
650669AssertArg (MemoryContextIsValid (CurrentMemoryContext ));
670+ AssertNotInCriticalSection (CurrentMemoryContext );
651671
652672if (!AllocSizeIsValid (size ))
653673elog (ERROR ,"invalid memory alloc request size %zu" ,size );
@@ -667,6 +687,7 @@ palloc0(Size size)
667687void * ret ;
668688
669689AssertArg (MemoryContextIsValid (CurrentMemoryContext ));
690+ AssertNotInCriticalSection (CurrentMemoryContext );
670691
671692if (!AllocSizeIsValid (size ))
672693elog (ERROR ,"invalid memory alloc request size %zu" ,size );
@@ -738,6 +759,7 @@ repalloc(void *pointer, Size size)
738759 ((char * )pointer - STANDARDCHUNKHEADERSIZE ))-> context ;
739760
740761AssertArg (MemoryContextIsValid (context ));
762+ AssertNotInCriticalSection (context );
741763
742764/* isReset must be false already */
743765Assert (!context -> isReset );
@@ -760,6 +782,7 @@ MemoryContextAllocHuge(MemoryContext context, Size size)
760782void * ret ;
761783
762784AssertArg (MemoryContextIsValid (context ));
785+ AssertNotInCriticalSection (context );
763786
764787if (!AllocHugeSizeIsValid (size ))
765788elog (ERROR ,"invalid memory alloc request size %zu" ,size );
@@ -801,6 +824,7 @@ repalloc_huge(void *pointer, Size size)
801824 ((char * )pointer - STANDARDCHUNKHEADERSIZE ))-> context ;
802825
803826AssertArg (MemoryContextIsValid (context ));
827+ AssertNotInCriticalSection (context );
804828
805829/* isReset must be false already */
806830Assert (!context -> isReset );