Hi,

While hacking on something I happened to notice a couple asserts on
ParallelWorkerNumber when collecting shared instrumentation:

  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);

This is not quire right, because num_workers is used to size arrays
indexed by ParallelWorkerNumber. And the comment in parallel.c also
claims (ParallelWorkerNumber < num_workers).

So AFAICS the assert(s) should be

  Assert(ParallelWorkerNumber < node->shared_info->num_workers);

I don't think we had issues with this not catching a bug. But it may be
a bit misleading, so worth fixing and (probably) backpatching.


regards

-- 
Tomas Vondra
From 71e6e1af59fe174d63ad08a31f1fdc96b4abf067 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <[email protected]>
Date: Thu, 12 Mar 2026 19:25:50 +0100
Subject: [PATCH] Tighten asserts on ParallelWorkerNumber

The comment about ParallelWorkerNumbr in parallel.c says:

  In parallel workers, it will be set to a value >= 0 and < the number
  of workers before any user code is invoked; each parallel worker will
  get a different parallel worker number.

However asserts in various places collecting instrumentation allowed
(ParallelWorkerNumber == num_workers). That would be a bug, as the value
is used as index into an array with num_workers entries.

Fixed by adjusting the asserts accordingly.
---
 src/backend/executor/nodeAgg.c             | 2 +-
 src/backend/executor/nodeBitmapHeapscan.c  | 2 +-
 src/backend/executor/nodeBitmapIndexscan.c | 2 +-
 src/backend/executor/nodeIncrementalSort.c | 2 +-
 src/backend/executor/nodeIndexonlyscan.c   | 2 +-
 src/backend/executor/nodeIndexscan.c       | 2 +-
 src/backend/executor/nodeMemoize.c         | 2 +-
 src/backend/executor/nodeSort.c            | 2 +-
 8 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 7d487a165fa..fd5b5104c56 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -4407,7 +4407,7 @@ ExecEndAgg(AggState *node)
 	{
 		AggregateInstrumentation *si;
 
-		Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
+		Assert(ParallelWorkerNumber < node->shared_info->num_workers);
 		si = &node->shared_info->sinstrument[ParallelWorkerNumber];
 		si->hash_batches_used = node->hash_batches_used;
 		si->hash_disk_used = node->hash_disk_used;
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index e0b6df64767..74eac93284e 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -276,7 +276,7 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
 	{
 		BitmapHeapScanInstrumentation *si;
 
-		Assert(ParallelWorkerNumber <= node->sinstrument->num_workers);
+		Assert(ParallelWorkerNumber < node->sinstrument->num_workers);
 		si = &node->sinstrument->sinstrument[ParallelWorkerNumber];
 
 		/*
diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c
index 058a59ef5e7..e08b1c43ace 100644
--- a/src/backend/executor/nodeBitmapIndexscan.c
+++ b/src/backend/executor/nodeBitmapIndexscan.c
@@ -192,7 +192,7 @@ ExecEndBitmapIndexScan(BitmapIndexScanState *node)
 	{
 		IndexScanInstrumentation *winstrument;
 
-		Assert(ParallelWorkerNumber <= node->biss_SharedInfo->num_workers);
+		Assert(ParallelWorkerNumber < node->biss_SharedInfo->num_workers);
 		winstrument = &node->biss_SharedInfo->winstrument[ParallelWorkerNumber];
 
 		/*
diff --git a/src/backend/executor/nodeIncrementalSort.c b/src/backend/executor/nodeIncrementalSort.c
index 3e6a79ea0c0..1d831049b65 100644
--- a/src/backend/executor/nodeIncrementalSort.c
+++ b/src/backend/executor/nodeIncrementalSort.c
@@ -102,7 +102,7 @@
 			if ((node)->shared_info && (node)->am_worker) \
 			{ \
 				Assert(IsParallelWorker()); \
-				Assert(ParallelWorkerNumber <= (node)->shared_info->num_workers); \
+				Assert(ParallelWorkerNumber < (node)->shared_info->num_workers); \
 				instrumentSortedGroup(&(node)->shared_info->sinfo[ParallelWorkerNumber].groupName##GroupInfo, \
 									  (node)->groupName##_state); \
 			} \
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index c2d09374517..9e8ea8ddf22 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -423,7 +423,7 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
 	{
 		IndexScanInstrumentation *winstrument;
 
-		Assert(ParallelWorkerNumber <= node->ioss_SharedInfo->num_workers);
+		Assert(ParallelWorkerNumber < node->ioss_SharedInfo->num_workers);
 		winstrument = &node->ioss_SharedInfo->winstrument[ParallelWorkerNumber];
 
 		/*
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index a616abff04c..4513b1f7a90 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -802,7 +802,7 @@ ExecEndIndexScan(IndexScanState *node)
 	{
 		IndexScanInstrumentation *winstrument;
 
-		Assert(ParallelWorkerNumber <= node->iss_SharedInfo->num_workers);
+		Assert(ParallelWorkerNumber < node->iss_SharedInfo->num_workers);
 		winstrument = &node->iss_SharedInfo->winstrument[ParallelWorkerNumber];
 
 		/*
diff --git a/src/backend/executor/nodeMemoize.c b/src/backend/executor/nodeMemoize.c
index edf52efd4c3..fdca97d7426 100644
--- a/src/backend/executor/nodeMemoize.c
+++ b/src/backend/executor/nodeMemoize.c
@@ -1123,7 +1123,7 @@ ExecEndMemoize(MemoizeState *node)
 		if (node->stats.mem_peak == 0)
 			node->stats.mem_peak = node->mem_used;
 
-		Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
+		Assert(ParallelWorkerNumber < node->shared_info->num_workers);
 		si = &node->shared_info->sinstrument[ParallelWorkerNumber];
 		memcpy(si, &node->stats, sizeof(MemoizeInstrumentation));
 	}
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index fd3a48ba546..e02313f7813 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -175,7 +175,7 @@ ExecSort(PlanState *pstate)
 			TuplesortInstrumentation *si;
 
 			Assert(IsParallelWorker());
-			Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
+			Assert(ParallelWorkerNumber < node->shared_info->num_workers);
 			si = &node->shared_info->sinstrument[ParallelWorkerNumber];
 			tuplesort_get_stats(tuplesortstate, si);
 		}
-- 
2.53.0

Reply via email to