From bb4c03a887f8ec5395ce37c09279a0786712b06c Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Wed, 29 Apr 2026 10:20:20 -0400
Subject: [PATCH v1_PGMASTER 5/7] Add VM corruption check to verify_heapam()

pg_check_visible() can catch cases were tuples are not visible to all
and the VM is set, but it doesn't specifically check page hints. This
doesn't check, for example, an INSERT failing to clear PD_ALL_VISIBLE.

This also helps users who have access to amcheck but not pg_visibility
to diagnose corruption.

Author: Melanie Plageman <melanieplageman@gmail.com>
---
 contrib/amcheck/verify_heapam.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index 20ff58aa782..0e023871566 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -481,6 +481,7 @@ verify_heapam(PG_FUNCTION_ARGS)
 
 	while ((ctx.buffer = read_stream_next_buffer(stream, NULL)) != InvalidBuffer)
 	{
+		uint8		vmbits;
 		OffsetNumber maxoff;
 		OffsetNumber predecessor[MaxOffsetNumber];
 		OffsetNumber successor[MaxOffsetNumber];
@@ -499,6 +500,21 @@ verify_heapam(PG_FUNCTION_ARGS)
 		ctx.blkno = BufferGetBlockNumber(ctx.buffer);
 		ctx.page = BufferGetPage(ctx.buffer);
 
+		/*
+		 * It is corruption of the page-level PD_ALL_VISIBLE flag is clear and
+		 * the visibility map bits corresponding to this heap page are set.
+		 */
+		vmbits = visibilitymap_get_status(ctx.rel, ctx.blkno, &vmbuffer);
+
+		if (!PageIsAllVisible(ctx.page) &&
+			(vmbits & VISIBILITYMAP_ALL_VISIBLE) != 0)
+		{
+			ctx.offnum = InvalidOffsetNumber;
+			ctx.attnum = -1;
+			report_corruption(&ctx,
+							  psprintf("page is not marked all-visible in page header but visibility map bit is set"));
+		}
+
 		/* Perform tuple checks */
 		maxoff = PageGetMaxOffsetNumber(ctx.page);
 		for (ctx.offnum = FirstOffsetNumber; ctx.offnum <= maxoff;
-- 
2.43.0

