From c8b2073d8f8e5e3be5263c4df6a2822ff2ae499a Mon Sep 17 00:00:00 2001 From: ChangAo Chen Date: Thu, 20 Aug 2026 14:06:54 +0800 Subject: [PATCH v3] Fix overflow in WAIT FOR LSN timeout handling. WAIT FOR accepted timeout values up to int64, but WaitForLSN converted milliseconds to microseconds without overflow checking. A sufficiently large value could therefore produce an invalid deadline and an immediate false timeout. Limit the timeout to the int range and use int consistently throughout the WaitForLSN interface, matching PostgreSQL's other timeout facilities. --- src/backend/access/transam/xlogwait.c | 2 +- src/backend/commands/repack_worker.c | 4 ++-- src/backend/commands/wait.c | 6 +++--- src/include/access/xlogwait.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/backend/access/transam/xlogwait.c b/src/backend/access/transam/xlogwait.c index eee90e7f626..2ea8c24a74f 100644 --- a/src/backend/access/transam/xlogwait.c +++ b/src/backend/access/transam/xlogwait.c @@ -437,7 +437,7 @@ WaitLSNTypeRequiresRecovery(WaitLSNType t) * or replica got promoted before the target LSN reached. */ WaitLSNResult -WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, int64 timeout) +WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, int timeout) { XLogRecPtr currentLSN; WaitLSNProcInfo *procInfo; diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c index af7e2a94764..a9870d9c8f2 100644 --- a/src/backend/commands/repack_worker.c +++ b/src/backend/commands/repack_worker.c @@ -447,7 +447,7 @@ decode_concurrent_changes(LogicalDecodingContext *ctx, if (record == NULL) { - int64 timeout = 0; + int timeout = 0; WaitLSNResult res; /* @@ -466,7 +466,7 @@ decode_concurrent_changes(LogicalDecodingContext *ctx, * should already have been flushed to disk. */ if (!XLogRecPtrIsValid(lsn_upto)) - timeout = 100L; + timeout = 100; res = WaitForLSN(WAIT_LSN_TYPE_PRIMARY_FLUSH, ctx->reader->EndRecPtr + 1, timeout); diff --git a/src/backend/commands/wait.c b/src/backend/commands/wait.c index 40a6ffde16b..d401d400e97 100644 --- a/src/backend/commands/wait.c +++ b/src/backend/commands/wait.c @@ -35,7 +35,7 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, bool isTopLevel, DestReceiver *dest) { XLogRecPtr lsn; - int64 timeout = 0; + int timeout = 0; WaitLSNResult waitLSNResult; WaitLSNType lsnType = WAIT_LSN_TYPE_STANDBY_REPLAY; /* default */ bool throw = true; @@ -116,7 +116,7 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, bool isTopLevel, dval = rint(dval); /* Range check */ - if (unlikely(isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))) + if (unlikely(isnan(dval) || !FLOAT8_FITS_IN_INT32(dval))) ereport(ERROR, errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("timeout value is out of range")); @@ -126,7 +126,7 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, bool isTopLevel, errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timeout cannot be negative")); - timeout = (int64) dval; + timeout = (int) dval; } else if (strcmp(defel->defname, "no_throw") == 0) { diff --git a/src/include/access/xlogwait.h b/src/include/access/xlogwait.h index 07157f220ea..2bf0263e9e2 100644 --- a/src/include/access/xlogwait.h +++ b/src/include/access/xlogwait.h @@ -104,6 +104,6 @@ extern XLogRecPtr GetCurrentLSNForWaitType(WaitLSNType lsnType); extern void WaitLSNWakeup(WaitLSNType lsnType, XLogRecPtr currentLSN); extern void WaitLSNCleanup(void); extern WaitLSNResult WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, - int64 timeout); + int timeout); #endif /* XLOG_WAIT_H */ -- 2.34.1