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;

Reply via email to