Fix bug in multixact Oldest*MXactId initialization and access
Yura Sokolov <y.sokolov@postgrespro.ru>
From: Yura Sokolov <y.sokolov@postgrespro.ru>
To: "pgsql-hackers@lists.postgresql.org" <pgsql-hackers@lists.postgresql.org>
Cc: Heikki Linnakangas <hlinnaka@iki.fi>, Andres Freund <andres@anarazel.de>
Date: 2026-02-24T17:35:18Z
Lists: pgsql-hackers
Attachments
- v00-0001-Fix-multixacts-OldestMemberMXactId-and-OldestVis.patch (text/x-patch) patch v0-0001
Good day. multixact.c has bug in initialization and access of OldestMemberMXactId (and partially OldestVisibleMXactId). Size of this arrays is defined as: #define MaxOldestSlot (MaxBackends + max_prepared_xacts) assuming there are only backends and prepared transactions could hold multixacts. This assumption is correct. And in fact there were no bug when this formula were introduced in 2009y [1], since these arrays were indexed but synthetic dummy `dummyBackendId` field of `GlobalTransactionData` struct. But in 2024y [2] field `dummyBackendId` were removed and pgprocno were used instead. But proc structs reserved for two phase commit are placed after auxiliary procs, therefore writes to OldestMemberMXactId[dummy] starts to overwrites slots of OldestVisibleMXactId. Then PostgreSQL 18 increased NUM_AUXILIARY_PROCS due to reserve of workers for AIO. And it is possible to make such test postgresql.conf with so extremely low MaxBackend so writes to OldestMemberMXactId[dummy] overwrites first entry of BufferDescriptors, which are allocated next in shared memory. Patch in attach replaces direct accesses to this arrays with inline functions which include asserts. And changes calculation of MaxOldestSlot to include NUM_AUXILIARY_PROCS. Certainly, it is not clearest patch possible: - may be you will decide to not introduce inline functions, - or will introduce separate inline function for each array, - or will fix slot calculation to remove aux procs from account, - or will revert deletion of dummyBackendId. [1] https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=cd87b6f8a5084c070c3e56b07794be8fea33647d [2] https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=ab355e3a88de745607f6dd4c21f0119b5c68f2ad -- regards Yura Sokolov aka funny-falcon
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Add test for row-locking and multixids with prepared transactions
- 969576dab47b 17.10 landed
- fa3b328e6dc5 18.4 landed
- fe08113aefc9 19 (unreleased) landed
-
Skip prepared_xacts test if max_prepared_transactions < 2
- ffe53037dff7 14.23 landed
- a6b11ac4c42d 15.18 landed
- 65f5c451a3e1 16.14 landed
- 80d1d4ee06fd 17.10 landed
- 201436c19f40 18.4 landed
- 19615a44b3e6 19 (unreleased) landed
-
Fix OldestMemberMXactId and OldestVisibleMXactId array usage
- dcd9c06a4203 17.10 landed
- 0a50ef094382 18.4 landed
- ccae90abdbb6 19 (unreleased) landed
-
Redefine backend ID to be an index into the proc array
- ab355e3a88de 17.0 cited
-
Fix an old bug in multixact and two-phase commit. Prepared transactions can
- cd87b6f8a508 9.0.0 cited