On Tue, Mar 10, 2026 at 11:09 PM Heikki Linnakangas <[email protected]> wrote:
> +1 for initializing all padding in WAL records. In fact I thought that
> we already did that. (Except in this case, apparently)

I found 42 exceptions like this. See the attached patch, it
initializes some WAL records and removes the WAL-related Valgrind
suppressions. The regression tests pass under Valgrind with these
changes.

As discussed above, I used memset instead of = { 0 }. I could observe
the latter to not initialize the padding on some configurations.
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 6afd5367c59..261405a122f 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1138,6 +1138,8 @@ brinbuild(Relation heap, Relation index, IndexInfo *indexInfo)
 		XLogRecPtr	recptr;
 		Page		page;
 
+		memset(&xlrec, 0, sizeof(xlrec));
+
 		xlrec.version = BRIN_CURRENT_VERSION;
 		xlrec.pagesPerRange = BrinGetPagesPerRange(index);
 
diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c
index a5187a6202f..bdef9a01fbd 100644
--- a/src/backend/access/brin/brin_pageops.c
+++ b/src/backend/access/brin/brin_pageops.c
@@ -187,6 +187,8 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
 			XLogRecPtr	recptr;
 			uint8		info = XLOG_BRIN_SAMEPAGE_UPDATE;
 
+			memset(&xlrec, 0, sizeof(xlrec));
+
 			xlrec.offnum = oldoff;
 
 			XLogBeginInsert();
@@ -272,6 +274,8 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
 			XLogRecPtr	recptr;
 			uint8		info;
 
+			memset(&xlrec, 0, sizeof(xlrec));
+
 			info = XLOG_BRIN_UPDATE | (extended ? XLOG_BRIN_INIT_PAGE : 0);
 
 			xlrec.insert.offnum = newoff;
@@ -429,6 +433,8 @@ brin_doinsert(Relation idxrel, BlockNumber pagesPerRange,
 		XLogRecPtr	recptr;
 		uint8		info;
 
+		memset(&xlrec, 0, sizeof(xlrec));
+
 		info = XLOG_BRIN_INSERT | (extended ? XLOG_BRIN_INIT_PAGE : 0);
 		xlrec.heapBlk = heapBlk;
 		xlrec.pagesPerRange = pagesPerRange;
diff --git a/src/backend/access/brin/brin_revmap.c b/src/backend/access/brin/brin_revmap.c
index 4e380ecc710..96d1795a6d3 100644
--- a/src/backend/access/brin/brin_revmap.c
+++ b/src/backend/access/brin/brin_revmap.c
@@ -411,6 +411,8 @@ brinRevmapDesummarizeRange(Relation idxrel, BlockNumber heapBlk)
 		xl_brin_desummarize xlrec;
 		XLogRecPtr	recptr;
 
+		memset(&xlrec, 0, sizeof(xlrec));
+
 		xlrec.pagesPerRange = revmap->rm_pagesPerRange;
 		xlrec.heapBlk = heapBlk;
 		xlrec.regOffset = regOffset;
@@ -624,6 +626,8 @@ revmap_physical_extend(BrinRevmap *revmap)
 		xl_brin_revmap_extend xlrec;
 		XLogRecPtr	recptr;
 
+		memset(&xlrec, 0, sizeof(xlrec));
+
 		xlrec.targetBlk = mapBlk;
 
 		XLogBeginInsert();
diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c
index 644d484ea53..189b579c60e 100644
--- a/src/backend/access/gin/ginbtree.c
+++ b/src/backend/access/gin/ginbtree.c
@@ -421,6 +421,8 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
 			ginxlogInsert xlrec;
 			BlockIdData childblknos[2];
 
+			memset(&xlrec, 0, sizeof(xlrec));
+
 			xlrec.flags = xlflags;
 
 			XLogRegisterData(&xlrec, sizeof(ginxlogInsert));
@@ -461,6 +463,8 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
 		Buffer		lbuffer = InvalidBuffer;
 		Page		newrootpg = NULL;
 
+		memset(&data, 0, sizeof(data));
+
 		/* Get a new index page to become the right page */
 		rbuffer = GinNewBuffer(btree->index);
 
diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c
index a6d88572cc2..fd1c46bc20f 100644
--- a/src/backend/access/gin/ginfast.c
+++ b/src/backend/access/gin/ginfast.c
@@ -118,6 +118,8 @@ writeListPage(Relation index, Buffer buffer,
 		ginxlogInsertListPage data;
 		XLogRecPtr	recptr;
 
+		memset(&data, 0, sizeof(data));
+
 		data.rightlink = rightlink;
 		data.ntuples = ntuples;
 
@@ -230,6 +232,8 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
 	int			cleanupSize;
 	bool		needWal;
 
+	memset(&data, 0, sizeof(data));
+
 	if (collector->ntuples == 0)
 		return;
 
@@ -571,6 +575,8 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
 		Buffer		buffers[GIN_NDELETE_AT_ONCE];
 		BlockNumber freespace[GIN_NDELETE_AT_ONCE];
 
+		memset(&data, 0, sizeof(data));
+
 		data.ndeleted = 0;
 		while (data.ndeleted < GIN_NDELETE_AT_ONCE && blknoToDelete != newHead)
 		{
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index 78f7b7a2495..2c85e31dc1a 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -687,6 +687,8 @@ ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
 		XLogRecPtr	recptr;
 		ginxlogUpdateMeta data;
 
+		memset(&data, 0, sizeof(data));
+
 		data.locator = index->rd_locator;
 		data.ntuples = 0;
 		data.newRightlink = data.prevTail = InvalidBlockNumber;
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index fbbe3a6dd70..c0d4fb86b48 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -199,6 +199,8 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
 		XLogRecPtr	recptr;
 		ginxlogDeletePage data;
 
+		memset(&data, 0, sizeof(data));
+
 		/*
 		 * We can't pass REGBUF_STANDARD for the deleted page, because we
 		 * didn't set pd_lower on pre-9.4 versions. The page might've been
diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c
index b354e4ba5d1..6b4cab9de16 100644
--- a/src/backend/access/gist/gistxlog.c
+++ b/src/backend/access/gist/gistxlog.c
@@ -503,6 +503,8 @@ gistXLogSplit(bool page_is_leaf,
 	XLogRecPtr	recptr;
 	int			i;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	for (ptr = dist; ptr; ptr = ptr->next)
 		npage++;
 
@@ -555,6 +557,8 @@ gistXLogPageDelete(Buffer buffer, FullTransactionId xid,
 	gistxlogPageDelete xlrec;
 	XLogRecPtr	recptr;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	xlrec.deleteXid = xid;
 	xlrec.downlinkOffset = downlinkOffset;
 
@@ -635,6 +639,8 @@ gistXLogUpdate(Buffer buffer,
 	int			i;
 	XLogRecPtr	recptr;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	xlrec.ntodelete = ntodelete;
 	xlrec.ntoinsert = ituplen;
 
@@ -673,6 +679,8 @@ gistXLogDelete(Buffer buffer, OffsetNumber *todelete, int ntodelete,
 	gistxlogDelete xlrec;
 	XLogRecPtr	recptr;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	xlrec.isCatalogRel = RelationIsAccessibleInLogicalDecoding(heaprel);
 	xlrec.snapshotConflictHorizon = snapshotConflictHorizon;
 	xlrec.ntodelete = ntodelete;
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 6203e3d7f8d..daab44ad937 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2366,6 +2366,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
 	int			npages = 0;
 	int			npages_used = 0;
 
+	memset(&scratch, 0, sizeof(scratch));
+
 	/* currently not needed (thus unsupported) for heap_multi_insert() */
 	Assert(!(options & HEAP_INSERT_NO_LOGICAL));
 
@@ -6587,6 +6589,7 @@ heap_inplace_update_and_unlock(Relation relation,
 		BlockNumber blkno;
 		XLogRecPtr	recptr;
 
+		memset(&xlrec, 0, sizeof(xlrec));
 		xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
 		xlrec.dbId = MyDatabaseId;
 		xlrec.tsId = MyDatabaseTableSpace;
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index a8025889be0..a6c918612c0 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -1957,6 +1957,7 @@ heap_log_freeze_cmp(const void *arg1, const void *arg2)
 static inline void
 heap_log_freeze_new_plan(xlhp_freeze_plan *plan, HeapTupleFreeze *frz)
 {
+	memset(plan, 0, sizeof(*plan));
 	plan->xmax = frz->xmax;
 	plan->t_infomask2 = frz->t_infomask2;
 	plan->t_infomask = frz->t_infomask;
@@ -2071,7 +2072,8 @@ log_heap_prune_and_freeze(Relation relation, Buffer buffer,
 	xlhp_prune_items unused_items;
 	OffsetNumber frz_offsets[MaxHeapTuplesPerPage];
 
-	xlrec.flags = 0;
+	memset(&xlrec, 0, sizeof(xlrec));
+	memset(&freeze_plans, 0, sizeof(freeze_plans));
 
 	/*
 	 * Prepare data for the buffer.  The arrays are not actually in the
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index aa82cede30a..ff475aa9739 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1317,6 +1317,8 @@ _bt_insertonpg(Relation rel,
 			XLogRecPtr	recptr;
 			uint16		upostingoff;
 
+			memset(&xlrec, 0, sizeof(xlrec));
+			memset(&xlmeta, 0, sizeof(xlmeta));
 			xlrec.offnum = newitemoff;
 
 			XLogBeginInsert();
@@ -1970,6 +1972,7 @@ _bt_split(Relation rel, Relation heaprel, BTScanInsert itup_key, Buffer buf,
 		uint8		xlinfo;
 		XLogRecPtr	recptr;
 
+		memset(&xlrec, 0, sizeof(xlrec));
 		xlrec.level = ropaque->btpo_level;
 		/* See comments below on newitem, orignewitem, and posting lists */
 		xlrec.firstrightoff = firstrightoff;
@@ -2560,6 +2563,8 @@ _bt_newlevel(Relation rel, Relation heaprel, Buffer lbuf, Buffer rbuf)
 		XLogRecPtr	recptr;
 		xl_btree_metadata md;
 
+		memset(&xlrec, 0, sizeof(xlrec));
+		memset(&md, 0, sizeof(md));
 		xlrec.rootblk = rootblknum;
 		xlrec.level = metad->btm_level;
 
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index c79dd38ee18..89f92dc7cba 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -287,6 +287,7 @@ _bt_set_cleanup_info(Relation rel, BlockNumber num_delpages)
 		xl_btree_metadata md;
 		XLogRecPtr	recptr;
 
+		memset(&md, 0, sizeof(md));
 		XLogBeginInsert();
 		XLogRegisterBuffer(0, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD);
 
@@ -475,6 +476,8 @@ _bt_getroot(Relation rel, Relation heaprel, int access)
 			XLogRecPtr	recptr;
 			xl_btree_metadata md;
 
+			memset(&xlrec, 0, sizeof(xlrec));
+			memset(&md, 0, sizeof(md));
 			XLogBeginInsert();
 			XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT);
 			XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD);
@@ -2253,6 +2256,7 @@ _bt_mark_page_halfdead(Relation rel, Relation heaprel, Buffer leafbuf,
 		xl_btree_mark_page_halfdead xlrec;
 		XLogRecPtr	recptr;
 
+		memset(&xlrec, 0, sizeof(xlrec));
 		xlrec.poffset = poffset;
 		xlrec.leafblk = leafblkno;
 		if (topparent != leafblkno)
@@ -2674,6 +2678,8 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 		uint8		xlinfo;
 		XLogRecPtr	recptr;
 
+		memset(&xlrec, 0, sizeof(xlrec));
+		memset(&xlmeta, 0, sizeof(xlmeta));
 		XLogBeginInsert();
 
 		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index af6b27b2135..7458715907f 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -205,6 +205,8 @@ addLeafTuple(Relation index, SpGistState *state, SpGistLeafTuple leafTuple,
 {
 	spgxlogAddLeaf xlrec;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	xlrec.newPage = isNew;
 	xlrec.storesNulls = isNulls;
 
@@ -404,6 +406,8 @@ moveLeafs(Relation index, SpGistState *state,
 	char	   *leafdata,
 			   *leafptr;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	/* This doesn't work on root page */
 	Assert(parent->buffer != InvalidBuffer);
 	Assert(parent->buffer != current->buffer);
@@ -714,6 +718,8 @@ doPickSplit(Relation index, SpGistState *state,
 				nToInsert,
 				maxToInclude;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	in.level = level;
 
 	/*
@@ -1518,6 +1524,8 @@ spgAddNodeAction(Relation index, SpGistState *state,
 	SpGistInnerTuple newInnerTuple;
 	spgxlogAddNode xlrec;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	/* Should not be applied to nulls */
 	Assert(!SpGistPageStoresNulls(current->page));
 
@@ -1726,6 +1734,8 @@ spgSplitNodeAction(Relation index, SpGistState *state,
 	spgxlogSplitTuple xlrec;
 	Buffer		newBuffer = InvalidBuffer;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	/* Should not be applied to nulls */
 	Assert(!SpGistPageStoresNulls(current->page));
 
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index 2678f7ab782..7d853bc9c07 100644
--- a/src/backend/access/spgist/spgvacuum.c
+++ b/src/backend/access/spgist/spgvacuum.c
@@ -140,6 +140,7 @@ vacuumLeafPage(spgBulkDeleteState *bds, Relation index, Buffer buffer,
 	OffsetNumber i,
 				max = PageGetMaxOffsetNumber(page);
 
+	memset(&xlrec, 0, sizeof(xlrec));
 	memset(predecessor, 0, sizeof(predecessor));
 	memset(deletable, 0, sizeof(deletable));
 	nDeletable = 0;
@@ -414,6 +415,8 @@ vacuumLeafRoot(spgBulkDeleteState *bds, Relation index, Buffer buffer)
 	OffsetNumber i,
 				max = PageGetMaxOffsetNumber(page);
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	xlrec.nDelete = 0;
 
 	/* Scan page, identify tuples to delete, accumulate stats */
@@ -505,6 +508,8 @@ vacuumRedirectAndPlaceholder(Relation index, Relation heaprel, Buffer buffer)
 	spgxlogVacuumRedirect xlrec;
 	GlobalVisState *vistest;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	xlrec.isCatalogRel = RelationIsAccessibleInLogicalDecoding(heaprel);
 	xlrec.nToPlaceholder = 0;
 	xlrec.snapshotConflictHorizon = InvalidTransactionId;
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 7fa8d9247e0..a849c494251 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -1355,6 +1355,8 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
 	xl_running_xacts xlrec;
 	XLogRecPtr	recptr;
 
+	memset(&xlrec, 0, sizeof(xlrec));
+
 	xlrec.xcnt = CurrRunningXacts->xcnt;
 	xlrec.subxcnt = CurrRunningXacts->subxcnt;
 	xlrec.subxid_overflow = (CurrRunningXacts->subxid_status != SUBXIDS_IN_ARRAY);
diff --git a/src/tools/valgrind.supp b/src/tools/valgrind.supp
index 2ad5b81526d..dc2e1323626 100644
--- a/src/tools/valgrind.supp
+++ b/src/tools/valgrind.supp
@@ -23,23 +23,6 @@
 	fun:pgstat_write_statsfiles
 }
 
-{
-	padding_XLogRecData_CRC
-	Memcheck:Value8
-
-	fun:pg_comp_crc32c*
-	fun:XLogRecordAssemble
-}
-
-{
-	padding_XLogRecData_write
-	Memcheck:Param
-	pwrite64(buf)
-
-	...
-	fun:XLogWrite
-}
-
 {
 	padding_relcache
 	Memcheck:Param

Reply via email to