From b0e06a6669de625d6226720a8b73ff130ea23ade Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sat, 24 Sep 2022 08:55:20 +1200
Subject: [PATCH 2/2] Fix sharedtuplestore.c corruption.

If the final chunk of an oversized tuple being written out to disk was
exactly 32760 bytes, it would be corrupted due to a fencepost bug.

Bug #17619.  Back-patch to 11 where the code arrived.

While testing that, I (tmunro) noticed that the per-participant page
counter was not initialized to zero as it should have been; that wasn't
a live bug when it was written since DSM memory was originally always
zeroed, but since 14 min_dynamic_shared_memory might be configured and
it supplies non-zeroed memory, so that is also fixed here.

Author: Dmitry Astapov <dastapov@gmail.com>
Discussion: https://postgr.es/m/17619-0de62ceda812b8b5%40postgresql.org
---
 src/backend/utils/sort/sharedtuplestore.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/sort/sharedtuplestore.c b/src/backend/utils/sort/sharedtuplestore.c
index 996cef07d4..464d4c5b7f 100644
--- a/src/backend/utils/sort/sharedtuplestore.c
+++ b/src/backend/utils/sort/sharedtuplestore.c
@@ -158,6 +158,7 @@ sts_initialize(SharedTuplestore *sts, int participants,
 		LWLockInitialize(&sts->participants[i].lock,
 						 LWTRANCHE_SHARED_TUPLESTORE);
 		sts->participants[i].read_page = 0;
+		sts->participants[i].npages = 0;
 		sts->participants[i].writing = false;
 	}
 
@@ -320,7 +321,7 @@ sts_puttuple(SharedTuplestoreAccessor *accessor, void *meta_data,
 
 	/* Do we have space? */
 	size = accessor->sts->meta_data_size + tuple->t_len;
-	if (accessor->write_pointer + size >= accessor->write_end)
+	if (accessor->write_pointer + size > accessor->write_end)
 	{
 		if (accessor->write_chunk == NULL)
 		{
@@ -340,7 +341,7 @@ sts_puttuple(SharedTuplestoreAccessor *accessor, void *meta_data,
 		}
 
 		/* It may still not be enough in the case of a gigantic tuple. */
-		if (accessor->write_pointer + size >= accessor->write_end)
+		if (accessor->write_pointer + size > accessor->write_end)
 		{
 			size_t		written;
 
-- 
2.30.2

