public inbox for [email protected]  
help / color / mirror / Atom feed
From: Richard Guo <[email protected]>
To: Alexander Lakhin <[email protected]>
Cc: [email protected]
Subject: Re: BUG #19405: Assertion in eval_windowaggregates() fails due to integer overflow
Date: Sat, 14 Feb 2026 22:44:48 +0900
Message-ID: <CAMbWs4-i9Hk8+fyxoT88ixbrBYuT+2=d9nLqFLi8jfS3k_z68w@mail.gmail.com> (raw)
In-Reply-To: <CAMbWs4_jYG-vjN579aLuE7pf9PaZaPL9KCjPRN0kn3T+obE7hw@mail.gmail.com>
References: <[email protected]>
	<CAMbWs4_GnG0NYnsBZJpHG-BLo28euD6VUx0WhFd4Ur6RaLr5WQ@mail.gmail.com>
	<[email protected]>
	<CAMbWs4_jYG-vjN579aLuE7pf9PaZaPL9KCjPRN0kn3T+obE7hw@mail.gmail.com>

On Sat, Feb 14, 2026 at 8:00 PM Richard Guo <[email protected]> wrote:
> Right, I noticed this one too.  Basically, nodeWindowAgg.c doesn't
> check for overflow when adding startOffsetValue or endOffsetValue.
> Since these values are provided by the user and can be arbitrarily
> large, simple addition does not seem safe.  I think we may need to
> switch to overflow-aware integer operations in all relevant code.

Here is an updated patch to fix all relevant code in nodeWindowAgg.c.

- Richard


Attachments:

  [application/octet-stream] v2-0001-Fix-signed-integer-overflow-in-nodeWindowAgg.c.patch (4.3K, 2-v2-0001-Fix-signed-integer-overflow-in-nodeWindowAgg.c.patch)
  download | inline diff:
From 9589510f4e284ef4ee9f0a95fac572aced43cbe7 Mon Sep 17 00:00:00 2001
From: Richard Guo <[email protected]>
Date: Sat, 14 Feb 2026 18:16:27 +0900
Subject: [PATCH v2] Fix signed integer overflow in nodeWindowAgg.c

---
 src/backend/executor/nodeWindowAgg.c | 54 +++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 5 deletions(-)

diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index d9b64b0f465..dab057df0bd 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -37,6 +37,7 @@
 #include "catalog/objectaccess.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_proc.h"
+#include "common/int.h"
 #include "executor/executor.h"
 #include "executor/nodeWindowAgg.h"
 #include "miscadmin.h"
@@ -1532,12 +1533,17 @@ row_is_in_frame(WindowObject winobj, int64 pos, TupleTableSlot *slot,
 		if (frameOptions & FRAMEOPTION_ROWS)
 		{
 			int64		offset = DatumGetInt64(winstate->endOffsetValue);
+			int64		target_pos;
 
 			/* rows after current row + offset are out of frame */
 			if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
 				offset = -offset;
 
-			if (pos > winstate->currentpos + offset)
+			if (pg_add_s64_overflow(winstate->currentpos, offset, &target_pos))
+			{
+				/* overflow: frame extends to end of partition */
+			}
+			else if (pos > target_pos)
 				return -1;
 		}
 		else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
@@ -1672,7 +1678,16 @@ update_frameheadpos(WindowAggState *winstate)
 			if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
 				offset = -offset;
 
-			winstate->frameheadpos = winstate->currentpos + offset;
+			/*
+			 * If we have an overflow, it means the frame head is beyond the
+			 * range of int64.  Since currentpos >= 0, this can only be a
+			 * positive overflow.  We treat this as being beyond end of
+			 * partition.
+			 */
+			if (pg_add_s64_overflow(winstate->currentpos, offset,
+									&winstate->frameheadpos))
+				winstate->frameheadpos = PG_INT64_MAX;
+
 			/* frame head can't go before first row */
 			if (winstate->frameheadpos < 0)
 				winstate->frameheadpos = 0;
@@ -1789,7 +1804,16 @@ update_frameheadpos(WindowAggState *winstate)
 			if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
 				minheadgroup = winstate->currentgroup - offset;
 			else
-				minheadgroup = winstate->currentgroup + offset;
+			{
+				/*
+				 * If we have an overflow, it means the target group is beyond
+				 * the range of int64.  We treat this as "infinity", which
+				 * ensures the loop below advances to end of partition.
+				 */
+				if (pg_add_s64_overflow(winstate->currentgroup, offset,
+										&minheadgroup))
+					minheadgroup = PG_INT64_MAX;
+			}
 
 			tuplestore_select_read_pointer(winstate->buffer,
 										   winstate->framehead_ptr);
@@ -1926,7 +1950,18 @@ update_frametailpos(WindowAggState *winstate)
 			if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
 				offset = -offset;
 
-			winstate->frametailpos = winstate->currentpos + offset + 1;
+			/*
+			 * If we have an overflow, it means the frame tail is beyond the
+			 * range of int64.  Since currentpos >= 0, this can only be a
+			 * positive overflow.  We treat this as being beyond end of
+			 * partition.
+			 */
+			if (pg_add_s64_overflow(winstate->currentpos, offset,
+									&winstate->frametailpos) ||
+				pg_add_s64_overflow(winstate->frametailpos, 1,
+									&winstate->frametailpos))
+				winstate->frametailpos = PG_INT64_MAX;
+
 			/* smallest allowable value of frametailpos is 0 */
 			if (winstate->frametailpos < 0)
 				winstate->frametailpos = 0;
@@ -2043,7 +2078,16 @@ update_frametailpos(WindowAggState *winstate)
 			if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
 				maxtailgroup = winstate->currentgroup - offset;
 			else
-				maxtailgroup = winstate->currentgroup + offset;
+			{
+				/*
+				 * If we have an overflow, it means the target group is beyond
+				 * the range of int64.  We treat this as "infinity", which
+				 * ensures the loop below advances to end of partition.
+				 */
+				if (pg_add_s64_overflow(winstate->currentgroup, offset,
+										&maxtailgroup))
+					maxtailgroup = PG_INT64_MAX;
+			}
 
 			tuplestore_select_read_pointer(winstate->buffer,
 										   winstate->frametail_ptr);
-- 
2.39.5 (Apple Git-154)



reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected]
  Subject: Re: BUG #19405: Assertion in eval_windowaggregates() fails due to integer overflow
  In-Reply-To: <CAMbWs4-i9Hk8+fyxoT88ixbrBYuT+2=d9nLqFLi8jfS3k_z68w@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox