From 753e07739b4e0e906e87f24e15e2c217de28f17d Mon Sep 17 00:00:00 2001
From: Andreas Karlsson <andreas.karlsson@percona.com>
Date: Thu, 4 Jun 2026 13:54:22 +0200
Subject: [PATCH v2 2/3] valgrind: Add NOACCESS sentinels to allocations in
 main shared memory

When built with USE_VALGRIND we have the ShmemAllocator add a NOACCESS
sentinel after every allocation in shared memory. On EXEC_BACKEND builds
we set up the sentinels when the backend attaches to shared memory, but
then only for things in ShmemIndex and not for allocations done directly
via legacy functions like ShmemAlloc().

Author: Andreas Karlsson <andreas@proxel.se>
---
 src/backend/storage/ipc/shmem.c | 38 ++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index f1f7cd3a4ff..a7077be097b 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -142,6 +142,7 @@
 #include "storage/shmem_internal.h"
 #include "storage/spin.h"
 #include "utils/builtins.h"
+#include "utils/memdebug.h"
 #include "utils/tuplestore.h"
 
 /*
@@ -279,6 +280,13 @@ static bool AttachShmemIndexEntry(ShmemRequest *request, bool missing_ok);
 
 Datum		pg_numa_available(PG_FUNCTION_ARGS);
 
+/* With valgrind, we want to add a couple NOACCESS bytes */
+#ifdef USE_VALGRIND
+#define NOACCESS_BYTES 32
+#else
+#define NOACCESS_BYTES 0
+#endif
+
 /*
  *	ShmemRequestStruct() --- request a named shared memory area
  *
@@ -405,9 +413,14 @@ ShmemGetRequestedSize(void)
 		/* pad the start address for alignment like ShmemAllocRaw() does */
 		if (alignment < PG_CACHE_LINE_SIZE)
 			alignment = PG_CACHE_LINE_SIZE;
+
 		size = TYPEALIGN(alignment, size);
 
 		size = add_size(size, request->options->size);
+
+#if USE_VALGRIND
+		size = add_size(size, NOACCESS_BYTES);
+#endif
 	}
 
 	return size;
@@ -492,6 +505,26 @@ ShmemAttachRequested(void)
 			callbacks->attach_fn(callbacks->opaque_arg);
 	}
 
+#ifdef USE_VALGRIND
+	{
+		HASH_SEQ_STATUS hstat;
+		ShmemIndexEnt *ent;
+
+		hash_seq_init(&hstat, ShmemIndex);
+
+		/*
+		 * When compiled with EXEC_BACKEND we need to recreate all NOACCESS
+		 * regions in each backend, but we can only recreate those with index
+		 * entries and not any of the regions for memory allocated directly with
+		 * ShmemAlloc().
+		 */
+		while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
+		{
+			VALGRIND_MAKE_MEM_NOACCESS(ent->location + ent->size, NOACCESS_BYTES);
+		}
+	}
+#endif
+
 	LWLockRelease(ShmemIndexLock);
 
 	shmem_request_state = SRS_DONE;
@@ -822,11 +855,14 @@ ShmemAllocRaw(Size size, Size alignment, Size *allocated_size)
 	rawStart = ShmemAllocator->free_offset;
 	newStart = TYPEALIGN(alignment, rawStart);
 
-	newFree = newStart + size;
+	newFree = newStart + size + NOACCESS_BYTES;
 	if (newFree <= ShmemSegHdr->totalsize)
 	{
 		newSpace = (char *) ShmemBase + newStart;
 		ShmemAllocator->free_offset = newFree;
+
+		/* Make the bytes at the end no-access */
+		VALGRIND_MAKE_MEM_NOACCESS(newSpace + size, NOACCESS_BYTES);
 	}
 	else
 		newSpace = NULL;
-- 
2.43.0

