From d8c89655eaeb6a34e11571553b4d112a50f1a298 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 v3 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 1fbba9c3a4c..25a6a7ec899 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.54.0

