mirror of
https://github.com/postgres/postgres.git
synced 2025-12-13 14:22:43 +03:00
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
This commit is contained in:
@@ -1153,6 +1153,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
|
|||||||
int slotno;
|
int slotno;
|
||||||
MultiXactOffset *offptr;
|
MultiXactOffset *offptr;
|
||||||
MultiXactOffset offset;
|
MultiXactOffset offset;
|
||||||
|
MultiXactOffset nextMXOffset;
|
||||||
int length;
|
int length;
|
||||||
MultiXactId oldestMXact;
|
MultiXactId oldestMXact;
|
||||||
MultiXactId nextMXact;
|
MultiXactId nextMXact;
|
||||||
@@ -1244,12 +1245,14 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
|
|||||||
offptr += entryno;
|
offptr += entryno;
|
||||||
offset = *offptr;
|
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 */
|
/* read next multi's offset */
|
||||||
{
|
{
|
||||||
MultiXactId tmpMXact;
|
MultiXactId tmpMXact;
|
||||||
MultiXactOffset nextMXOffset;
|
|
||||||
|
|
||||||
/* handle wraparound if needed */
|
/* handle wraparound if needed */
|
||||||
tmpMXact = multi + 1;
|
tmpMXact = multi + 1;
|
||||||
@@ -1283,21 +1286,27 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
|
|||||||
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
|
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
|
||||||
offptr += entryno;
|
offptr += entryno;
|
||||||
nextMXOffset = *offptr;
|
nextMXOffset = *offptr;
|
||||||
|
|
||||||
if (nextMXOffset == 0)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_DATA_CORRUPTED),
|
|
||||||
errmsg("MultiXact %u has invalid next offset",
|
|
||||||
multi)));
|
|
||||||
|
|
||||||
length = nextMXOffset - offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LWLockRelease(lock);
|
LWLockRelease(lock);
|
||||||
lock = NULL;
|
lock = NULL;
|
||||||
|
|
||||||
/* A multixid with zero members should not happen */
|
/* Sanity check the next offset */
|
||||||
Assert(length > 0);
|
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 */
|
/* read the members */
|
||||||
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
|
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
|
||||||
|
|||||||
Reference in New Issue
Block a user