From 29595315f01071bd505cf5d1c94855474f5facbe Mon Sep 17 00:00:00 2001
From: Lukas Fittl <lukas@fittl.com>
Date: Sat, 21 Mar 2026 11:30:20 -0700
Subject: [PATCH v1 2/2] Stop using TopMemoryContext for resource owner related
 allocations

This removes the unnecessary use of TopMemoryContext for objects that
need to be accessed during resource cleanup, instead allocating them
in the current memory context. This is made possible thanks to the recent
refactoring that delayed freeing portal subsidiary memory until after
ResourceOwnerRelease has completed.

The current memory context is assumed to be a child context of the
currently active portal (if any), like the executor context, or another
kind of local context that survives until after res owner cleanup.

Author: Lukas Fittl <lukas@fittl.com>
Reviewed By:
Discussion:
---
 contrib/pgcrypto/openssl.c             |  6 ++----
 src/backend/jit/llvm/llvmjit.c         | 14 +++++++++-----
 src/backend/storage/ipc/waiteventset.c |  9 +++++++--
 src/common/cryptohash_openssl.c        |  7 +++----
 src/common/hmac_openssl.c              |  7 +++----
 5 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c
index d3c12e7fda3..f01c105dddf 100644
--- a/contrib/pgcrypto/openssl.c
+++ b/contrib/pgcrypto/openssl.c
@@ -176,7 +176,7 @@ px_find_digest(const char *name, PX_MD **res)
 	 * The order is crucial, to make sure we don't leak anything on
 	 * out-of-memory or other error.
 	 */
-	digest = MemoryContextAlloc(TopMemoryContext, sizeof(*digest));
+	digest = palloc(sizeof(*digest));
 
 	ctx = EVP_MD_CTX_create();
 	if (!ctx)
@@ -196,7 +196,6 @@ px_find_digest(const char *name, PX_MD **res)
 	digest->owner = CurrentResourceOwner;
 	ResourceOwnerRememberOSSLDigest(digest->owner, digest);
 
-	/* The PX_MD object is allocated in the current memory context. */
 	h = palloc_object(PX_MD);
 	h->result_size = digest_result_size;
 	h->block_size = digest_block_size;
@@ -794,7 +793,7 @@ px_find_cipher(const char *name, PX_Cipher **res)
 	 * The order is crucial, to make sure we don't leak anything on
 	 * out-of-memory or other error.
 	 */
-	od = MemoryContextAllocZero(TopMemoryContext, sizeof(*od));
+	od = palloc0(sizeof(*od));
 	od->ciph = i->ciph;
 
 	/* Allocate an EVP_CIPHER_CTX object. */
@@ -812,7 +811,6 @@ px_find_cipher(const char *name, PX_Cipher **res)
 	if (i->ciph->cipher_func)
 		od->evp_ciph = i->ciph->cipher_func();
 
-	/* The PX_Cipher is allocated in current memory context */
 	c = palloc_object(PX_Cipher);
 	c->block_size = gen_ossl_block_size;
 	c->key_size = gen_ossl_key_size;
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index 2e8aa4749db..acffd7235bb 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -233,8 +233,7 @@ llvm_create_context(int jitFlags)
 
 	ResourceOwnerEnlarge(CurrentResourceOwner);
 
-	context = MemoryContextAllocZero(TopMemoryContext,
-									 sizeof(LLVMJitContext));
+	context = palloc0(sizeof(LLVMJitContext));
 	context->base.flags = jitFlags;
 
 	/* ensure cleanup */
@@ -760,8 +759,13 @@ llvm_compile_module(LLVMJitContext *context)
 		pfree(filename);
 	}
 
+	/*
+	 * Allocate handle in the same long-lived context as the LLVMJitContext,
+	 * since this can be called during expression evaluation in a short-lived
+	 * per-tuple context.
+	 */
 	handle = (LLVMJitHandle *)
-		MemoryContextAlloc(TopMemoryContext, sizeof(LLVMJitHandle));
+		MemoryContextAlloc(GetMemoryChunkContext(context), sizeof(LLVMJitHandle));
 
 	/*
 	 * Emit the code. Note that this can, depending on the optimization
@@ -805,8 +809,8 @@ llvm_compile_module(LLVMJitContext *context)
 	context->module = NULL;
 	context->compiled = true;
 
-	/* remember emitted code for cleanup and lookups */
-	oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+	/* remember emitted code for cleanup and lookups. */
+	oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(context));
 	context->handles = lappend(context->handles, handle);
 	MemoryContextSwitchTo(oldcontext);
 
diff --git a/src/backend/storage/ipc/waiteventset.c b/src/backend/storage/ipc/waiteventset.c
index 0f228e1e7b8..414e9805eeb 100644
--- a/src/backend/storage/ipc/waiteventset.c
+++ b/src/backend/storage/ipc/waiteventset.c
@@ -389,9 +389,14 @@ CreateWaitEventSet(ResourceOwner resowner, int nevents)
 #endif
 
 	if (resowner != NULL)
+	{
 		ResourceOwnerEnlarge(resowner);
-
-	data = (char *) MemoryContextAllocZero(TopMemoryContext, sz);
+		data = (char *) palloc0(sz);
+	}
+	else
+	{
+		data = (char *) MemoryContextAllocZero(TopMemoryContext, sz);
+	}
 
 	set = (WaitEventSet *) data;
 	data += MAXALIGN(sizeof(WaitEventSet));
diff --git a/src/common/cryptohash_openssl.c b/src/common/cryptohash_openssl.c
index 51b7e040933..2373699aa75 100644
--- a/src/common/cryptohash_openssl.c
+++ b/src/common/cryptohash_openssl.c
@@ -34,12 +34,11 @@
 #endif
 
 /*
- * In the backend, use an allocation in TopMemoryContext to count for
- * resowner cleanup handling.  In the frontend, use malloc to be able
- * to return a failure status back to the caller.
+ * In backends, use an allocation in the current memory context.  In frontend,
+ * use malloc to be able to return a failure status back to the caller.
  */
 #ifndef FRONTEND
-#define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
+#define ALLOC(size) palloc(size)
 #define FREE(ptr) pfree(ptr)
 #else
 #define ALLOC(size) malloc(size)
diff --git a/src/common/hmac_openssl.c b/src/common/hmac_openssl.c
index 7990822854c..97a1b0756dd 100644
--- a/src/common/hmac_openssl.c
+++ b/src/common/hmac_openssl.c
@@ -34,13 +34,12 @@
 #endif
 
 /*
- * In backend, use an allocation in TopMemoryContext to count for resowner
- * cleanup handling if necessary.  In frontend, use malloc to be able to return
- * a failure status back to the caller.
+ * In backends, use an allocation in the current memory context.  In frontend,
+ * use malloc to be able to return a failure status back to the caller.
  */
 #ifndef FRONTEND
 #define USE_RESOWNER_FOR_HMAC
-#define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
+#define ALLOC(size) palloc(size)
 #define FREE(ptr) pfree(ptr)
 #else							/* FRONTEND */
 #define ALLOC(size) malloc(size)
-- 
2.47.1

