From ba8adab91935d18982bcf94d4e142beb79dc6be4 Mon Sep 17 00:00:00 2001
From: Palak Chaturvedi <palakchaturvedi2843@gmail.com>
Date: Wed, 5 Aug 2026 14:53:38 +0000
Subject: [PATCH] test_shmem: make resizable shmem tests portable

Fix several portability and synchronization problems in the resizable
shared memory test.

test_shmem_usage() followed every address-adjacent VMA, so any private
mapping that happened to abut the main shared-memory segment could be
added to the shared-memory usage: a glibc arena on Linux 64-bit, the
writable segments of loaded libraries on 32-bit, an AddressSanitizer
shadow region, and so on.  Continue across split VMAs only while they
remain contiguous and retain the target mapping's shared/private flag.
This still accounts for the protected reservation tail and can detect
pages that were not released while shrinking.

Use long for values read with the %ld conversion specifier.  This avoids
a type mismatch on MSVC, where long is 32 bits.  Also read beyond the
current structure size through a volatile pointer, so the compiler
cannot fold the faulting loop to one load.

After crashing a backend, wait for the post-reinitialization ready
message in the server log.  Polling SELECT 1 can succeed before the
postmaster has processed SIGCHLD and reinitialized shared memory.

Skip the resizable shared memory test on Windows.  Windows CI runs with
an Administrator token, which direct postgres -C execution refuses, and
the /proc/self/smaps accounting the test relies on is Linux-only.
---
 .../t/002_resizable_shmem_struct.pl           | 13 ++++-
 src/test/modules/test_shmem/test_shmem.c      | 50 +++++++++----------
 2 files changed, 35 insertions(+), 28 deletions(-)

diff --git a/src/test/modules/test_shmem/t/002_resizable_shmem_struct.pl b/src/test/modules/test_shmem/t/002_resizable_shmem_struct.pl
index 4d2fd3c4282..71e49ce455c 100644
--- a/src/test/modules/test_shmem/t/002_resizable_shmem_struct.pl
+++ b/src/test/modules/test_shmem/t/002_resizable_shmem_struct.pl
@@ -7,6 +7,11 @@ use PostgreSQL::Test::Cluster;
 use PostgreSQL::Test::Utils;
 use Test::More;
 
+if ($windows_os)
+{
+	plan skip_all => 'resizable shared memory tests are not supported on Windows';
+}
+
 # Test resizable shared memory functionality, both when loaded at startup via
 # shared_preload_libraries and when loaded after startup (late allocation).
 
@@ -85,6 +90,10 @@ sub test_fault_beyond_size
 
 	for my $mode ('write', 'read')
 	{
+		# Wait for crash recovery, not just a connection accepted before the
+		# postmaster has processed SIGCHLD for the crashed backend.
+		my $log_offset = -s $node->logfile;
+
 		my ($ret, $stdout, $stderr) = $node->psql('postgres',
 			"SELECT resizable_shmem_access_beyond_size('$mode');");
 		ok($ret != 0, "$prefix: $mode past current size crashes the backend");
@@ -92,8 +101,8 @@ sub test_fault_beyond_size
 			 qr/server closed the connection unexpectedly|connection to server was lost/,
 			 "$prefix: $mode crash reports lost connection");
 
-		$node->poll_query_until('postgres', 'SELECT 1', '1')
-		  or die "server did not come back after $mode crash";
+		$node->wait_for_log(qr/database system is ready to accept connections/,
+							$log_offset);
 	}
 
 	is($node->safe_psql('postgres',
diff --git a/src/test/modules/test_shmem/test_shmem.c b/src/test/modules/test_shmem/test_shmem.c
index 83f8ea9cc3c..2100e33f545 100644
--- a/src/test/modules/test_shmem/test_shmem.c
+++ b/src/test/modules/test_shmem/test_shmem.c
@@ -345,11 +345,8 @@ resizable_shmem_read(PG_FUNCTION_ARGS)
  * backend.
  *
  * The VMA containing our resizable_shmem pointer identifies the start of the
- * main shared-memory segment.
- *
- * mprotect() calls issued when the resizable structure grows and shrinks can
- * split the original mmap into several adjacent VMAs, so we sum the accounting
- * fields across the base VMA and any VMAs contiguous with it.
+ * main shared-memory segment.  mprotect() can split that mapping into adjacent
+ * VMAs, so include adjacent VMAs with the same shared/private flag.
  */
 PG_FUNCTION_INFO_V1(test_shmem_usage);
 Datum
@@ -359,12 +356,13 @@ test_shmem_usage(PG_FUNCTION_ARGS)
 	char		line[256];
 	uintptr_t	target = (uintptr_t) resizable_shmem;
 	bool		in_target_vma = false;
+	bool		target_is_shared = false;
 	bool		use_hugetlb = (huge_pages_status == HUGE_PAGES_ON);
 	unsigned long prev_end = 0;
-	int64		total_rss_kb = 0;
-	int64		total_swap_kb = 0;
-	int64		total_shared_hugetlb_kb = 0;
-	int64		val;
+	long		total_rss_kb = 0;
+	long		total_swap_kb = 0;
+	long		total_shared_hugetlb_kb = 0;
+	long		val;
 	size_t		result;
 
 	f = AllocateFile("/proc/self/smaps", "r");
@@ -377,21 +375,20 @@ test_shmem_usage(PG_FUNCTION_ARGS)
 	{
 		unsigned long start;
 		unsigned long end;
+		char		perms[8];
 
-		if (sscanf(line, "%lx-%lx", &start, &end) == 2)
+		if (sscanf(line, "%lx-%lx %7s", &start, &end, perms) == 3)
 		{
 			if (in_target_vma)
 			{
-				/*
-				 * Continue accumulating only across VMAs that are contiguous
-				 * with the previous one; stop as soon as we hit a gap or a
-				 * different mapping.
-				 */
-				if (start != prev_end)
+				if (start != prev_end || (perms[3] == 's') != target_is_shared)
 					break;
 			}
-			else
-				in_target_vma = (target >= start && target < end);
+			else if (target >= start && target < end)
+			{
+				in_target_vma = true;
+				target_is_shared = (perms[3] == 's');
+			}
 
 			prev_end = end;
 		}
@@ -482,18 +479,19 @@ resizable_shmem_access_beyond_size(PG_FUNCTION_ARGS)
 	ShmemProtectStruct("resizable_shmem");
 #endif
 
-	for (int i = resizable_shmem->num_entries; i < test_max_entries; i++)
+	if (do_write)
 	{
-		if (do_write)
+		for (int i = resizable_shmem->num_entries; i < test_max_entries; i++)
 			resizable_shmem->data[i] = 0xdead;
-		else
-			sink = resizable_shmem->data[i];
+	}
+	else
+	{
+		volatile int32 *volatile_data = resizable_shmem->data;
+
+		for (int i = resizable_shmem->num_entries; i < test_max_entries; i++)
+			sink = volatile_data[i];
 	}
 
-	/*
-	 * Return the last read value so that compiler doesn't optimize away the
-	 * assignment to sink.
-	 */
 	PG_RETURN_INT32(sink);
 }
 
-- 
2.43.0

