From 26d4fda37ea10d146e9d35fca70f817a0bfe300c Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Wed, 27 Mar 2019 21:16:50 +1300 Subject: [PATCH] Fix off-by-one error in txid_status(). The transaction ID returned by GetNextXidAndEpoch() is in the future, so we can't attempt to access its status or we might try to read a CLOG page that doesn't exist. The > vs >= confusion probably stemmed from the choice of a variable name containing the word "last" instead of "next", so fix that too. Back-patch to 10 where the function arrived. Author: Thomas Munro Discussion: https://postgr.es/m/CA%2BhUKG%2Buua_BV5cyfsioKVN2d61Lukg28ECsWTXKvh%3DBtN2DPA%40mail.gmail.com --- src/backend/utils/adt/txid.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c index 7974c0bd3d..cef184e960 100644 --- a/src/backend/utils/adt/txid.c +++ b/src/backend/utils/adt/txid.c @@ -113,9 +113,9 @@ TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid) uint32 xid_epoch = (uint32) (xid_with_epoch >> 32); TransactionId xid = (TransactionId) xid_with_epoch; uint32 now_epoch; - TransactionId now_epoch_last_xid; + TransactionId now_epoch_next_xid; - GetNextXidAndEpoch(&now_epoch_last_xid, &now_epoch); + GetNextXidAndEpoch(&now_epoch_next_xid, &now_epoch); if (extracted_xid != NULL) *extracted_xid = xid; @@ -129,7 +129,7 @@ TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid) /* If the transaction ID is in the future, throw an error. */ if (xid_epoch > now_epoch - || (xid_epoch == now_epoch && xid > now_epoch_last_xid)) + || (xid_epoch == now_epoch && xid >= now_epoch_next_xid)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transaction ID %s is in the future", @@ -151,7 +151,7 @@ TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid) * CLOG entry is guaranteed to still exist. */ if (xid_epoch + 1 < now_epoch - || (xid_epoch + 1 == now_epoch && xid < now_epoch_last_xid) + || (xid_epoch + 1 == now_epoch && xid < now_epoch_next_xid) || TransactionIdPrecedes(xid, ShmemVariableCache->oldestClogXid)) return false;