From 0798f565c68ab15f2aff22c58ff29f8d4a2a75fd Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nbossart@postgresql.org>
Date: Mon, 24 Apr 2023 11:29:56 -0700
Subject: [PATCH v3 1/1] Prevent underflow in KeepLogSeg().

When determining the oldest segment that must be kept for
replication slots, KeepLogSeg() might calculate a segment number
ahead of the one for the LSN given to the function.  This causes
underflow in subsequent calculations, which could result in
unexpected behavior when removing or recycling WAL files.  This was
introduced with max_slot_wal_keep_size in c655077.  To fix, cap the
aforementioned value as needed.

Reported-by: Xu Xingwang
Author: Kyotaro Horiguchi
Reviewed-by: Junwang Zhao
Discussion: https://postgr.es/m/17903-4288d439dee856c6%40postgresql.org
Backpatch-through: 13
---
 src/backend/access/transam/xlog.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 63481d826f..66ea6ee204 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7463,6 +7463,15 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 	{
 		XLByteToSeg(keep, segno, wal_segment_size);
 
+		/*
+		 * It's possible for the slot minimum LSN to be greater than the recptr
+		 * given to the function.  This means that the segno we just calculated
+		 * might be greater than currSegno, which would cause some subsequent
+		 * calculations to underflow.  To avoid this, cap segno at currSegNo.
+		 */
+		if (segno > currSegNo)
+			segno = currSegNo;
+
 		/* Cap by max_slot_wal_keep_size ... */
 		if (max_slot_wal_keep_size_mb >= 0)
 		{
-- 
2.25.1

