Re: [PATCH]Fix pg_xact corruption from subtransaction abort after subcommit

From: "Jonathan Gonzalez V(dot)" <jonathan(dot)abdiel(at)gmail(dot)com>
To: Bryan Green <dbryan(dot)green(at)gmail(dot)com>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: [PATCH]Fix pg_xact corruption from subtransaction abort after subcommit
Date: 2026-08-12 13:36:01
Message-ID: 875x1f1mwu.fsf@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers


Hello!

Bryan Green <dbryan(dot)green(at)gmail(dot)com> writes:
> ...
>     BEGIN;
>     DO $$
>     BEGIN
>         BEGIN
>             INSERT INTO t VALUES (1);   -- subtransaction acquires an XID
>         EXCEPTION WHEN OTHERS THEN
>             NULL;                       -- swallow the commit-time error
>         END;
>     END $$;
>     COMMIT;                             -- crashes here
>
>     TRAP: failed Assert("curval == 0 || ... || curval == status"),
>           File: "clog.c", Line: 702
>         TransactionIdSetStatusBit
>         TransactionIdSetTreeStatus
>         TransactionIdCommitTree
>         RecordTransactionCommit
>
> The fix is small and stays in xact.c.  AtSubCommit_childXids() records the
> parent's child count before it appends, and AbortSubTransaction() restores
> that count when the subtransaction aborts after the transfer.  The entries
> we added are the tail of the parent's array, so restoring the length drops
> exactly them; the grandchildren revert to aborted, which is correct because
> the whole subtree is rolling back.
>
> I confirmed on current master that the reproduction crashes without the
> patch and commits cleanly with it, that the aborted row is gone, that a
> committed sibling savepoint survives, and that the regression tests pass.

Probably this requires to have this test in the patch, reproducing this
issue it's not easy. Using a test that use the callback or an injection
point, don't know if this it's expects to be backported, if that's not
the case probably an injection point plus a regression will be enough.

Related to the code, you added this:

@@ -250,6 +252,7 @@ static TransactionStateData TopTransactionStateData = {
.state = TRANS_DEFAULT,
.blockState = TBLOCK_DEFAULT,
.topXidLogged = false,
+ .savedParentNChildXids = -1,
};

Why not initialize in StartTransaction() alongside with the other
transaction states ?

I was able to confirm this error, but it requires a test that targets
this specific case, that's why I think that the test should be included
here.

Regards,
--
Jonathan Gonzalez V.
EDB
https://www.enterprisedb.com

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Nathan Bossart 2026-08-12 14:10:07 Re: missing PGDLLIMPORT in utils/acl.h after CVE-related "Invalidate plan cache after role changes"
Previous Message Hüseyin Demir 2026-08-12 13:28:13 Re: [PATCH] pg_upgrade: add --initdb option to create the new cluster automatically