| From: | Masahiko Sawada <sawada(dot)mshk(at)gmail(dot)com> |
|---|---|
| To: | a(dot)kozhemyakin(at)postgrespro(dot)ru, pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Cc: | Amit Kapila <amit(dot)kapila16(at)gmail(dot)com> |
| Subject: | Re: BUG #19556: Segmentation fault in test_decoding |
| Date: | 2026-07-22 02:51:33 |
| Message-ID: | CAD21AoCz_x0zp7VcNTgO_gcbi=SVq2usoXbr26ry+HQm39hE0w@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
(CC'ing Amit as commit a271a1b50e might be related)
On Sun, Jul 19, 2026 at 12:30 AM Masahiko Sawada <sawada(dot)mshk(at)gmail(dot)com> wrote:
>
> On Fri, Jul 17, 2026 at 9:30 AM PG Bug reporting form
> <noreply(at)postgresql(dot)org> wrote:
> >
> > The following bug has been logged on the website:
> >
> > Bug reference: 19556
> > Logged by: Alexander Kozhemyakin
> > Email address: a(dot)kozhemyakin(at)postgrespro(dot)ru
> > PostgreSQL version: 19beta2
> > Operating system: ubuntu 26.04
> > Description:
> >
> > Hi,
> >
> > The following script causes the server to crash with a Segmentation fault.
> >
> > initdb -D data
> > echo "
> > max_prepared_transactions = '15'
> > wal_level = logical " >> data/postgresql.auto.conf
> > pg_ctl -D data -l logfile start
> >
> > psql <<EOF
> > SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot',
> > 'test_decoding', false, true);
> > CREATE TABLE test (id int PRIMARY KEY, data text);
> > INSERT INTO test VALUES (1, 'test data');
> > BEGIN;
> > SELECT * FROM test WHERE id = 1 FOR SHARE;
> > PREPARE TRANSACTION 'p1';
> > SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL,
> > 'include-xids', '0', 'skip-empty-xacts', '1');
> > EOF
> >
> >
> > backtrace
> > Program terminated with signal SIGSEGV, Segmentation fault.
> > #0 0x0000749f6ee23f54 in pg_decode_prepare_txn (ctx=0x6344c3d7f3f0,
> > txn=0x6344c3d7d320, prepare_lsn=24628632) at
> > /pgpro/postgres/contrib/test_decoding/test_decoding.c:378
> > 378 if (data->skip_empty_xacts && !txndata->xact_wrote_changes)
> > (gdb) bt
> > #0 0x0000749f6ee23f54 in pg_decode_prepare_txn (ctx=0x6344c3d7f3f0,
> > txn=0x6344c3d7d320, prepare_lsn=24628632) at
> > /pgpro/postgres/contrib/test_decoding/test_decoding.c:378
> > #1 0x00006344a8e8293c in prepare_cb_wrapper (cache=<optimized out>,
> > txn=<optimized out>, prepare_lsn=<optimized out>) at
> > /pgpro/postgres/src/backend/replication/logical/logical.c:985
> > #2 0x00006344a8e90c24 in ReorderBufferPrepare (rb=0x6344c3cd9e10,
> > xid=xid(at)entry=745, gid=gid(at)entry=0x7ffcb3620ef4 "p1") at
> > /pgpro/postgres/src/backend/replication/logical/reorderbuffer.c:2934
> > #3 0x00006344a8e7fa26 in DecodePrepare (ctx=0x6344c3d7f3f0,
> > buf=0x7ffcb3621030, parsed=0x7ffcb3620ea0) at
> > /pgpro/postgres/src/backend/replication/logical/decode.c:815
> > #4 xact_decode (ctx=0x6344c3d7f3f0, buf=0x7ffcb3621030) at
> > /pgpro/postgres/src/backend/replication/logical/decode.c:347
> > #5 0x00006344a8e7f223 in LogicalDecodingProcessRecord
> > (ctx=ctx(at)entry=0x6344c3d7f3f0, record=0x6344c3d7f788) at
> > /pgpro/postgres/src/backend/replication/logical/decode.c:116
> > #6 0x00006344a8e8577b in pg_logical_slot_get_changes_guts
> > (fcinfo=0x6344c3d83410, confirm=confirm(at)entry=true,
> > binary=binary(at)entry=false) at
> > /pgpro/postgres/src/backend/replication/logical/logicalfuncs.c:266
> > #7 0x00006344a8e858f4 in pg_logical_slot_get_changes (fcinfo=<optimized
> > out>) at /pgpro/postgres/src/backend/replication/logical/logicalfuncs.c:333
> > #8 0x00006344a8d3666d in ExecMakeTableFunctionResult
> > (setexpr=0x6344c3d5ffc8, econtext=0x6344c3d5fe18, argContext=<optimized
> > out>, expectedDesc=0x6344c3d49868, randomAccess=false)
> > at /pgpro/postgres/src/backend/executor/execSRF.c:234
> > #9 0x00006344a8d4a14b in FunctionNext (node=node(at)entry=0x6344c3d5fc08) at
> > /pgpro/postgres/src/backend/executor/nodeFunctionscan.c:94
> > #10 0x00006344a8d36f4c in ExecScanFetch (node=<optimized out>,
> > epqstate=<optimized out>, accessMtd=<optimized out>, recheckMtd=<optimized
> > out>) at /pgpro/postgres/src/include/executor/execScan.h:126
> > #11 ExecScanExtended (node=<optimized out>, accessMtd=0x6344a8d49e10
> > <FunctionNext>, recheckMtd=0x6344a8d49e00 <FunctionRecheck>, epqstate=0x0,
> > qual=0x0, projInfo=0x6344c3d49ea8)
> > at /pgpro/postgres/src/include/executor/execScan.h:187
> > #12 ExecScan (node=0x6344c3d5fc08, accessMtd=0x6344a8d49e10 <FunctionNext>,
> > recheckMtd=0x6344a8d49e00 <FunctionRecheck>) at
> > /pgpro/postgres/src/backend/executor/execScan.c:59
> > #13 0x00006344a8d2c17b in ExecProcNode (node=0x6344c3d5fc08) at
> > /pgpro/postgres/src/include/executor/executor.h:272
> > #14 ExecutePlan (queryDesc=0x6344c3cd55d0, operation=CMD_SELECT,
> > sendTuples=true, numberTuples=0, direction=<optimized out>,
> > dest=0x6344c3d8b7b8) at /pgpro/postgres/src/backend/executor/execMain.c:1675
> > #15 standard_ExecutorRun (queryDesc=0x6344c3cd55d0, direction=<optimized
> > out>, count=0) at /pgpro/postgres/src/backend/executor/execMain.c:364
> > #16 0x00006344a8f11478 in PortalRunSelect
> > (portal=portal(at)entry=0x6344c3d018b0, forward=forward(at)entry=true, count=0,
> > count(at)entry=9223372036854775807, dest=dest(at)entry=0x6344c3d8b7b8)
> > at /pgpro/postgres/src/backend/tcop/pquery.c:920
> > #17 0x00006344a8f12c5e in PortalRun (portal=portal(at)entry=0x6344c3d018b0,
> > count=count(at)entry=9223372036854775807, isTopLevel=isTopLevel(at)entry=true,
> > dest=dest(at)entry=0x6344c3d8b7b8, altdest=altdest(at)entry=0x6344c3d8b7b8,
> > qc=qc(at)entry=0x7ffcb3621640) at
> > /pgpro/postgres/src/backend/tcop/pquery.c:764
> > #18 0x00006344a8f0e95e in exec_simple_query (query_string=0x6344c3c80f60
> > "SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL,
> > 'include-xids', '0', 'skip-empty-xacts', '1');")
> > at /pgpro/postgres/src/backend/tcop/postgres.c:1271
> > #19 0x00006344a8f103e5 in PostgresMain (dbname=<optimized out>,
> > username=<optimized out>) at
> > /pgpro/postgres/src/backend/tcop/postgres.c:4691
> > #20 0x00006344a8f0aaa3 in BackendMain (startup_data=<optimized out>,
> > startup_data_len=<optimized out>) at
> > /pgpro/postgres/src/backend/tcop/backend_startup.c:107
> > #21 0x00006344a8e6184f in postmaster_child_launch (child_type=<optimized
> > out>, child_slot=1, startup_data=startup_data(at)entry=0x7ffcb3621aec "",
> > startup_data_len=startup_data_len(at)entry=4,
> > client_sock=client_sock(at)entry=0x7ffcb3621af0) at
> > /pgpro/postgres/src/backend/postmaster/launch_backend.c:274
> > #22 0x00006344a8e653ef in BackendStartup (client_sock=0x7ffcb3621af0) at
> > /pgpro/postgres/src/backend/postmaster/postmaster.c:3519
> > #23 ServerLoop () at
> > /pgpro/postgres/src/backend/postmaster/postmaster.c:1688
> > #24 0x00006344a8e66cbf in PostmasterMain (argc=argc(at)entry=3,
> > argv=argv(at)entry=0x6344c3c7b440) at
> > /pgpro/postgres/src/backend/postmaster/postmaster.c:1386
> > #25 0x00006344a8b3b35e in main (argc=3, argv=0x6344c3c7b440) at
> > /pgpro/postgres/src/backend/main/main.c:230
> >
>
> Thank you for the report!
>
> > first bad commit 072ee847ad4c3fb52
>
> Right. I've confirmed that this issue can happen PG18 or newer. In
> ReorderBufferPrepare() it sends a prepare message if
> ReorderBufferReplay() didn't send it, but ISTM missed the case where
> the transaction is empty. I'll investigate the issue further and work
> on it.
>
While researching this bug, I found another one that is related and
probably should be fixed first: even in PG17 and earlier, logical
decoding calls the commit_prepared callback without first calling the
prepare callback:
BEGIN;
SELECT * FROM test WHERE id = 1 FOR SHARE;
PREPARE TRANSACTION 'p1';
COMMIT PREPARED 'p1';
In logical replication, the subscriber ends up with an error because
the prepared transaction doesn't exist on it.
In summary, with the above scenario, logical decoding calls:
- the prepare and commit_prepared callbacks (PG18+)
- the commit_prepared callback (PG17-)
Neither is correct.
I think we shouldn't call the commit_prepared callback for an empty
transaction (one that has no base snapshot), so in this case we
shouldn't call any of the begin_prepare, prepare, or commit_prepared
callbacks. Thoughts?
Regards,
--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Amit Kapila | 2026-07-22 06:07:25 | Re: BUG #19556: Segmentation fault in test_decoding |
| Previous Message | Zsolt Parragi | 2026-07-21 21:36:55 | Should CUSTER (ANALYZE) work? |