From: Heikki Linnakangas Date: Thu, 11 Dec 2025 09:18:14 +0000 (+0200) Subject: Add runtime checks for bogus multixact offsets X-Git-Url: http://waps.l3s.uni-hannover.de/gitweb/static/sequence.php?a=commitdiff_plain;p=postgresql.git Add runtime checks for bogus multixact offsets It's not far-fetched that we'd try to read a multixid with an invalid offset in case of bugs or corruption. Or if you call pg_get_multixact_members() after a crash that left behind invalid but unused multixids. Better to get a somewhat descriptive error message if that happens. Discussion: https://www.postgresql.org/message-id/3624730d-6dae-42bf-9458-76c4c965fb27@iki.fi --- diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 3a95f9ca1f8..8ba2f4529dc 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -1153,6 +1153,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, int slotno; MultiXactOffset *offptr; MultiXactOffset offset; + MultiXactOffset nextMXOffset; int length; MultiXactId oldestMXact; MultiXactId nextMXact; @@ -1244,12 +1245,14 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, offptr += entryno; offset = *offptr; - Assert(offset != 0); + if (offset == 0) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("MultiXact %u has invalid offset", multi))); /* read next multi's offset */ { MultiXactId tmpMXact; - MultiXactOffset nextMXOffset; /* handle wraparound if needed */ tmpMXact = multi + 1; @@ -1283,21 +1286,27 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno]; offptr += entryno; nextMXOffset = *offptr; - - if (nextMXOffset == 0) - ereport(ERROR, - (errcode(ERRCODE_DATA_CORRUPTED), - errmsg("MultiXact %u has invalid next offset", - multi))); - - length = nextMXOffset - offset; } LWLockRelease(lock); lock = NULL; - /* A multixid with zero members should not happen */ - Assert(length > 0); + /* Sanity check the next offset */ + if (nextMXOffset == 0) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("MultiXact %u has invalid next offset", multi))); + if (nextMXOffset < offset) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("MultiXact %u has offset (%" PRIu64 ") greater than its next offset (%" PRIu64 ")", + multi, offset, nextMXOffset))); + if (nextMXOffset - offset > INT32_MAX) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("MultiXact %u has too many members (%" PRIu64 ")", + multi, nextMXOffset - offset))); + length = nextMXOffset - offset; /* read the members */ ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));