| From: | Manu <manuelreyesbravo(at)gmail(dot)com> |
|---|---|
| To: | Hayato Kuroda (Fujitsu) <kuroda(dot)hayato(at)fujitsu(dot)com> |
| Cc: | Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>, Zhijie Hou (Fujitsu) <houzj(dot)fnst(at)fujitsu(dot)com>, vignesh C <vignesh21(at)gmail(dot)com>, Shlok Kyal <shlok(dot)kyal(dot)oss(at)gmail(dot)com>, shveta malik <shveta(dot)malik(at)gmail(dot)com>, Tomas Vondra <tomas(at)vondra(dot)me>, Dilip Kumar <dilipbalaut(at)gmail(dot)com>, Andrei Lepikhov <lepihov(at)gmail(dot)com>, wenhui qiu <qiuwenhuifx(at)gmail(dot)com>, Peter Smith <smithpb2250(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | Re: Parallel Apply |
| Date: | 2026-10-19 11:47:13 |
| Message-ID: | 179241043331.412232.10093540019935452394@gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
While testing the v27 patch set I hit a reproducible hang in the leader
apply worker, caused by an uninitialized read in the UPDATE path of
handle_dependency_on_change().
For an UPDATE, oldtup is filled by logicalrep_read_update() only when the
message carries an old tuple (the replica identity key changed). The
replica-identity check added in 0005 is guarded by that:
> if (has_oldtup)
> check_and_record_ri_dependency(relid, &oldtup, ...);
But the local-key check added in 0011 and the foreign-key check added in
0012 pass &oldtup with old_tuple=true unconditionally in the same case:
> check_and_record_local_key_dependency(relid, &oldtup, true, ...); /* 0011 */
> check_and_record_fkey_dependency(relid, &oldtup, true, ...); /* 0012 */
When the UPDATE does not change the replica identity, has_oldtup is false
and oldtup is never initialized, so both calls read uninitialized stack
memory.
Minimal repro (the subscriber has a local unique index on t(v); the update
touches a non-key column, so no old tuple is sent):
UPDATE t SET v = v + 1 WHERE id = :x;
Under gdb on the leader, oldtup.ncols comes out as garbage (I saw
-1475947488). The effect depends on the stack contents:
- a negative or small value: nothing visible;
- a large positive value: the leader spins in build_replica_identity_key()
(bms_is_member with values in the hundreds of millions), sits at 100% of
one core with the parallel workers idle, the publisher disconnects it on
wal_sender_timeout, and it relaunches and hangs again.
This is on a clean checkout, master 8e82d6610e72 with the v27 series. The
DELETE path is fine (logicalrep_read_delete always fills oldtup) and the
insert/new-tuple checks use newtup, so only the old-tuple checks in the
UPDATE case are affected. Guarding them with has_oldtup, as the 0005 RI
check already is, matches the existing pattern.
I have a self-contained repro script and can share it.
Regards,
Manu
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Osama Abdul Qader | 2026-10-19 11:49:14 | Re: [PATCH v1] Generic Datum Encoding and Compression Contexts (pg_encoding_type, pg_encoding_context) |
| Previous Message | Matheus Alcantara | 2026-10-19 11:34:11 | Re: postgres_fdw: transaction mode inheritance corner cases |