From 7a35a1e8816aff273809180143a3623358105d82 Mon Sep 17 00:00:00 2001
From: Greg Burd <greg@burd.me>
Date: Mon, 14 Sep 2026 13:01:10 -0400
Subject: [PATCH v4 3/3] Reject an invalid TID in table_tuple_lock()

An invalid TID reaching heap_lock_tuple() is handed to ReadBuffer() as
InvalidBlockNumber, which is P_NEW, so the relation is extended by a
block before the lock attempt fails.  The uninitialized block is left
behind and later breaks sequential scans with "invalid page in block".
A caller that gets this far with an invalid TID has a bug, and nothing
good comes of letting it reach the AM, so check at the table AM
boundary where every AM is covered.

In an assert-enabled build the ItemPointerGetBlockNumber() inside
heap_lock_tuple() already trips on this, so the new check mainly buys a
clean error instead of relation extension in a production build.

Suggested-by: Andres Freund
---
 src/include/access/tableam.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index ebec31a22e4..e362878387d 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -1652,6 +1652,19 @@ table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot,
 				 LockWaitPolicy wait_policy, uint8 flags,
 				 TM_FailureData *tmfd)
 {
+	/*
+	 * Reject an invalid TID here rather than letting it reach the AM.  For
+	 * heap that meant handing InvalidBlockNumber to ReadBuffer(), which is
+	 * P_NEW and therefore extends the relation, leaving an uninitialized
+	 * block behind that later breaks sequential scans.  A caller that gets
+	 * this far with an invalid TID has a bug, so fail cleanly instead.
+	 */
+	if (unlikely(!ItemPointerIsValid(tid)))
+		elog(ERROR, "cannot lock tuple with invalid TID (%u,%u) in relation \"%s\"",
+			 ItemPointerGetBlockNumberNoCheck(tid),
+			 ItemPointerGetOffsetNumberNoCheck(tid),
+			 RelationGetRelationName(rel));
+
 	return rel->rd_tableam->tuple_lock(rel, tid, snapshot, slot,
 									   cid, mode, wait_policy,
 									   flags, tmfd);
-- 
2.50.1

