On Tue, Nov 26, 2024 at 1:58 AM Vallimaharajan G < vallimaharajan...@zohocorp.com> wrote: > > Hi Developers, > We have discovered a bug in the parallel_vacuum_reset_dead_items function in PG v17.2. Specifically: > > TidStoreDestroy(dead_items) frees the dead_items pointer. > The pointer is reinitialized using TidStoreCreateShared(). > However, the code later accesses the freed pointer instead of the newly reinitialized pvs->dead_items, as seen in these lines: > > pvs->shared->dead_items_dsa_handle = dsa_get_handle(TidStoreGetDSA(dead_items)); > pvs->shared->dead_items_handle = TidStoreGetHandle(dead_items);
Thanks for the report! I don't see any immediate evidence of deleterious effects, but it's still sloppy. To reduce risk going forward, I think we should always access this pointer via the struct rather than a separate copy, quick attempt attached. (BTW, it's normally discouraged to cross-post to different lists. Either one is fine in this case.) -- John Naylor Amazon Web Services
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 793bd33cb4..667b1c54e1 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -2917,8 +2917,6 @@ dead_items_add(LVRelState *vacrel, BlockNumber blkno, OffsetNumber *offsets, static void dead_items_reset(LVRelState *vacrel) { - TidStore *dead_items = vacrel->dead_items; - if (ParallelVacuumIsActive(vacrel)) { parallel_vacuum_reset_dead_items(vacrel->pvs); @@ -2926,7 +2924,7 @@ dead_items_reset(LVRelState *vacrel) } /* Recreate the tidstore with the same max_bytes limitation */ - TidStoreDestroy(dead_items); + TidStoreDestroy(vacrel->dead_items); vacrel->dead_items = TidStoreCreateLocal(vacrel->dead_items_info->max_bytes, true); /* Reset the counter */ diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c index 4fd6574e12..4b0669b1e6 100644 --- a/src/backend/commands/vacuumparallel.c +++ b/src/backend/commands/vacuumparallel.c @@ -247,7 +247,6 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes, ParallelVacuumState *pvs; ParallelContext *pcxt; PVShared *shared; - TidStore *dead_items; PVIndStats *indstats; BufferUsage *buffer_usage; WalUsage *wal_usage; @@ -378,11 +377,10 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes, shared->dead_items_info.max_bytes = vac_work_mem * 1024L; /* Prepare DSA space for dead items */ - dead_items = TidStoreCreateShared(shared->dead_items_info.max_bytes, - LWTRANCHE_PARALLEL_VACUUM_DSA); - pvs->dead_items = dead_items; - shared->dead_items_handle = TidStoreGetHandle(dead_items); - shared->dead_items_dsa_handle = dsa_get_handle(TidStoreGetDSA(dead_items)); + pvs->dead_items = TidStoreCreateShared(shared->dead_items_info.max_bytes, + LWTRANCHE_PARALLEL_VACUUM_DSA); + shared->dead_items_handle = TidStoreGetHandle(pvs->dead_items); + shared->dead_items_dsa_handle = dsa_get_handle(TidStoreGetDSA(pvs->dead_items)); /* Use the same buffer size for all workers */ shared->ring_nbuffers = GetAccessStrategyBufferCount(bstrategy); @@ -474,7 +472,6 @@ parallel_vacuum_get_dead_items(ParallelVacuumState *pvs, VacDeadItemsInfo **dead void parallel_vacuum_reset_dead_items(ParallelVacuumState *pvs) { - TidStore *dead_items = pvs->dead_items; VacDeadItemsInfo *dead_items_info = &(pvs->shared->dead_items_info); /* @@ -482,13 +479,13 @@ parallel_vacuum_reset_dead_items(ParallelVacuumState *pvs) * operating system. Then we recreate the tidstore with the same max_bytes * limitation we just used. */ - TidStoreDestroy(dead_items); + TidStoreDestroy(pvs->dead_items); pvs->dead_items = TidStoreCreateShared(dead_items_info->max_bytes, LWTRANCHE_PARALLEL_VACUUM_DSA); /* Update the DSA pointer for dead_items to the new one */ - pvs->shared->dead_items_dsa_handle = dsa_get_handle(TidStoreGetDSA(dead_items)); - pvs->shared->dead_items_handle = TidStoreGetHandle(dead_items); + pvs->shared->dead_items_dsa_handle = dsa_get_handle(TidStoreGetDSA(pvs->dead_items)); + pvs->shared->dead_items_handle = TidStoreGetHandle(pvs->dead_items); /* Reset the counter */ dead_items_info->num_items = 0;