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,
519533 MemoryContext node ;
520534 Size needed = size + strlen (name ) + 1 ;
521535
536+ Assert (CritSectionCount == 0 );
537+
522538 /* Get space for node and name */
523539 if (TopMemoryContext != NULL )
524540 {
@@ -575,6 +591,7 @@ MemoryContextAlloc(MemoryContext context, Size size)
575591 void * ret ;
576592
577593 AssertArg (MemoryContextIsValid (context ));
594+ AssertNotInCriticalSection (context );
578595
579596 if (!AllocSizeIsValid (size ))
580597 elog (ERROR , "invalid memory alloc request size %zu" , size );
@@ -600,6 +617,7 @@ MemoryContextAllocZero(MemoryContext context, Size size)
600617 void * ret ;
601618
602619 AssertArg (MemoryContextIsValid (context ));
620+ AssertNotInCriticalSection (context );
603621
604622 if (!AllocSizeIsValid (size ))
605623 elog (ERROR , "invalid memory alloc request size %zu" , size );
@@ -627,6 +645,7 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size)
627645 void * ret ;
628646
629647 AssertArg (MemoryContextIsValid (context ));
648+ AssertNotInCriticalSection (context );
630649
631650 if (!AllocSizeIsValid (size ))
632651 elog (ERROR , "invalid memory alloc request size %zu" , size );
@@ -648,6 +667,7 @@ palloc(Size size)
648667 void * ret ;
649668
650669 AssertArg (MemoryContextIsValid (CurrentMemoryContext ));
670+ AssertNotInCriticalSection (CurrentMemoryContext );
651671
652672 if (!AllocSizeIsValid (size ))
653673 elog (ERROR , "invalid memory alloc request size %zu" , size );
@@ -667,6 +687,7 @@ palloc0(Size size)
667687 void * ret ;
668688
669689 AssertArg (MemoryContextIsValid (CurrentMemoryContext ));
690+ AssertNotInCriticalSection (CurrentMemoryContext );
670691
671692 if (!AllocSizeIsValid (size ))
672693 elog (ERROR , "invalid memory alloc request size %zu" , size );
@@ -738,6 +759,7 @@ repalloc(void *pointer, Size size)
738759 ((char * ) pointer - STANDARDCHUNKHEADERSIZE ))-> context ;
739760
740761 AssertArg (MemoryContextIsValid (context ));
762+ AssertNotInCriticalSection (context );
741763
742764 /* isReset must be false already */
743765 Assert (!context -> isReset );
@@ -760,6 +782,7 @@ MemoryContextAllocHuge(MemoryContext context, Size size)
760782 void * ret ;
761783
762784 AssertArg (MemoryContextIsValid (context ));
785+ AssertNotInCriticalSection (context );
763786
764787 if (!AllocHugeSizeIsValid (size ))
765788 elog (ERROR , "invalid memory alloc request size %zu" , size );
@@ -801,6 +824,7 @@ repalloc_huge(void *pointer, Size size)
801824 ((char * ) pointer - STANDARDCHUNKHEADERSIZE ))-> context ;
802825
803826 AssertArg (MemoryContextIsValid (context ));
827+ AssertNotInCriticalSection (context );
804828
805829 /* isReset must be false already */
806830 Assert (!context -> isReset );
0 commit comments