public inbox for [email protected]
help / color / mirror / Atom feedRe: Fix uninitialized xl_running_xacts padding
16+ messages / 6 participants
[nested] [flat]
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-02-16 20:10 Andres Freund <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Andres Freund @ 2026-02-16 20:10 UTC (permalink / raw)
To: Anthonin Bonnefoy <[email protected]>; +Cc: Bertrand Drouvot <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
Hi,
On 2026-02-16 12:02:33 +0100, Anthonin Bonnefoy wrote:
> I think that depends on the C standard used. With C99, there's no rule
> for the padding bytes initialization.
> With C11, in 6.7.9 Initialization of the standard: "the remainder of
> the aggregate shall be initialized implicitly the same as objects that
> have static storage duration", and with static storage will "every
> member is initialized (recursively) according to these rules, and any
> padding is initialized to zero bits".
I don't think that rule applies for things like xl_running_xacts, as it does
not have static storage duration.
> So if I read this correctly, '{0}' will set padding bytes to 0 when
> using C11. But given Postgres is using C99, that's not something we
> can rely on?
We use C11, but the guarantee doesn't help us, due to the static storage
duration restriction. However, in C23, this has been fixed:
6.7.10 Initialization, point 11:
If an object that has automatic storage duration is initialized with an empty
initializer, its value is the same as the initialization of a static storage
duration object. Otherwise, if an object that has automatic storage duration
is not initialized explicitly, its representation is indeterminate. [...]
This notably includes being able to initialize everything to default with {}.
But C23 won't help us for a while :(
> > > True about the initialization part, mostly I guess, still we tend to
> > > worry about eliminating padding because these are wasted bytes in the
> > > WAL records. For example, xlhp_freeze_plans has two bytes of padding,
> > > that we eliminate while inserting its record by splitting the
> > > FLEXIBLE_ARRAY_MEMBER part.
> >
> > But in the case of this thread it's in the middle of the struct, so I'm not
> > sure the "wasted" bytes would be elminated, would it?
>
> Moving subxid_overflow before xids, wouldn't you have 3 bytes of
> padding at the end of the struct for the whole struct alignment?
Yes. I'm a bit doubtful the space wastage argument is strong for most of the
record types with padding, for a lot of them the waste through the padding is
such a small amount compared to the record type that it won't matter.
I don't think it makes a whole lot of sense to tackle this specifically for
xl_running_xacts. Until now we just accepted that WAL insertions can contain
random padding. If we don't want that, we should go around and make sure that
there is no padding (or padding is initialized) for *all* WAL records,
document that as the rule, and remove the relevant valgrind suppressions.
A lot of the WAL structs have holes. At least
- xl_brin_update
- xl_btree_mark_page_halfdead
- xl_btree_unlink_page
- xl_hash_vacuum_one_page
- xl_heap_inplace
- xl_heap_multi_insert
- xl_heap_rewrite_mapping
- xl_heap_truncate
- xl_invalidations
- xl_logical_message
- xl_multixact_create
- xl_running_xacts
- xl_xact_prepare
- xlhp_freeze_plan (not a toplevel type)
- xlhp_freeze_plans (not a toplevel type)
I didn't check how many WAL record have trailing padding that we don't avoid
with
offsetoff(structname, last_field) + sizeof(last_field_type)
style hackery.
Greetings,
Andres Freund
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-10 21:51 Alexander Kuzmenkov <[email protected]>
parent: Andres Freund <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Alexander Kuzmenkov @ 2026-03-10 21:51 UTC (permalink / raw)
To: Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; +Cc: Bertrand Drouvot <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On 16/02/2026 21:10, Andres Freund wrote:
> I don't think it makes a whole lot of sense to tackle this specifically for
> xl_running_xacts. Until now we just accepted that WAL insertions can contain
> random padding. If we don't want that, we should go around and make sure that
> there is no padding (or padding is initialized) for *all* WAL records,
> document that as the rule, and remove the relevant valgrind suppressions.
That's not random, that's server memory, right? Probably not another
Heartbleed, but I'd rather initialize a few locals than find out.
Happy to see this being worked on, these uninitialized WAL records are a
major obstacle to enabling MemorySanitizer. I ran into this again today
and this is how I found this thread. Unfortunately the MemorySanitizer
can't even use the same suppressions as Valgrind, because the
suppression architecture is different (can only remove the checks from a
given function, not all stack traces that have this function like
Valgrind does).
Best regards
Alexander Kuzmenkov
TigerData
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-10 22:09 Heikki Linnakangas <[email protected]>
parent: Alexander Kuzmenkov <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Heikki Linnakangas @ 2026-03-10 22:09 UTC (permalink / raw)
To: Alexander Kuzmenkov <[email protected]>; Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; +Cc: Bertrand Drouvot <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On 10/03/2026 23:51, Alexander Kuzmenkov wrote:
> On 16/02/2026 21:10, Andres Freund wrote:
>> I don't think it makes a whole lot of sense to tackle this
>> specifically for
>> xl_running_xacts. Until now we just accepted that WAL insertions can
>> contain
>> random padding. If we don't want that, we should go around and make
>> sure that
>> there is no padding (or padding is initialized) for *all* WAL records,
>> document that as the rule, and remove the relevant valgrind suppressions.
>
> That's not random, that's server memory, right? Probably not another
> Heartbleed, but I'd rather initialize a few locals than find out.
>
> Happy to see this being worked on, these uninitialized WAL records are a
> major obstacle to enabling MemorySanitizer. I ran into this again today
> and this is how I found this thread. Unfortunately the MemorySanitizer
> can't even use the same suppressions as Valgrind, because the
> suppression architecture is different (can only remove the checks from a
> given function, not all stack traces that have this function like
> Valgrind does).
+1 for initializing all padding in WAL records. In fact I thought that
we already did that. (Except in this case, apparently)
- Heikki
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-11 10:45 Alexander Kuzmenkov <[email protected]>
parent: Heikki Linnakangas <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Alexander Kuzmenkov @ 2026-03-11 10:45 UTC (permalink / raw)
To: Heikki Linnakangas <[email protected]>; +Cc: Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
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.
Attachments:
[text/x-patch] initialize-wal-record-padding.patch (13.3K, 2-initialize-wal-record-padding.patch)
download | inline diff:
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
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-11 11:07 Alexander Kuzmenkov <[email protected]>
parent: Alexander Kuzmenkov <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Alexander Kuzmenkov @ 2026-03-11 11:07 UTC (permalink / raw)
To: Heikki Linnakangas <[email protected]>; +Cc: Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On Wed, Mar 11, 2026 at 11:45 AM Alexander Kuzmenkov
<[email protected]> wrote:
>
> 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.
I think I'm making some unneeded changes here though. For example in
ginxlogInsertListPage for a two-int struct with no padding. I'll need
to check them again one by one.
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-12 12:54 Heikki Linnakangas <[email protected]>
parent: Alexander Kuzmenkov <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Heikki Linnakangas @ 2026-03-12 12:54 UTC (permalink / raw)
To: Alexander Kuzmenkov <[email protected]>; +Cc: Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On 11/03/2026 13:07, Alexander Kuzmenkov wrote:
> On Wed, Mar 11, 2026 at 11:45 AM Alexander Kuzmenkov
> <[email protected]> wrote:
>>
>> 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.
>
> I think I'm making some unneeded changes here though. For example in
> ginxlogInsertListPage for a two-int struct with no padding. I'll need
> to check them again one by one.
I experimented with this a little more. Valgrind complained about one
more place on 'master': the xl_multixact_create got padding, when
MultiXactOffset was widened to 64 bits. That could be fixed by swapping
the fields.
Another thing I did to find possible initializations: I ran 'pahole
bin/postgres' and search for all the "xl_*" structs with padding, and
then looked at where they're initialized. Attached patch (0003) shows a
few places that look suspicious to me. I don't think I caught all
structs used in WAL records, though, like the ginxlogInsertListPage
thing mentioned.
I wish we could just mark all WAL record structs with
pg_attribute_packed(). Unfortunately pg_attribute_packed() is not
available on all compilers we support.
- Heikki
Attachments:
[text/x-patch] 0001-Initialize-WAL-record-structs.patch (14.4K, 2-0001-Initialize-WAL-record-structs.patch)
download | inline diff:
From 2b9a360952aae94eb09afd7a46b0e4170f916464 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <[email protected]>
Date: Thu, 12 Mar 2026 12:42:11 +0200
Subject: [PATCH 1/4] Initialize WAL record structs
Author: Alexander Kuzmenkov <[email protected]>
---
src/backend/access/brin/brin.c | 2 ++
src/backend/access/brin/brin_pageops.c | 6 ++++++
src/backend/access/brin/brin_revmap.c | 4 ++++
src/backend/access/gin/ginbtree.c | 4 ++++
src/backend/access/gin/ginfast.c | 6 ++++++
src/backend/access/gin/ginutil.c | 2 ++
src/backend/access/gin/ginvacuum.c | 2 ++
src/backend/access/gist/gistxlog.c | 8 ++++++++
src/backend/access/heap/heapam.c | 3 +++
src/backend/access/heap/pruneheap.c | 5 ++++-
src/backend/access/nbtree/nbtinsert.c | 5 +++++
src/backend/access/nbtree/nbtpage.c | 6 ++++++
src/backend/access/spgist/spgdoinsert.c | 10 ++++++++++
src/backend/access/spgist/spgvacuum.c | 5 +++++
src/backend/storage/ipc/standby.c | 2 ++
src/tools/valgrind.supp | 17 -----------------
16 files changed, 69 insertions(+), 18 deletions(-)
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 1909c3254b5..88e32c7fb74 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1141,6 +1141,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 7da97bec43b..dc56932ab21 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();
@@ -271,6 +273,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;
@@ -427,6 +431,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 233355cb2d5..c9db4e59822 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 3d3a9da56b1..6eaeebf79bc 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 f50848eb65a..710c16887df 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 ff927279cc3..76be56e932b 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -650,6 +650,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 d5c8bef5ceb..ad3c4115593 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -200,6 +200,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 c783838495f..8629514e265 100644
--- a/src/backend/access/gist/gistxlog.c
+++ b/src/backend/access/gist/gistxlog.c
@@ -501,6 +501,8 @@ gistXLogSplit(bool page_is_leaf,
XLogRecPtr recptr;
int i;
+ memset(&xlrec, 0, sizeof(xlrec));
+
for (ptr = dist; ptr; ptr = ptr->next)
npage++;
@@ -553,6 +555,8 @@ gistXLogPageDelete(Buffer buffer, FullTransactionId xid,
gistxlogPageDelete xlrec;
XLogRecPtr recptr;
+ memset(&xlrec, 0, sizeof(xlrec));
+
xlrec.deleteXid = xid;
xlrec.downlinkOffset = downlinkOffset;
@@ -633,6 +637,8 @@ gistXLogUpdate(Buffer buffer,
int i;
XLogRecPtr recptr;
+ memset(&xlrec, 0, sizeof(xlrec));
+
xlrec.ntodelete = ntodelete;
xlrec.ntoinsert = ituplen;
@@ -671,6 +677,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 8f1c11a9350..b11dba81aef 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2428,6 +2428,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));
@@ -6654,6 +6656,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 6beeb6956e3..54b4a5ab0c8 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -2058,6 +2058,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;
@@ -2182,7 +2183,9 @@ log_heap_prune_and_freeze(Relation relation, Buffer buffer,
Assert((vmflags & VISIBILITYMAP_VALID_BITS) == vmflags);
- xlrec.flags = 0;
+ memset(&xlrec, 0, sizeof(xlrec));
+ memset(&freeze_plans, 0, sizeof(freeze_plans));
+
regbuf_flags_heap = REGBUF_STANDARD;
/*
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 796e1513ddf..a4a6d4e8995 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1336,6 +1336,8 @@ _bt_insertonpg(Relation rel,
XLogRecPtr recptr;
uint16 upostingoff;
+ memset(&xlrec, 0, sizeof(xlrec));
+ memset(&xlmeta, 0, sizeof(xlmeta));
xlrec.offnum = newitemoff;
XLogBeginInsert();
@@ -1996,6 +1998,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;
@@ -2585,6 +2588,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 4125c185e8b..176090e6558 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -288,6 +288,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);
@@ -476,6 +477,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);
@@ -2255,6 +2258,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)
@@ -2678,6 +2682,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 7c7371c69e8..e96b20c30bd 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -204,6 +204,8 @@ addLeafTuple(Relation index, SpGistState *state, SpGistLeafTuple leafTuple,
{
spgxlogAddLeaf xlrec;
+ memset(&xlrec, 0, sizeof(xlrec));
+
xlrec.newPage = isNew;
xlrec.storesNulls = isNulls;
@@ -403,6 +405,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);
@@ -710,6 +714,8 @@ doPickSplit(Relation index, SpGistState *state,
nToInsert,
maxToInclude;
+ memset(&xlrec, 0, sizeof(xlrec));
+
in.level = level;
/*
@@ -1514,6 +1520,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));
@@ -1722,6 +1730,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 6b7117b56b2..9e6acb873ef 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 f3ad90c7c7a..4ae5be2792b 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -1357,6 +1357,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 d56794b4f7e..f2ab0c8a052 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
--
2.47.3
[text/x-patch] 0002-Avoid-padding-in-xl_multixact_create-WAL-record.patch (1.7K, 3-0002-Avoid-padding-in-xl_multixact_create-WAL-record.patch)
download | inline diff:
From 74d0084faef3bc6d748bd1e26e39c2683d27de1a Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <[email protected]>
Date: Thu, 12 Mar 2026 14:30:13 +0200
Subject: [PATCH 2/4] Avoid padding in xl_multixact_create WAL record
When MultiXactOffset was widened to 64 bits in commit bd8d9c9bdf, the
struct started to need alignment padding for the 'moff' field. Reorder
the fields to avoid it.
Discussion: https://www.postgresql.org/message-id/CALzhyqzKTRVsQGj+qDDRVs3Oo0EvffuQvVO0v4rbpWU=SoXKug@mail.gmail.com
---
src/include/access/multixact.h | 2 +-
src/include/access/xlog_internal.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 2ae8b571dcc..757c631e725 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -72,8 +72,8 @@ typedef struct MultiXactMember
typedef struct xl_multixact_create
{
MultiXactId mid; /* new MultiXact's ID */
- MultiXactOffset moff; /* its starting offset in members file */
int32 nmembers; /* number of member XIDs */
+ MultiXactOffset moff; /* its starting offset in members file */
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER];
} xl_multixact_create;
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 58ae12bb20f..629ac3a7d3e 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -31,7 +31,7 @@
/*
* Each page of XLOG file has a header like this:
*/
-#define XLOG_PAGE_MAGIC 0xD11C /* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD11D /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
--
2.47.3
[text/x-patch] 0003-XXX-a-few-more-places-that-maybe-need-clearing.patch (3.8K, 4-0003-XXX-a-few-more-places-that-maybe-need-clearing.patch)
download | inline diff:
From a60e3cb4911911fff968eadb4e0f318c2edd1dbb Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <[email protected]>
Date: Thu, 12 Mar 2026 14:40:25 +0200
Subject: [PATCH 3/4] XXX: a few more places that maybe need clearing?
I spotted these by doing 'pahole bin/postgres', and searching for
"xl_*" structs that have padding in them. Then I searched where
they're initialized.
---
src/backend/access/hash/hashinsert.c | 2 ++
src/backend/access/heap/heapam.c | 6 ++++++
src/backend/access/heap/rewriteheap.c | 2 ++
src/backend/access/transam/twophase.c | 2 ++
src/backend/commands/tablecmds.c | 2 ++
src/backend/replication/logical/message.c | 2 ++
6 files changed, 16 insertions(+)
diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c
index 0cefbacc96e..45e613ceddb 100644
--- a/src/backend/access/hash/hashinsert.c
+++ b/src/backend/access/hash/hashinsert.c
@@ -426,6 +426,8 @@ _hash_vacuum_one_page(Relation rel, Relation hrel, Buffer metabuf, Buffer buf)
xl_hash_vacuum_one_page xlrec;
XLogRecPtr recptr;
+ /* XXX: clear padding? */
+
xlrec.isCatalogRel = RelationIsAccessibleInLogicalDecoding(hrel);
xlrec.snapshotConflictHorizon = snapshotConflictHorizon;
xlrec.ntuples = ndeletable;
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index b11dba81aef..54943be6126 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2616,6 +2616,12 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
xlrec = (xl_heap_multi_insert *) scratchptr;
scratchptr += SizeOfHeapMultiInsert;
+ /*
+ * XXX: need to clear padding in xl_heap_multi_insert? The scratch
+ * area was zeroed at the top of the function, but we're reusing
+ * it for multiple records.
+ */
+
/*
* Allocate offsets array. Unless we're reinitializing the page,
* in that case the tuples are stored in order starting at
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 6b19ac3030d..b6d784572ec 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -842,6 +842,8 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
else
dboid = MyDatabaseId;
+ /* XXX: clear padding? */
+
xlrec.num_mappings = num_mappings;
xlrec.mapped_rel = RelationGetRelid(state->rs_old_rel);
xlrec.mapped_xid = src->xid;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 55b9f38927d..c22ab93965e 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1076,6 +1076,8 @@ StartPrepare(GlobalTransaction gxact)
records.total_len = 0;
+ /* XXX: Clear padding? */
+
/* Create header */
hdr.magic = TWOPHASE_MAGIC;
hdr.total_len = 0; /* EndPrepare will fill this in */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index a7c32679b22..1bf59f77ae1 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2325,6 +2325,8 @@ ExecuteTruncateGuts(List *explicit_rels,
foreach(cell, relids_logged)
logrelids[i++] = lfirst_oid(cell);
+ /* XXX: clear padding? */
+
xlrec.dbId = MyDatabaseId;
xlrec.nrelids = list_length(relids_logged);
xlrec.flags = 0;
diff --git a/src/backend/replication/logical/message.c b/src/backend/replication/logical/message.c
index 06825d66e7f..40d032a4ffc 100644
--- a/src/backend/replication/logical/message.c
+++ b/src/backend/replication/logical/message.c
@@ -55,6 +55,8 @@ LogLogicalMessage(const char *prefix, const char *message, size_t size,
GetCurrentTransactionId();
}
+ /* XXX: clear padding? */
+
xlrec.dbId = MyDatabaseId;
xlrec.transactional = transactional;
/* trailing zero is critical; see logicalmsg_desc */
--
2.47.3
[text/x-patch] 0004-Add-an-explicit-valgrind-check-in-XLogInsert-for-uni.patch (1.3K, 5-0004-Add-an-explicit-valgrind-check-in-XLogInsert-for-uni.patch)
download | inline diff:
From f36c2e1a052ae30d6fbdc946f990ab079234e332 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <[email protected]>
Date: Thu, 12 Mar 2026 12:52:41 +0200
Subject: [PATCH 4/4] Add an explicit valgrind check in XLogInsert() for
uninitialized data
Even without this, Valgrind complains if uninitialized memory copied
into the WAL, when the WAL is flushed to disk. With this commit, it's
caught earlier, in XLogInsert(), which makes it more clear where the
uninitialized data is coming from.
---
src/backend/access/transam/xlog.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b9b678f3722..8eae29a3548 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -98,6 +98,7 @@
#include "utils/guc_hooks.h"
#include "utils/guc_tables.h"
#include "utils/injection_point.h"
+#include "utils/memdebug.h"
#include "utils/pgstat_internal.h"
#include "utils/ps_status.h"
#include "utils/relmapper.h"
@@ -1259,6 +1260,8 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
const char *rdata_data = rdata->data;
int rdata_len = rdata->len;
+ VALGRIND_CHECK_MEM_IS_DEFINED(rdata_data, rdata_len);
+
while (rdata_len > freespace)
{
/*
--
2.47.3
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-12 18:23 Alexander Kuzmenkov <[email protected]>
parent: Heikki Linnakangas <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Alexander Kuzmenkov @ 2026-03-12 18:23 UTC (permalink / raw)
To: Heikki Linnakangas <[email protected]>; +Cc: Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
The functions in the "0003" patch haven't surfaced in my "make
installcheck-parallel" runs with Valgrind, or the "make check" with
MemorySanitizer. However, I could hit most of them with some fuzzing. The
only exception was `xl_hash_vacuum_one_page` but that's probably also
triggerable.
I noticed that we also use `sizeof` in some WAL functions, so probably the
tail padding can also be written to WAL? For example, consider this:
(gdb) ptype/o gistxlogPageSplit
type = struct gistxlogPageSplit {
/* 0 | 4 */ BlockNumber origrlink;
/* XXX 4-byte hole */
/* 8 | 8 */ GistNSN orignsn;
/* 16 | 1 */ _Bool origleaf;
/* XXX 1-byte hole */
/* 18 | 2 */ uint16 npage;
/* 20 | 1 */ _Bool markfollowright;
/* XXX 3-byte padding */
/* total size (bytes): 24 */
}
And then we do XLogRegisterData((char *) &xlrec,
sizeof(gistxlogPageSplit));
In general, I'm wondering what our approach to this should be. Several
potential improvements were mentioned, but I think for now we could focus
on removing the Valgrind suppression. This is a meaningful improvement that
uses the existing test tools. Do we want to defensively zero-initialize
every case that seems to be potentially affected, i.e. written to WAL and
has holes/tail padding? That sounds cheap and simple and probably even
backportable. In the "0001" patch, there are several cases where no padding
goes into WAL, I can remove these. For example, the use of
xl_brin_createidx in brinbuild() does not have this problem.
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-16 16:14 Alexander Kuzmenkov <[email protected]>
parent: Alexander Kuzmenkov <[email protected]>
0 siblings, 2 replies; 16+ messages in thread
From: Alexander Kuzmenkov @ 2026-03-16 16:14 UTC (permalink / raw)
To: Heikki Linnakangas <[email protected]>; +Cc: Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
I have removed the unnecessary memsets (for structs with no padding). With
these changes, and removing the two WAL-related suppressions, the make
installcheck under Valgrind passes. The second patch is a small addition to
the hash index test that exercises the "vacuum one page" path we discussed
above.
Attachments:
[text/x-patch] initialize-wal-structs-with-padding-only.patch (14.6K, 3-initialize-wal-structs-with-padding-only.patch)
download | inline diff:
diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c
index 7da97be..ba3b1c2 100644
--- a/src/backend/access/brin/brin_pageops.c
+++ b/src/backend/access/brin/brin_pageops.c
@@ -271,6 +271,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;
diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c
index 3d3a9da..0021db0 100644
--- a/src/backend/access/gin/ginbtree.c
+++ b/src/backend/access/gin/ginbtree.c
@@ -461,6 +461,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 f50848e..d83aecb 100644
--- a/src/backend/access/gin/ginfast.c
+++ b/src/backend/access/gin/ginfast.c
@@ -230,6 +230,8 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
int cleanupSize;
bool needWal;
+ memset(&data, 0, sizeof(data));
+
if (collector->ntuples == 0)
return;
@@ -571,6 +573,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 ff92727..76be56e 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -650,6 +650,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 840543e..1c524de 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -214,6 +214,8 @@ ginDeletePostingPage(GinVacuumState *gvs, Buffer dBuffer, Buffer lBuffer,
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 c783838..1028db4 100644
--- a/src/backend/access/gist/gistxlog.c
+++ b/src/backend/access/gist/gistxlog.c
@@ -501,6 +501,8 @@ gistXLogSplit(bool page_is_leaf,
XLogRecPtr recptr;
int i;
+ memset(&xlrec, 0, sizeof(xlrec));
+
for (ptr = dist; ptr; ptr = ptr->next)
npage++;
@@ -671,6 +673,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/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c
index 0cefbac..6f30bd0 100644
--- a/src/backend/access/hash/hashinsert.c
+++ b/src/backend/access/hash/hashinsert.c
@@ -426,6 +426,7 @@ _hash_vacuum_one_page(Relation rel, Relation hrel, Buffer metabuf, Buffer buf)
xl_hash_vacuum_one_page xlrec;
XLogRecPtr recptr;
+ memset(&xlrec, 0, sizeof(xlrec));
xlrec.isCatalogRel = RelationIsAccessibleInLogicalDecoding(hrel);
xlrec.snapshotConflictHorizon = snapshotConflictHorizon;
xlrec.ntuples = ndeletable;
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 8f1c11a..b11dba8 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2428,6 +2428,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));
@@ -6654,6 +6656,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 6beeb69..54b4a5a 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -2058,6 +2058,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;
@@ -2182,7 +2183,9 @@ log_heap_prune_and_freeze(Relation relation, Buffer buffer,
Assert((vmflags & VISIBILITYMAP_VALID_BITS) == vmflags);
- xlrec.flags = 0;
+ memset(&xlrec, 0, sizeof(xlrec));
+ memset(&freeze_plans, 0, sizeof(freeze_plans));
+
regbuf_flags_heap = REGBUF_STANDARD;
/*
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 6b19ac3..6c94ae1 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -842,6 +842,7 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
else
dboid = MyDatabaseId;
+ memset(&xlrec, 0, sizeof(xlrec));
xlrec.num_mappings = num_mappings;
xlrec.mapped_rel = RelationGetRelid(state->rs_old_rel);
xlrec.mapped_xid = src->xid;
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 91bb37d..87ac75b 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1337,6 +1337,7 @@ _bt_insertonpg(Relation rel,
XLogRecPtr recptr;
uint16 upostingoff;
+ memset(&xlmeta, 0, sizeof(xlmeta));
xlrec.offnum = newitemoff;
XLogBeginInsert();
@@ -2602,6 +2603,7 @@ _bt_newlevel(Relation rel, Relation heaprel, Buffer lbuf, Buffer rbuf)
XLogRecPtr recptr;
xl_btree_metadata md;
+ 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 9aa7806..1fb6ced 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -288,6 +288,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);
@@ -476,6 +477,7 @@ _bt_getroot(Relation rel, Relation heaprel, int access)
XLogRecPtr recptr;
xl_btree_metadata md;
+ memset(&md, 0, sizeof(md));
XLogBeginInsert();
XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT);
XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD);
@@ -2255,6 +2257,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)
@@ -2678,6 +2681,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 7c7371c..4cc4768 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -403,6 +403,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);
@@ -710,6 +712,8 @@ doPickSplit(Relation index, SpGistState *state,
nToInsert,
maxToInclude;
+ memset(&xlrec, 0, sizeof(xlrec));
+
in.level = level;
/*
@@ -1514,6 +1518,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));
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index 6b7117b..9e6acb8 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/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 55b9f38..4406e34 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1040,6 +1040,9 @@ save_state_data(const void *data, uint32 len)
}
memcpy(records.tail->data + records.tail->len, data, len);
+ /* Zero MAXALIGN padding to avoid uninitialized bytes in WAL */
+ if (padlen > len)
+ memset(records.tail->data + records.tail->len + len, 0, padlen - len);
records.tail->len += padlen;
records.bytes_free -= padlen;
records.total_len += padlen;
@@ -1077,6 +1080,7 @@ StartPrepare(GlobalTransaction gxact)
records.total_len = 0;
/* Create header */
+ memset(&hdr, 0, sizeof(hdr));
hdr.magic = TWOPHASE_MAGIC;
hdr.total_len = 0; /* EndPrepare will fill this in */
hdr.xid = xid;
@@ -1275,6 +1279,7 @@ RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info,
{
TwoPhaseRecordOnDisk record;
+ memset(&record, 0, sizeof(record));
record.rmid = rmid;
record.info = info;
record.len = len;
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b9b678f..f5b3616 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5149,6 +5149,7 @@ BootStrapXLOG(uint32 data_checksum_version)
* segment with logid=0 logseg=1. The very first WAL segment, 0/0, is not
* used, so that we can use 0/0 to mean "before any valid WAL segment".
*/
+ memset(&checkPoint, 0, sizeof(checkPoint));
checkPoint.redo = wal_segment_size + SizeOfXLogLongPHD;
checkPoint.ThisTimeLineID = BootstrapTimeLineID;
checkPoint.PrevTimeLineID = BootstrapTimeLineID;
@@ -8252,6 +8253,7 @@ XLogReportParameters(void)
xl_parameter_change xlrec;
XLogRecPtr recptr;
+ memset(&xlrec, 0, sizeof(xlrec));
xlrec.MaxConnections = MaxConnections;
xlrec.max_worker_processes = max_worker_processes;
xlrec.max_wal_senders = max_wal_senders;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cd6d720..9b5ab9c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2318,6 +2318,8 @@ ExecuteTruncateGuts(List *explicit_rels,
xl_heap_truncate xlrec;
int i = 0;
+ memset(&xlrec, 0, sizeof(xlrec));
+
/* should only get here if effective_wal_level is 'logical' */
Assert(XLogLogicalInfoActive());
diff --git a/src/backend/replication/logical/message.c b/src/backend/replication/logical/message.c
index 06825d6..64a41c3 100644
--- a/src/backend/replication/logical/message.c
+++ b/src/backend/replication/logical/message.c
@@ -46,6 +46,8 @@ LogLogicalMessage(const char *prefix, const char *message, size_t size,
xl_logical_message xlrec;
XLogRecPtr lsn;
+ memset(&xlrec, 0, sizeof(xlrec));
+
/*
* Force xid to be allocated if we're emitting a transactional message.
*/
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 26afd8f..df971f5 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -1011,6 +1011,7 @@ replorigin_advance(ReplOriginId node,
{
xl_replorigin_set xlrec;
+ memset(&xlrec, 0, sizeof(xlrec));
xlrec.remote_lsn = remote_commit;
xlrec.node_id = node;
xlrec.force = go_backward;
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index f3ad90c..4ae5be2 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -1357,6 +1357,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/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c
index bc8c43b..25d329e 100644
--- a/src/backend/utils/activity/pgstat_relation.c
+++ b/src/backend/utils/activity/pgstat_relation.c
@@ -695,6 +695,7 @@ AtPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state)
PgStat_TableStatus *tabstat PG_USED_FOR_ASSERTS_ONLY;
TwoPhasePgStatRecord record;
+ memset(&record, 0, sizeof(record));
Assert(trans->nest_level == 1);
Assert(trans->upper == NULL);
tabstat = trans->parent;
diff --git a/src/tools/valgrind.supp b/src/tools/valgrind.supp
index d56794b..f2ab0c8 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
[text/x-patch] hash-vacuum-one-page-test.patch (2.0K, 4-hash-vacuum-one-page-test.patch)
download | inline diff:
diff --git a/src/test/regress/expected/hash_index.out b/src/test/regress/expected/hash_index.out
index 0403540..258d501 100644
--- a/src/test/regress/expected/hash_index.out
+++ b/src/test/regress/expected/hash_index.out
@@ -333,6 +333,25 @@ ROLLBACK;
INSERT INTO hash_cleanup_heap SELECT 1 FROM generate_series(1, 50) as i;
CHECKPOINT;
VACUUM hash_cleanup_heap;
+-- Test insert-driven cleanup of dead index tuples (_hash_vacuum_one_page).
+TRUNCATE hash_cleanup_heap;
+INSERT INTO hash_cleanup_heap SELECT 1 FROM generate_series(1, 1000) as i;
+DELETE FROM hash_cleanup_heap
+ WHERE ctid IN ('(0,5)','(0,10)','(0,15)','(0,20)','(0,25)',
+ '(0,30)','(0,35)','(0,40)','(0,45)','(0,50)');
+SET enable_seqscan = off;
+SET enable_bitmapscan = off;
+SELECT count(*) FROM hash_cleanup_heap WHERE keycol = 1;
+ count
+-------
+ 990
+(1 row)
+
+INSERT INTO hash_cleanup_heap SELECT 1 FROM generate_series(1, 200) as i;
+RESET enable_seqscan;
+RESET enable_bitmapscan;
-- Clean up.
DROP TABLE hash_cleanup_heap;
-- Index on temp table.
diff --git a/src/test/regress/sql/hash_index.sql b/src/test/regress/sql/hash_index.sql
index 60571f6..1c85d98 100644
--- a/src/test/regress/sql/hash_index.sql
+++ b/src/test/regress/sql/hash_index.sql
@@ -314,6 +314,21 @@ INSERT INTO hash_cleanup_heap SELECT 1 FROM generate_series(1, 50) as i;
CHECKPOINT;
VACUUM hash_cleanup_heap;
+-- Test insert-driven cleanup of dead index tuples (_hash_vacuum_one_page).
+TRUNCATE hash_cleanup_heap;
+INSERT INTO hash_cleanup_heap SELECT 1 FROM generate_series(1, 1000) as i;
+DELETE FROM hash_cleanup_heap
+ WHERE ctid IN ('(0,5)','(0,10)','(0,15)','(0,20)','(0,25)',
+ '(0,30)','(0,35)','(0,40)','(0,45)','(0,50)');
+SET enable_seqscan = off;
+SET enable_bitmapscan = off;
+SELECT count(*) FROM hash_cleanup_heap WHERE keycol = 1;
+INSERT INTO hash_cleanup_heap SELECT 1 FROM generate_series(1, 200) as i;
+RESET enable_seqscan;
+RESET enable_bitmapscan;
+
-- Clean up.
DROP TABLE hash_cleanup_heap;
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-17 12:43 Bertrand Drouvot <[email protected]>
parent: Alexander Kuzmenkov <[email protected]>
1 sibling, 1 reply; 16+ messages in thread
From: Bertrand Drouvot @ 2026-03-17 12:43 UTC (permalink / raw)
To: Alexander Kuzmenkov <[email protected]>; +Cc: Heikki Linnakangas <[email protected]>; Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
Hi,
On Mon, Mar 16, 2026 at 05:14:10PM +0100, Alexander Kuzmenkov wrote:
> I have removed the unnecessary memsets (for structs with no padding). With
> these changes, and removing the two WAL-related suppressions, the make
> installcheck under Valgrind passes.
Thanks for the patch!
Without the memset part of the patch, I got valgrind's things like:
214 heap_multi_insert (heapam.c:2425)
149 heap_inplace_update_and_unlock (heapam.c:6592)
5 palloc (mcxt.c:1411)
3 _bt_getroot (nbtpage.c:348)
2 log_heap_prune_and_freeze (pruneheap.c:2171)
2 LogCurrentRunningXacts (standby.c:1356)
1 vacuumRedirectAndPlaceholder (spgvacuum.c:495)
1 _bt_set_cleanup_info (nbtpage.c:234)
1 ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
and none with the patch applied. So the proposed changes look good to me.
One comment regarding the new memset(s) in the patch, I wonder if we should:
1/ Add a comment on top of them explaining why we are doing this and why
we don't use {0} (cf. Andres's point about C23 up-thread)
or
2/ Create a new macro, say INITIALIZE_PADDING or such with the comment on
top of it. That way, we could do things like:
+ INITIALIZE_PADDING(xlrec);
instead of
+ memset(&xlrec, 0, sizeof(xlrec));
I think that it would make the intent more clear and we could switch to {0} in a
single place (if we feel the need) once C23 is required.
Regards,
--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-17 18:45 Zsolt Parragi <[email protected]>
parent: Bertrand Drouvot <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Zsolt Parragi @ 2026-03-17 18:45 UTC (permalink / raw)
To: Bertrand Drouvot <[email protected]>; +Cc: Alexander Kuzmenkov <[email protected]>; Heikki Linnakangas <[email protected]>; Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Michael Paquier <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
Hello!
I'd like to propose a different approach: instead of relying on
valgrind and runtime detection of the issue, why don't we (also) add
specific static analysis rules to detect the situation at compile
time?
There are several threads when I had the same idea: maybe I should
write a postgres specific clang-tidy checker, and ask what everyone
thinks about integrating that into the build process in an optional
way?
I attached a WIP patch that addresses this, specifically for the xlog
padding problem for now.
src/tools/pg-tidy contains a basic custom clang-tidy plugin that works
based on two annotations (and helper macros that resolve to "" for
normal compilation):
* PG_NOPADDING can be used to mark that a struct doesn't have any
padding. If this annotation is added to a struct, but it has padding,
it will generate clang-tidy warnings. This is basically "-Wpadded",
but specifically for selected types.
* A separate check rule requires all PG_NOPADDING structs to be always
zero-initialized, meaning we don't have to rely on memset at all
* PG_REQUIRE_NOPADDING can be used to mark function arguments. If an
argument is marked with this, then the underlying type of its
parameter has to be either a primitive type, or a struct annotated
with PG_NOPADDING
Possible alternatives:
* I could simplify this by removing PG_NOPADDING, and instead checking
the requirement at every call site of a function with
PG_REQUIRE_NOPADDING. That would also mean that it could only enforce
zero-initialization when it's clearly visible in the same function. I
choose the two annotation approach for increased reliability
* I could simplify this to only check for end padding, enforce memset
instead of zero initialization, and build upon Alexander's previous
patch.
0001 implements and integrates pg-tidy (I only added it to the meson
build, if there's interest I can also add it to make. clang-tidy
integration works similarly to the llvm bitcode patch, so it is
properly parallelized/incremental)
0002 adds basic helper macros
0003 marks the data in XLogRegisterData with PG_REQUIRE_NOPADDING, all
related structs with PG_NOPADDING, and then fixes the padding issues
by adding explicit padding data instead of the compiler autogenerated
padding. We also cast a few arrays to char* (or alternatively we could
use nolint to suppress the check), because I didn't want to everywhere
zero initialize types like RelFileLocator.
0004 removes the now trivial SizeOf macros
Compared to only using valgrind, clang-tidy:
* works at compile time, guaranteed for every type used with xlog
* in theory should work with extensions (if we want to, e.g. by
integrating it into pgxs), without requiring extension developers to
add proper test workflows using valgrind
* valgrind should still work
What do you think? I'm interested in opinions about both the specific
case, and the generic idea of using custom clang-tidy checks for
various postgres-specific checks. As I mentioned at the beginning of
the message I think this could be useful for other things and doesn't
always require custom annotations, in several cases it could work
without any C code change.
Attachments:
[application/octet-stream] 0004-Remove-trivial-SizeOfXXX-macros-that-are-just-sizeof.patch (43.9K, 2-0004-Remove-trivial-SizeOfXXX-macros-that-are-just-sizeof.patch)
download | inline diff:
From cd4a4373a1c07d03e47303288bdb92f52ec58d4b Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <[email protected]>
Date: Tue, 17 Mar 2026 18:14:35 +0000
Subject: [PATCH 4/4] Remove trivial SizeOfXXX macros that are just
sizeof(type)
Now that WAL record structs have explicit padding, the SizeOfXXX macros
that previously used offsetof() to skip trailing padding are plain
sizeof() aliases. Replace all usages with direct sizeof() calls for
clarity, as sizeof(type) is self-documenting at the call site.
Macros using offsetof() (for flexible array members), MAXALIGN, or
arithmetic are kept as they carry additional semantics.
---
src/backend/access/brin/brin.c | 2 +-
src/backend/access/brin/brin_pageops.c | 6 ++---
src/backend/access/brin/brin_revmap.c | 4 ++--
src/backend/access/gist/gistxlog.c | 4 ++--
src/backend/access/hash/hash.c | 4 ++--
src/backend/access/hash/hashinsert.c | 2 +-
src/backend/access/hash/hashovfl.c | 6 ++---
src/backend/access/hash/hashpage.c | 8 +++----
src/backend/access/heap/heapam.c | 30 ++++++++++++------------
src/backend/access/heap/heapam_xlog.c | 18 +++++++-------
src/backend/access/heap/pruneheap.c | 2 +-
src/backend/access/nbtree/nbtdedup.c | 2 +-
src/backend/access/nbtree/nbtinsert.c | 6 ++---
src/backend/access/nbtree/nbtpage.c | 18 +++++++-------
src/backend/access/nbtree/nbtxlog.c | 4 ++--
src/backend/access/rmgrdesc/heapdesc.c | 2 +-
src/backend/access/rmgrdesc/nbtdesc.c | 4 ++--
src/backend/access/rmgrdesc/xactdesc.c | 2 +-
src/backend/access/transam/commit_ts.c | 2 +-
src/backend/access/transam/multixact.c | 4 ++--
src/backend/access/transam/xact.c | 2 +-
src/backend/access/transam/xloginsert.c | 4 ++--
src/backend/replication/logical/decode.c | 26 ++++++++++----------
src/include/access/brin_xlog.h | 6 -----
src/include/access/commit_ts.h | 1 -
src/include/access/gistxlog.h | 2 --
src/include/access/hash_xlog.h | 10 --------
src/include/access/heapam_xlog.h | 11 ---------
src/include/access/multixact.h | 1 -
src/include/access/nbtxlog.h | 10 --------
src/include/access/xact.h | 1 -
src/include/access/xlogrecord.h | 3 +--
32 files changed, 82 insertions(+), 125 deletions(-)
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 8ef44a0075b..e4cf698b649 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1143,7 +1143,7 @@ brinbuild(Relation heap, Relation index, IndexInfo *indexInfo)
xlrec.pagesPerRange = BrinGetPagesPerRange(index);
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfBrinCreateIdx);
+ XLogRegisterData(&xlrec, sizeof(xl_brin_createidx));
XLogRegisterBuffer(0, meta, REGBUF_WILL_INIT | REGBUF_STANDARD);
recptr = XLogInsert(RM_BRIN_ID, XLOG_BRIN_CREATE_INDEX);
diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c
index a1e8bd0e225..4f0160250ff 100644
--- a/src/backend/access/brin/brin_pageops.c
+++ b/src/backend/access/brin/brin_pageops.c
@@ -190,7 +190,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
xlrec.offnum = oldoff;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfBrinSamepageUpdate);
+ XLogRegisterData(&xlrec, sizeof(xl_brin_samepage_update));
XLogRegisterBuffer(0, oldbuf, REGBUF_STANDARD);
XLogRegisterBufData(0, newtup, newsz);
@@ -281,7 +281,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
XLogBeginInsert();
/* new page */
- XLogRegisterData(&xlrec, SizeOfBrinUpdate);
+ XLogRegisterData(&xlrec, sizeof(xl_brin_update));
XLogRegisterBuffer(0, newbuf, REGBUF_STANDARD | (extended ? REGBUF_WILL_INIT : 0));
XLogRegisterBufData(0, newtup, newsz);
@@ -433,7 +433,7 @@ brin_doinsert(Relation idxrel, BlockNumber pagesPerRange,
xlrec.offnum = off;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfBrinInsert);
+ XLogRegisterData(&xlrec, sizeof(xl_brin_insert));
XLogRegisterBuffer(0, *buffer, REGBUF_STANDARD | (extended ? REGBUF_WILL_INIT : 0));
XLogRegisterBufData(0, tup, itemsz);
diff --git a/src/backend/access/brin/brin_revmap.c b/src/backend/access/brin/brin_revmap.c
index 57ac044497a..ee013bdd167 100644
--- a/src/backend/access/brin/brin_revmap.c
+++ b/src/backend/access/brin/brin_revmap.c
@@ -416,7 +416,7 @@ brinRevmapDesummarizeRange(Relation idxrel, BlockNumber heapBlk)
xlrec.regOffset = regOffset;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfBrinDesummarize);
+ XLogRegisterData(&xlrec, sizeof(xl_brin_desummarize));
XLogRegisterBuffer(0, revmapBuf, 0);
XLogRegisterBuffer(1, regBuf, REGBUF_STANDARD);
recptr = XLogInsert(RM_BRIN_ID, XLOG_BRIN_DESUMMARIZE);
@@ -627,7 +627,7 @@ revmap_physical_extend(BrinRevmap *revmap)
xlrec.targetBlk = mapBlk;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfBrinRevmapExtend);
+ XLogRegisterData(&xlrec, sizeof(xl_brin_revmap_extend));
XLogRegisterBuffer(0, revmap->rm_metaBuf, REGBUF_STANDARD);
XLogRegisterBuffer(1, buf, REGBUF_WILL_INIT);
diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c
index b93e831b829..194a7f8ab34 100644
--- a/src/backend/access/gist/gistxlog.c
+++ b/src/backend/access/gist/gistxlog.c
@@ -557,7 +557,7 @@ gistXLogPageDelete(Buffer buffer, FullTransactionId xid,
xlrec.downlinkOffset = downlinkOffset;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfGistxlogPageDelete);
+ XLogRegisterData(&xlrec, sizeof(gistxlogPageDelete));
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
XLogRegisterBuffer(1, parentBuffer, REGBUF_STANDARD);
@@ -607,7 +607,7 @@ gistXLogPageReuse(Relation rel, Relation heaprel,
xlrec_reuse.snapshotConflictHorizon = deleteXid;
XLogBeginInsert();
- XLogRegisterData(&xlrec_reuse, SizeOfGistxlogPageReuse);
+ XLogRegisterData(&xlrec_reuse, sizeof(gistxlogPageReuse));
XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_REUSE);
}
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index f565cfc77a8..d4e3b4c54a3 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -619,7 +619,7 @@ loop_top:
xlrec.ntuples = metap->hashm_ntuples;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashUpdateMetaPage);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_update_meta_page));
XLogRegisterBuffer(0, metabuf, REGBUF_STANDARD);
@@ -826,7 +826,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
xlrec.is_primary_bucket_page = (buf == bucket_buf);
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashDelete);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_delete));
/*
* bucket buffer was not changed, but still needs to be
diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c
index 5ba623393a8..37d6e3a86e4 100644
--- a/src/backend/access/hash/hashinsert.c
+++ b/src/backend/access/hash/hashinsert.c
@@ -221,7 +221,7 @@ restart_insert:
xlrec.offnum = itup_off;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashInsert);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_insert));
XLogRegisterBuffer(1, metabuf, REGBUF_STANDARD);
diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c
index 69e90ffac5b..89936095eff 100644
--- a/src/backend/access/hash/hashovfl.c
+++ b/src/backend/access/hash/hashovfl.c
@@ -388,7 +388,7 @@ found:
xlrec.bmsize = metap->hashm_bmsize;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashAddOvflPage);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_add_ovfl_page));
XLogRegisterBuffer(0, ovflbuf, REGBUF_WILL_INIT);
XLogRegisterBufData(0, &pageopaque->hasho_bucket, sizeof(Bucket));
@@ -656,7 +656,7 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
xlrec.is_prev_bucket_same_wrt = (wbuf == prevbuf);
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashSqueezePage);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_squeeze_page));
/*
* bucket buffer was not changed, but still needs to be registered to
@@ -993,7 +993,7 @@ readpage:
xlrec.is_prim_bucket_same_wrt = (wbuf == bucket_buf);
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashMovePageContents);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_move_page_contents));
/*
* bucket buffer was not changed, but still needs to
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 61a0badbfaa..4e766d256f7 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -394,7 +394,7 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
xlrec.ffactor = metap->hashm_ffactor;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashInitMetaPage);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_init_meta_page));
XLogRegisterBuffer(0, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD);
recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_INIT_META_PAGE);
@@ -468,7 +468,7 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
xlrec.bmsize = metap->hashm_bmsize;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashInitBitmapPage);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_init_bitmap_page));
XLogRegisterBuffer(0, bitmapbuf, REGBUF_WILL_INIT);
/*
@@ -930,7 +930,7 @@ restart_expand:
sizeof(uint32));
}
- XLogRegisterData(&xlrec, SizeOfHashSplitAllocPage);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_split_allocate_page));
recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_SPLIT_ALLOCATE_PAGE);
@@ -1304,7 +1304,7 @@ _hash_splitbucket(Relation rel,
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHashSplitComplete);
+ XLogRegisterData(&xlrec, sizeof(xl_hash_split_complete));
XLogRegisterBuffer(0, bucket_obuf, REGBUF_STANDARD);
XLogRegisterBuffer(1, bucket_nbuf, REGBUF_STANDARD);
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index c8b1ef7d372..4d43b33daea 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2268,7 +2268,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
}
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHeapInsert);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_insert));
xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
xlhdr.t_infomask = heaptup->t_data->t_infomask;
@@ -2280,7 +2280,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
* xl_heap_header in the xlog.
*/
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
- XLogRegisterBufData(0, &xlhdr, SizeOfHeapHeader);
+ XLogRegisterBufData(0, &xlhdr, sizeof(xl_heap_header));
/* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
XLogRegisterBufData(0,
(char *) heaptup->t_data + SizeofHeapTupleHeader,
@@ -2655,7 +2655,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
xlrec->offsets[i] = ItemPointerGetOffsetNumber(&heaptup->t_self);
/* xl_multi_insert_tuple needs two-byte alignment. */
tuphdr = (xl_multi_insert_tuple *) SHORTALIGN(scratchptr);
- scratchptr = ((char *) tuphdr) + SizeOfMultiInsertTuple;
+ scratchptr = ((char *) tuphdr) + sizeof(xl_multi_insert_tuple);
tuphdr->t_infomask2 = heaptup->t_data->t_infomask2;
tuphdr->t_infomask = heaptup->t_data->t_infomask;
@@ -3179,7 +3179,7 @@ l1:
}
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHeapDelete);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_delete));
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
@@ -3192,7 +3192,7 @@ l1:
xlhdr.t_infomask = old_key_tuple->t_data->t_infomask;
xlhdr.t_hoff = old_key_tuple->t_data->t_hoff;
- XLogRegisterData(&xlhdr, SizeOfHeapHeader);
+ XLogRegisterData(&xlhdr, sizeof(xl_heap_header));
XLogRegisterData((char *) old_key_tuple->t_data
+ SizeofHeapTupleHeader,
old_key_tuple->t_len
@@ -3960,7 +3960,7 @@ l2:
oldtup.t_data->t_infomask2);
xlrec.flags =
cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0;
- XLogRegisterData(&xlrec, SizeOfHeapLock);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_lock));
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK);
PageSetLSN(page, recptr);
}
@@ -5294,7 +5294,7 @@ failed:
xlrec.infobits_set = compute_infobits(new_infomask,
tuple->t_data->t_infomask2);
xlrec.flags = cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0;
- XLogRegisterData(&xlrec, SizeOfHeapLock);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_lock));
/* we don't decode row locks atm, so no need to log the origin */
@@ -6047,7 +6047,7 @@ l4:
xlrec.flags =
cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0;
- XLogRegisterData(&xlrec, SizeOfHeapLockUpdated);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_lock_updated));
recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_LOCK_UPDATED);
@@ -6211,7 +6211,7 @@ heap_finish_speculative(Relation relation, const ItemPointerData *tid)
/* We want the same filtering on this as on a plain insert */
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
- XLogRegisterData(&xlrec, SizeOfHeapConfirm);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_confirm));
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CONFIRM);
@@ -6356,7 +6356,7 @@ heap_abort_speculative(Relation relation, const ItemPointerData *tid)
xlrec.xmax = xid;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHeapDelete);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_delete));
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
/* No replica identity & replication origin logged */
@@ -8896,7 +8896,7 @@ log_heap_visible(Relation rel, Buffer heap_buffer, Buffer vm_buffer,
if (RelationIsAccessibleInLogicalDecoding(rel))
xlrec.flags |= VISIBILITYMAP_XLOG_CATALOG_REL;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHeapVisible);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_visible));
XLogRegisterBuffer(0, vm_buffer, 0);
@@ -9047,7 +9047,7 @@ log_heap_update(Relation reln, Buffer oldbuf,
if (oldbuf != newbuf)
XLogRegisterBuffer(1, oldbuf, REGBUF_STANDARD);
- XLogRegisterData(&xlrec, SizeOfHeapUpdate);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_update));
/*
* Prepare WAL data for the new tuple.
@@ -9080,7 +9080,7 @@ log_heap_update(Relation reln, Buffer oldbuf,
*
* The 'data' doesn't include the common prefix or suffix.
*/
- XLogRegisterBufData(0, &xlhdr, SizeOfHeapHeader);
+ XLogRegisterBufData(0, &xlhdr, sizeof(xl_heap_header));
if (prefixlen == 0)
{
XLogRegisterBufData(0,
@@ -9115,7 +9115,7 @@ log_heap_update(Relation reln, Buffer oldbuf,
xlhdr_idx.t_infomask = old_key_tuple->t_data->t_infomask;
xlhdr_idx.t_hoff = old_key_tuple->t_data->t_hoff;
- XLogRegisterData(&xlhdr_idx, SizeOfHeapHeader);
+ XLogRegisterData(&xlhdr_idx, sizeof(xl_heap_header));
/* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
XLogRegisterData((char *) old_key_tuple->t_data + SizeofHeapTupleHeader,
@@ -9195,7 +9195,7 @@ log_heap_new_cid(Relation relation, HeapTuple tup)
* called us certainly did, but that's WAL-logged separately.
*/
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfHeapNewCid);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_new_cid));
/* will be looked at irrespective of origin */
diff --git a/src/backend/access/heap/heapam_xlog.c b/src/backend/access/heap/heapam_xlog.c
index 46fc689302d..ec901460191 100644
--- a/src/backend/access/heap/heapam_xlog.c
+++ b/src/backend/access/heap/heapam_xlog.c
@@ -40,8 +40,8 @@ heap_xlog_prune_freeze(XLogReaderState *record)
Size freespace = 0;
XLogRecGetBlockTag(record, 0, &rlocator, NULL, &blkno);
- memcpy(&xlrec, maindataptr, SizeOfHeapPrune);
- maindataptr += SizeOfHeapPrune;
+ memcpy(&xlrec, maindataptr, sizeof(xl_heap_prune));
+ maindataptr += sizeof(xl_heap_prune);
/*
* We will take an ordinary exclusive lock or a cleanup lock depending on
@@ -559,10 +559,10 @@ heap_xlog_insert(XLogReaderState *record)
data = XLogRecGetBlockData(record, 0, &datalen);
- newlen = datalen - SizeOfHeapHeader;
- Assert(datalen > SizeOfHeapHeader && newlen <= MaxHeapTupleSize);
- memcpy(&xlhdr, data, SizeOfHeapHeader);
- data += SizeOfHeapHeader;
+ newlen = datalen - sizeof(xl_heap_header);
+ Assert(datalen > sizeof(xl_heap_header) && newlen <= MaxHeapTupleSize);
+ memcpy(&xlhdr, data, sizeof(xl_heap_header));
+ data += sizeof(xl_heap_header);
htup = &tbuf.hdr;
MemSet(htup, 0, SizeofHeapTupleHeader);
@@ -697,7 +697,7 @@ heap_xlog_multi_insert(XLogReaderState *record)
elog(PANIC, "invalid max offset number");
xlhdr = (xl_multi_insert_tuple *) SHORTALIGN(tupdata);
- tupdata = ((char *) xlhdr) + SizeOfMultiInsertTuple;
+ tupdata = ((char *) xlhdr) + sizeof(xl_multi_insert_tuple);
newlen = xlhdr->datalen;
Assert(newlen <= MaxHeapTupleSize);
@@ -978,8 +978,8 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
recdata += sizeof(uint16);
}
- memcpy(&xlhdr, recdata, SizeOfHeapHeader);
- recdata += SizeOfHeapHeader;
+ memcpy(&xlhdr, recdata, sizeof(xl_heap_header));
+ recdata += sizeof(xl_heap_header);
tuplen = recdata_end - recdata;
Assert(tuplen <= MaxHeapTupleSize);
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index d609b63ef97..962ab79f62c 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -2291,7 +2291,7 @@ log_heap_prune_and_freeze(Relation relation, Buffer buffer,
Assert(nredirected == 0 && ndead == 0);
/* also, any items in 'unused' must've been LP_DEAD previously */
}
- XLogRegisterData(&xlrec, SizeOfHeapPrune);
+ XLogRegisterData(&xlrec, sizeof(xl_heap_prune));
if (TransactionIdIsValid(conflict_xid))
XLogRegisterData(&conflict_xid, sizeof(TransactionId));
diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c
index e20590a5547..6a5b15e6ee2 100644
--- a/src/backend/access/nbtree/nbtdedup.c
+++ b/src/backend/access/nbtree/nbtdedup.c
@@ -252,7 +252,7 @@ _bt_dedup_pass(Relation rel, Buffer buf, IndexTuple newitem, Size newitemsz,
XLogBeginInsert();
XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
- XLogRegisterData(&xlrec_dedup, SizeOfBtreeDedup);
+ XLogRegisterData(&xlrec_dedup, sizeof(xl_btree_dedup));
/*
* The intervals array is not in the buffer, but pretend that it is.
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 71a62b06692..fd2c374cd6d 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1328,7 +1328,7 @@ _bt_insertonpg(Relation rel,
xlrec.offnum = newitemoff;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfBtreeInsert);
+ XLogRegisterData(&xlrec, sizeof(xl_btree_insert));
if (isleaf && postingoff == 0)
{
@@ -1994,7 +1994,7 @@ _bt_split(Relation rel, Relation heaprel, BTScanInsert itup_key, Buffer buf,
xlrec.postingoff = postingoff;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfBtreeSplit);
+ XLogRegisterData(&xlrec, sizeof(xl_btree_split));
XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
XLogRegisterBuffer(1, rbuf, REGBUF_WILL_INIT);
@@ -2578,7 +2578,7 @@ _bt_newlevel(Relation rel, Relation heaprel, Buffer lbuf, Buffer rbuf)
xlrec.level = metad->btm_level;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfBtreeNewroot);
+ XLogRegisterData(&xlrec, sizeof(xl_btree_newroot));
XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT);
XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD);
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 80f9ec2c846..40d55834633 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -494,7 +494,7 @@ _bt_getroot(Relation rel, Relation heaprel, int access)
xlrec.rootblk = rootblkno;
xlrec.level = 0;
- XLogRegisterData(&xlrec, SizeOfBtreeNewroot);
+ XLogRegisterData(&xlrec, sizeof(xl_btree_newroot));
recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT);
@@ -949,7 +949,7 @@ _bt_allocbuf(Relation rel, Relation heaprel)
RelationIsAccessibleInLogicalDecoding(heaprel);
XLogBeginInsert();
- XLogRegisterData(&xlrec_reuse, SizeOfBtreeReusePage);
+ XLogRegisterData(&xlrec_reuse, sizeof(xl_btree_reuse_page));
XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE);
}
@@ -1234,7 +1234,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf,
XLogBeginInsert();
XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
- XLogRegisterData(&xlrec_vacuum, SizeOfBtreeVacuum);
+ XLogRegisterData(&xlrec_vacuum, sizeof(xl_btree_vacuum));
if (ndeletable > 0)
XLogRegisterBufData(0, deletable,
@@ -1352,7 +1352,7 @@ _bt_delitems_delete(Relation rel, Buffer buf,
XLogBeginInsert();
XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
- XLogRegisterData(&xlrec_delete, SizeOfBtreeDelete);
+ XLogRegisterData(&xlrec_delete, sizeof(xl_btree_delete));
if (ndeletable > 0)
XLogRegisterBufData(0, deletable,
@@ -1420,7 +1420,7 @@ _bt_delitems_update(BTVacuumPosting *updatable, int nupdatable,
_bt_update_posting(vacposting);
/* Keep track of size of xl_btree_update for updatedbuf in passing */
- itemsz = SizeOfBtreeUpdate + vacposting->ndeletedtids * sizeof(uint16);
+ itemsz = sizeof(xl_btree_update) + vacposting->ndeletedtids * sizeof(uint16);
buflen += itemsz;
/* Build updatedoffsets buffer in passing */
@@ -1443,8 +1443,8 @@ _bt_delitems_update(BTVacuumPosting *updatable, int nupdatable,
update.ndeletedtids = vacposting->ndeletedtids;
memcpy(updatedbuf + offset, &update.ndeletedtids,
- SizeOfBtreeUpdate);
- offset += SizeOfBtreeUpdate;
+ sizeof(xl_btree_update));
+ offset += sizeof(xl_btree_update);
itemsz = update.ndeletedtids * sizeof(uint16);
memcpy(updatedbuf + offset, vacposting->deletetids, itemsz);
@@ -2271,7 +2271,7 @@ _bt_mark_page_halfdead(Relation rel, Relation heaprel, Buffer leafbuf,
xlrec.leftblk = opaque->btpo_prev;
xlrec.rightblk = opaque->btpo_next;
- XLogRegisterData(&xlrec, SizeOfBtreeMarkPageHalfDead);
+ XLogRegisterData(&xlrec, sizeof(xl_btree_mark_page_halfdead));
recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_MARK_PAGE_HALFDEAD);
@@ -2698,7 +2698,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
xlrec.leafrightsib = leafrightsib;
xlrec.leaftopparent = leaftopparent;
- XLogRegisterData(&xlrec, SizeOfBtreeUnlinkPage);
+ XLogRegisterData(&xlrec, sizeof(xl_btree_unlink_page));
if (BufferIsValid(metabuf))
{
diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c
index dff7d286fc8..62221d424bd 100644
--- a/src/backend/access/nbtree/nbtxlog.c
+++ b/src/backend/access/nbtree/nbtxlog.c
@@ -562,7 +562,7 @@ btree_xlog_updates(Page page, OffsetNumber *updatedoffsets,
vacposting->itup = origtuple;
vacposting->ndeletedtids = updates->ndeletedtids;
memcpy(vacposting->deletetids,
- (char *) updates + SizeOfBtreeUpdate,
+ (char *) updates + sizeof(xl_btree_update),
updates->ndeletedtids * sizeof(uint16));
_bt_update_posting(vacposting);
@@ -577,7 +577,7 @@ btree_xlog_updates(Page page, OffsetNumber *updatedoffsets,
/* advance to next xl_btree_update from array */
updates = (xl_btree_update *)
- ((char *) updates + SizeOfBtreeUpdate +
+ ((char *) updates + sizeof(xl_btree_update) +
updates->ndeletedtids * sizeof(uint16));
}
}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 02ae91653c1..e8fbf609d3a 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -278,7 +278,7 @@ heap2_desc(StringInfo buf, XLogReaderState *record)
{
TransactionId conflict_xid;
- memcpy(&conflict_xid, rec + SizeOfHeapPrune, sizeof(TransactionId));
+ memcpy(&conflict_xid, rec + sizeof(xl_heap_prune), sizeof(TransactionId));
appendStringInfo(buf, "snapshotConflictHorizon: %u",
conflict_xid);
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index 1d08f9957bd..00799a5f430 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -236,7 +236,7 @@ delvacuum_desc(StringInfo buf, char *block_data,
{
uint16 *ptid;
- ptid = (uint16 *) ((char *) updates + SizeOfBtreeUpdate) + p;
+ ptid = (uint16 *) ((char *) updates + sizeof(xl_btree_update)) + p;
appendStringInfo(buf, "%u", *ptid);
if (p < updates->ndeletedtids - 1)
@@ -247,7 +247,7 @@ delvacuum_desc(StringInfo buf, char *block_data,
appendStringInfoString(buf, ", ");
updates = (xl_btree_update *)
- ((char *) updates + SizeOfBtreeUpdate +
+ ((char *) updates + sizeof(xl_btree_update) +
updates->ndeletedtids * sizeof(uint16));
}
appendStringInfoChar(buf, ']');
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 5e9b08b1dac..0681e557257 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -140,7 +140,7 @@ ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *pars
void
ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
{
- char *data = ((char *) xlrec) + MinSizeOfXactAbort;
+ char *data = ((char *) xlrec) + sizeof(xl_xact_abort);
memset(parsed, 0, sizeof(*parsed));
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 55349042ed7..aaed461c9d5 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -972,7 +972,7 @@ WriteTruncateXlogRec(int64 pageno, TransactionId oldestXid)
xlrec.oldestXid = oldestXid;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfCommitTsTruncate);
+ XLogRegisterData(&xlrec, sizeof(xl_commit_ts_truncate));
(void) XLogInsert(RM_COMMIT_TS_ID, COMMIT_TS_TRUNCATE);
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index a005bbed209..f6577650056 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -2803,7 +2803,7 @@ WriteMTruncateXlogRec(Oid oldestMultiDB,
xlrec.oldestOffset = oldestOffset;
XLogBeginInsert();
- XLogRegisterData(&xlrec, SizeOfMultiXactTruncate);
+ XLogRegisterData(&xlrec, sizeof(xl_multixact_truncate));
recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
XLogFlush(recptr);
}
@@ -2868,7 +2868,7 @@ multixact_redo(XLogReaderState *record)
int64 pageno;
memcpy(&xlrec, XLogRecGetData(record),
- SizeOfMultiXactTruncate);
+ sizeof(xl_multixact_truncate));
elog(DEBUG1, "replaying multixact truncation: "
"oldestMulti %u (offsets segment %" PRIx64 "), "
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index df72a2566e6..97500b82ddd 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -6096,7 +6096,7 @@ XactLogAbortRecord(TimestampTz abort_time,
XLogBeginInsert();
- XLogRegisterData(&xlrec, MinSizeOfXactAbort);
+ XLogRegisterData(&xlrec, sizeof(xl_xact_abort));
if (xl_xinfo.xinfo != 0)
XLogRegisterData(&xl_xinfo, sizeof(xl_xinfo));
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index d1b6fbea81c..3c857b24bd9 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -838,8 +838,8 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
prev_regbuf = regbuf;
/* Ok, copy the header to the scratch buffer */
- memcpy(scratch, &bkpb, SizeOfXLogRecordBlockHeader);
- scratch += SizeOfXLogRecordBlockHeader;
+ memcpy(scratch, &bkpb, sizeof(XLogRecordBlockHeader));
+ scratch += sizeof(XLogRecordBlockHeader);
if (include_image)
{
memcpy(scratch, &bimg, SizeOfXLogRecordBlockImageHeader);
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 867cf9d0158..c2a7c1594b1 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -923,7 +923,7 @@ DecodeInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
memcpy(&change->data.tp.rlocator, &target_locator, sizeof(RelFileLocator));
tupledata = XLogRecGetBlockData(r, 0, &datalen);
- tuplelen = datalen - SizeOfHeapHeader;
+ tuplelen = datalen - sizeof(xl_heap_header);
change->data.tp.newtuple =
ReorderBufferAllocTupleBuf(ctx->reorder, tuplelen);
@@ -975,7 +975,7 @@ DecodeUpdate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
data = XLogRecGetBlockData(r, 0, &datalen);
- tuplelen = datalen - SizeOfHeapHeader;
+ tuplelen = datalen - sizeof(xl_heap_header);
change->data.tp.newtuple =
ReorderBufferAllocTupleBuf(ctx->reorder, tuplelen);
@@ -989,9 +989,9 @@ DecodeUpdate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
Size tuplelen;
/* caution, remaining data in record is not aligned */
- data = XLogRecGetData(r) + SizeOfHeapUpdate;
- datalen = XLogRecGetDataLen(r) - SizeOfHeapUpdate;
- tuplelen = datalen - SizeOfHeapHeader;
+ data = XLogRecGetData(r) + sizeof(xl_heap_update);
+ datalen = XLogRecGetDataLen(r) - sizeof(xl_heap_update);
+ tuplelen = datalen - sizeof(xl_heap_header);
change->data.tp.oldtuple =
ReorderBufferAllocTupleBuf(ctx->reorder, tuplelen);
@@ -1043,15 +1043,15 @@ DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
/* old primary key stored */
if (xlrec->flags & XLH_DELETE_CONTAINS_OLD)
{
- Size datalen = XLogRecGetDataLen(r) - SizeOfHeapDelete;
- Size tuplelen = datalen - SizeOfHeapHeader;
+ Size datalen = XLogRecGetDataLen(r) - sizeof(xl_heap_delete);
+ Size tuplelen = datalen - sizeof(xl_heap_header);
- Assert(XLogRecGetDataLen(r) > (SizeOfHeapDelete + SizeOfHeapHeader));
+ Assert(XLogRecGetDataLen(r) > (sizeof(xl_heap_delete) + sizeof(xl_heap_header)));
change->data.tp.oldtuple =
ReorderBufferAllocTupleBuf(ctx->reorder, tuplelen);
- DecodeXLogTuple((char *) xlrec + SizeOfHeapDelete,
+ DecodeXLogTuple((char *) xlrec + sizeof(xl_heap_delete),
datalen, change->data.tp.oldtuple);
}
@@ -1154,7 +1154,7 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
memcpy(&change->data.tp.rlocator, &rlocator, sizeof(RelFileLocator));
xlhdr = (xl_multi_insert_tuple *) SHORTALIGN(data);
- data = ((char *) xlhdr) + SizeOfMultiInsertTuple;
+ data = ((char *) xlhdr) + sizeof(xl_multi_insert_tuple);
datalen = xlhdr->datalen;
change->data.tp.newtuple =
@@ -1246,7 +1246,7 @@ static void
DecodeXLogTuple(char *data, Size len, HeapTuple tuple)
{
xl_heap_header xlhdr = {0};
- int datalen = len - SizeOfHeapHeader;
+ int datalen = len - sizeof(xl_heap_header);
HeapTupleHeader header;
Assert(datalen >= 0);
@@ -1261,12 +1261,12 @@ DecodeXLogTuple(char *data, Size len, HeapTuple tuple)
tuple->t_tableOid = InvalidOid;
/* data is not stored aligned, copy to aligned storage */
- memcpy(&xlhdr, data, SizeOfHeapHeader);
+ memcpy(&xlhdr, data, sizeof(xl_heap_header));
memset(header, 0, SizeofHeapTupleHeader);
memcpy(((char *) tuple->t_data) + SizeofHeapTupleHeader,
- data + SizeOfHeapHeader,
+ data + sizeof(xl_heap_header),
datalen);
header->t_infomask = xlhdr.t_infomask;
diff --git a/src/include/access/brin_xlog.h b/src/include/access/brin_xlog.h
index b22137970d3..56c22be801a 100644
--- a/src/include/access/brin_xlog.h
+++ b/src/include/access/brin_xlog.h
@@ -53,7 +53,6 @@ typedef struct PG_NO_PADDING xl_brin_createidx
uint16 version;
pg_padding_2(pg_pad);
} xl_brin_createidx;
-#define SizeOfBrinCreateIdx (sizeof(xl_brin_createidx))
/*
* This is what we need to know about a BRIN tuple insert
@@ -73,7 +72,6 @@ typedef struct PG_NO_PADDING xl_brin_insert
pg_padding_2(pg_pad);
} xl_brin_insert;
-#define SizeOfBrinInsert (sizeof(xl_brin_insert))
/*
* A cross-page update is the same as an insert, but also stores information
@@ -95,7 +93,6 @@ typedef struct PG_NO_PADDING xl_brin_update
xl_brin_insert insert;
} xl_brin_update;
-#define SizeOfBrinUpdate (sizeof(xl_brin_update))
/*
* This is what we need to know about a BRIN tuple samepage update
@@ -107,7 +104,6 @@ typedef struct PG_NO_PADDING xl_brin_samepage_update
OffsetNumber offnum;
} xl_brin_samepage_update;
-#define SizeOfBrinSamepageUpdate (sizeof(xl_brin_samepage_update))
/*
* This is what we need to know about a revmap extension
@@ -124,7 +120,6 @@ typedef struct PG_NO_PADDING xl_brin_revmap_extend
BlockNumber targetBlk;
} xl_brin_revmap_extend;
-#define SizeOfBrinRevmapExtend (sizeof(xl_brin_revmap_extend))
/*
* This is what we need to know about a range de-summarization
@@ -142,7 +137,6 @@ typedef struct PG_NO_PADDING xl_brin_desummarize
pg_padding_2(pg_pad);
} xl_brin_desummarize;
-#define SizeOfBrinDesummarize (sizeof(xl_brin_desummarize))
extern void brin_redo(XLogReaderState *record);
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 92e50b0c806..bd4358f8a5f 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -53,7 +53,6 @@ typedef struct PG_NO_PADDING xl_commit_ts_truncate
pg_padding_4(pg_pad);
} xl_commit_ts_truncate;
-#define SizeOfCommitTsTruncate (sizeof(xl_commit_ts_truncate))
extern void commit_ts_redo(XLogReaderState *record);
extern void commit_ts_desc(StringInfo buf, XLogReaderState *record);
diff --git a/src/include/access/gistxlog.h b/src/include/access/gistxlog.h
index f19d4e8dfe6..81af9dfb6cb 100644
--- a/src/include/access/gistxlog.h
+++ b/src/include/access/gistxlog.h
@@ -97,7 +97,6 @@ typedef struct PG_NO_PADDING gistxlogPageDelete
pg_padding_4(pg_pad2);
} gistxlogPageDelete;
-#define SizeOfGistxlogPageDelete (sizeof(gistxlogPageDelete))
/*
@@ -115,7 +114,6 @@ typedef struct PG_NO_PADDING gistxlogPageReuse
pg_padding_4(pg_pad4);
} gistxlogPageReuse;
-#define SizeOfGistxlogPageReuse (sizeof(gistxlogPageReuse))
extern void gist_redo(XLogReaderState *record);
extern void gist_desc(StringInfo buf, XLogReaderState *record);
diff --git a/src/include/access/hash_xlog.h b/src/include/access/hash_xlog.h
index bb6b9d0fe11..665fbbeb80a 100644
--- a/src/include/access/hash_xlog.h
+++ b/src/include/access/hash_xlog.h
@@ -64,7 +64,6 @@ typedef struct PG_NO_PADDING xl_hash_insert
OffsetNumber offnum;
} xl_hash_insert;
-#define SizeOfHashInsert (sizeof(xl_hash_insert))
/*
* This is what we need to know about addition of overflow page.
@@ -84,7 +83,6 @@ typedef struct PG_NO_PADDING xl_hash_add_ovfl_page
pg_padding_1(pg_pad);
} xl_hash_add_ovfl_page;
-#define SizeOfHashAddOvflPage (sizeof(xl_hash_add_ovfl_page))
/*
* This is what we need to know about allocating a page for split.
@@ -105,7 +103,6 @@ typedef struct PG_NO_PADDING xl_hash_split_allocate_page
pg_padding_2(pg_pad2);
} xl_hash_split_allocate_page;
-#define SizeOfHashSplitAllocPage (sizeof(xl_hash_split_allocate_page))
/*
* This is what we need to know about completing the split operation.
@@ -121,7 +118,6 @@ typedef struct PG_NO_PADDING xl_hash_split_complete
uint16 new_bucket_flag;
} xl_hash_split_complete;
-#define SizeOfHashSplitComplete (sizeof(xl_hash_split_complete))
/*
* This is what we need to know about move page contents required during
@@ -142,7 +138,6 @@ typedef struct PG_NO_PADDING xl_hash_move_page_contents
pg_padding_1(pg_pad);
} xl_hash_move_page_contents;
-#define SizeOfHashMovePageContents (sizeof(xl_hash_move_page_contents))
/*
* This is what we need to know about the squeeze page operation.
@@ -171,7 +166,6 @@ typedef struct PG_NO_PADDING xl_hash_squeeze_page
* page */
} xl_hash_squeeze_page;
-#define SizeOfHashSqueezePage (sizeof(xl_hash_squeeze_page))
/*
* This is what we need to know about the deletion of index tuples from a page.
@@ -189,7 +183,6 @@ typedef struct PG_NO_PADDING xl_hash_delete
* primary bucket page */
} xl_hash_delete;
-#define SizeOfHashDelete (sizeof(xl_hash_delete))
/*
* This is what we need for metapage update operation.
@@ -203,7 +196,6 @@ typedef struct PG_NO_PADDING xl_hash_update_meta_page
double ntuples;
} xl_hash_update_meta_page;
-#define SizeOfHashUpdateMetaPage (sizeof(xl_hash_update_meta_page))
/*
* This is what we need to initialize metapage.
@@ -220,7 +212,6 @@ typedef struct PG_NO_PADDING xl_hash_init_meta_page
pg_padding_2(pg_pad);
} xl_hash_init_meta_page;
-#define SizeOfHashInitMetaPage (sizeof(xl_hash_init_meta_page))
/*
* This is what we need to initialize bitmap page.
@@ -235,7 +226,6 @@ typedef struct PG_NO_PADDING xl_hash_init_bitmap_page
uint16 bmsize;
} xl_hash_init_bitmap_page;
-#define SizeOfHashInitBitmapPage (sizeof(xl_hash_init_bitmap_page))
/*
* This is what we need for index tuple deletion and to
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 74a3803ad14..ad8316fda2b 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -118,7 +118,6 @@ typedef struct PG_NO_PADDING xl_heap_delete
uint8 flags;
} xl_heap_delete;
-#define SizeOfHeapDelete sizeof(xl_heap_delete)
/*
* xl_heap_truncate flag values, 8 bits are available.
@@ -157,7 +156,6 @@ typedef struct PG_NO_PADDING xl_heap_header
pg_padding_1(pg_pad);
} xl_heap_header;
-#define SizeOfHeapHeader sizeof(xl_heap_header)
/* This is what we need to know about insert */
typedef struct PG_NO_PADDING xl_heap_insert
@@ -169,7 +167,6 @@ typedef struct PG_NO_PADDING xl_heap_insert
/* xl_heap_header & TUPLE DATA in backup block 0 */
} xl_heap_insert;
-#define SizeOfHeapInsert sizeof(xl_heap_insert)
/*
* This is what we need to know about a multi-insert.
@@ -202,7 +199,6 @@ typedef struct PG_NO_PADDING xl_multi_insert_tuple
/* TUPLE DATA FOLLOWS AT END OF STRUCT */
} xl_multi_insert_tuple;
-#define SizeOfMultiInsertTuple sizeof(xl_multi_insert_tuple)
/*
* This is what we need to know about update|hot_update
@@ -237,7 +233,6 @@ typedef struct PG_NO_PADDING xl_heap_update
*/
} xl_heap_update;
-#define SizeOfHeapUpdate sizeof(xl_heap_update)
/*
* These structures and flags encode VACUUM pruning and freezing and on-access
@@ -299,7 +294,6 @@ typedef struct PG_NO_PADDING xl_heap_prune
*/
} xl_heap_prune;
-#define SizeOfHeapPrune sizeof(xl_heap_prune)
/* to handle recovery conflict during logical decoding on standby */
#define XLHP_IS_CATALOG_REL (1 << 1)
@@ -418,7 +412,6 @@ typedef struct PG_NO_PADDING xl_heap_lock
uint8 flags; /* XLH_LOCK_* flag bits */
} xl_heap_lock;
-#define SizeOfHeapLock sizeof(xl_heap_lock)
/* This is what we need to know about locking an updated version of a row */
typedef struct PG_NO_PADDING xl_heap_lock_updated
@@ -429,7 +422,6 @@ typedef struct PG_NO_PADDING xl_heap_lock_updated
uint8 flags;
} xl_heap_lock_updated;
-#define SizeOfHeapLockUpdated sizeof(xl_heap_lock_updated)
/* This is what we need to know about confirmation of speculative insertion */
typedef struct PG_NO_PADDING xl_heap_confirm
@@ -437,7 +429,6 @@ typedef struct PG_NO_PADDING xl_heap_confirm
OffsetNumber offnum; /* confirmed tuple's offset on page */
} xl_heap_confirm;
-#define SizeOfHeapConfirm sizeof(xl_heap_confirm)
/* This is what we need to know about in-place update */
typedef struct PG_NO_PADDING xl_heap_inplace
@@ -469,7 +460,6 @@ typedef struct PG_NO_PADDING xl_heap_visible
pg_padding_2(pg_pad2);
} xl_heap_visible;
-#define SizeOfHeapVisible sizeof(xl_heap_visible)
typedef struct PG_NO_PADDING xl_heap_new_cid
{
@@ -490,7 +480,6 @@ typedef struct PG_NO_PADDING xl_heap_new_cid
pg_padding_2(pg_pad);
} xl_heap_new_cid;
-#define SizeOfHeapNewCid sizeof(xl_heap_new_cid)
/* logical rewrite xlog record header */
typedef struct PG_NO_PADDING xl_heap_rewrite_mapping
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 3fe4501d27f..06aa4632760 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -92,7 +92,6 @@ typedef struct PG_NO_PADDING xl_multixact_truncate
MultiXactOffset oldestOffset;
} xl_multixact_truncate;
-#define SizeOfMultiXactTruncate (sizeof(xl_multixact_truncate))
extern MultiXactId MultiXactIdCreate(TransactionId xid1,
diff --git a/src/include/access/nbtxlog.h b/src/include/access/nbtxlog.h
index 8918d675dce..1a6cfd3dfbf 100644
--- a/src/include/access/nbtxlog.h
+++ b/src/include/access/nbtxlog.h
@@ -86,7 +86,6 @@ typedef struct PG_NO_PADDING xl_btree_insert
/* NEW TUPLE ALWAYS FOLLOWS AT THE END */
} xl_btree_insert;
-#define SizeOfBtreeInsert sizeof(xl_btree_insert)
/*
* On insert with split, we save all the items going into the right sibling
@@ -161,7 +160,6 @@ typedef struct PG_NO_PADDING xl_btree_split
pg_padding_2(pg_pad);
} xl_btree_split;
-#define SizeOfBtreeSplit sizeof(xl_btree_split)
/*
* When page is deduplicated, consecutive groups of tuples with equal keys are
@@ -177,7 +175,6 @@ typedef struct PG_NO_PADDING xl_btree_dedup
/* DEDUPLICATION INTERVALS FOLLOW */
} xl_btree_dedup;
-#define SizeOfBtreeDedup sizeof(xl_btree_dedup)
/*
* This is what we need to know about page reuse within btree. This record
@@ -198,7 +195,6 @@ typedef struct PG_NO_PADDING xl_btree_reuse_page
pg_padding_4(pg_pad4);
} xl_btree_reuse_page;
-#define SizeOfBtreeReusePage sizeof(xl_btree_reuse_page)
/*
* xl_btree_vacuum and xl_btree_delete records describe deletion of index
@@ -240,7 +236,6 @@ typedef struct PG_NO_PADDING xl_btree_vacuum
*/
} xl_btree_vacuum;
-#define SizeOfBtreeVacuum sizeof(xl_btree_vacuum)
typedef struct PG_NO_PADDING xl_btree_delete
{
@@ -261,7 +256,6 @@ typedef struct PG_NO_PADDING xl_btree_delete
*/
} xl_btree_delete;
-#define SizeOfBtreeDelete sizeof(xl_btree_delete)
/*
* The offsets that appear in xl_btree_update metadata are offsets into the
@@ -276,7 +270,6 @@ typedef struct PG_NO_PADDING xl_btree_update
/* POSTING LIST uint16 OFFSETS TO A DELETED TID FOLLOW */
} xl_btree_update;
-#define SizeOfBtreeUpdate sizeof(xl_btree_update)
/*
* This is what we need to know about marking an empty subtree for deletion.
@@ -300,7 +293,6 @@ typedef struct PG_NO_PADDING xl_btree_mark_page_halfdead
BlockNumber topparent; /* topmost internal page in the subtree */
} xl_btree_mark_page_halfdead;
-#define SizeOfBtreeMarkPageHalfDead sizeof(xl_btree_mark_page_halfdead)
/*
* This is what we need to know about deletion of a btree page. Note that we
@@ -339,7 +331,6 @@ typedef struct PG_NO_PADDING xl_btree_unlink_page
/* xl_btree_metadata FOLLOWS IF XLOG_BTREE_UNLINK_PAGE_META */
} xl_btree_unlink_page;
-#define SizeOfBtreeUnlinkPage sizeof(xl_btree_unlink_page)
/*
* New root log record. There are zero tuples if this is to establish an
@@ -358,7 +349,6 @@ typedef struct PG_NO_PADDING xl_btree_newroot
uint32 level; /* its tree level */
} xl_btree_newroot;
-#define SizeOfBtreeNewroot sizeof(xl_btree_newroot)
/*
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index d9617b235bd..082e3760cfc 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -348,7 +348,6 @@ typedef struct PG_NO_PADDING xl_xact_abort
/* twophase_gid follows if XINFO_HAS_GID. As a null-terminated string. */
/* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */
} xl_xact_abort;
-#define MinSizeOfXactAbort sizeof(xl_xact_abort)
typedef struct xl_xact_prepare
{
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index 8c74998607d..3da0e3a4078 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -112,7 +112,6 @@ typedef struct PG_NO_PADDING XLogRecordBlockHeader
/* BlockNumber follows */
} XLogRecordBlockHeader;
-#define SizeOfXLogRecordBlockHeader (sizeof(XLogRecordBlockHeader))
/*
* Additional header information when a full-page image is included
@@ -184,7 +183,7 @@ typedef struct PG_NO_PADDING XLogRecordBlockCompressHeader
* temporary buffer for constructing the header.
*/
#define MaxSizeOfXLogRecordBlockHeader \
- (SizeOfXLogRecordBlockHeader + \
+ (sizeof(XLogRecordBlockHeader) + \
SizeOfXLogRecordBlockImageHeader + \
SizeOfXLogRecordBlockCompressHeader + \
sizeof(RelFileLocator) + \
--
2.43.0
[application/octet-stream] 0001-Integrate-pg-tidy-clang-tidy-plugin-into-the-Postgre.patch (27.9K, 3-0001-Integrate-pg-tidy-clang-tidy-plugin-into-the-Postgre.patch)
download | inline diff:
From 524b193e9e95f96c24290f37db590b330c077eee Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <[email protected]>
Date: Tue, 17 Mar 2026 16:19:24 +0000
Subject: [PATCH 1/4] Integrate pg-tidy clang-tidy plugin into the PostgreSQL
meson build
Add pg-tidy, a clang-tidy plugin with PostgreSQL-specific checks, to the
meson build system as an optional component (off by default).
The pg_tidy option requires LLVM/clang development libraries and
clang-tidy to be available. When enabled, it builds the pg_tidy shared
module and runs clang-tidy with only pg-specific checks on all source
files as part of the default build.
The LLVM detection is extended so that pg_tidy=enabled triggers LLVM
detection even when llvm=disabled (for JIT). A new llvm_jit_enabled
variable gates the JIT module separately from the LLVM dependency.
---
meson.build | 45 ++++++-
meson_options.txt | 3 +
src/backend/jit/llvm/meson.build | 2 +-
src/meson.build | 2 +
src/tools/pg-tidy/include/pg_tidy.h | 12 ++
src/tools/pg-tidy/meson.build | 69 ++++++++++
src/tools/pg-tidy/run_pg_tidy_file.py | 35 ++++++
src/tools/pg-tidy/src/PgNoPaddingCheck.cpp | 108 ++++++++++++++++
src/tools/pg-tidy/src/PgNoPaddingCheck.h | 21 ++++
.../pg-tidy/src/PgNoPaddingInitCheck.cpp | 44 +++++++
src/tools/pg-tidy/src/PgNoPaddingInitCheck.h | 18 +++
.../pg-tidy/src/PgRequiresNoPaddingCheck.cpp | 89 +++++++++++++
.../pg-tidy/src/PgRequiresNoPaddingCheck.h | 18 +++
src/tools/pg-tidy/src/PgTidyModule.cpp | 22 ++++
src/tools/pg-tidy/test/lit.cfg.py | 0
src/tools/pg-tidy/test/lit.site.cfg.py.in | 15 +++
src/tools/pg-tidy/test/pg-no-padding-init.c | 28 +++++
src/tools/pg-tidy/test/pg-no-padding.c | 118 ++++++++++++++++++
.../pg-tidy/test/pg-requires-no-padding.c | 54 ++++++++
19 files changed, 697 insertions(+), 6 deletions(-)
create mode 100644 src/tools/pg-tidy/include/pg_tidy.h
create mode 100644 src/tools/pg-tidy/meson.build
create mode 100644 src/tools/pg-tidy/run_pg_tidy_file.py
create mode 100644 src/tools/pg-tidy/src/PgNoPaddingCheck.cpp
create mode 100644 src/tools/pg-tidy/src/PgNoPaddingCheck.h
create mode 100644 src/tools/pg-tidy/src/PgNoPaddingInitCheck.cpp
create mode 100644 src/tools/pg-tidy/src/PgNoPaddingInitCheck.h
create mode 100644 src/tools/pg-tidy/src/PgRequiresNoPaddingCheck.cpp
create mode 100644 src/tools/pg-tidy/src/PgRequiresNoPaddingCheck.h
create mode 100644 src/tools/pg-tidy/src/PgTidyModule.cpp
create mode 100644 src/tools/pg-tidy/test/lit.cfg.py
create mode 100644 src/tools/pg-tidy/test/lit.site.cfg.py.in
create mode 100644 src/tools/pg-tidy/test/pg-no-padding-init.c
create mode 100644 src/tools/pg-tidy/test/pg-no-padding.c
create mode 100644 src/tools/pg-tidy/test/pg-requires-no-padding.c
diff --git a/meson.build b/meson.build
index 5122706477d..b0d24e980af 100644
--- a/meson.build
+++ b/meson.build
@@ -926,13 +926,25 @@ endif
###############################################################
llvmopt = get_option('llvm')
+pg_tidy_opt = get_option('pg_tidy')
llvm = not_found_dep
+llvm_binpath = ''
+pg_tidy_enabled = false
if have_cxx
- llvm = dependency('llvm', version: '>=14', method: 'config-tool', required: llvmopt)
+ # Detect LLVM if needed for JIT or pg_tidy
+ llvm_required = llvmopt.enabled() or pg_tidy_opt.enabled()
+ llvm_needed = not llvmopt.disabled() or not pg_tidy_opt.disabled()
+ if llvm_needed
+ llvm = dependency('llvm', version: '>=14', method: 'config-tool',
+ required: llvm_required)
+ endif
if llvm.found()
- cdata.set('USE_LLVM', 1)
+ llvm_jit_enabled = not llvmopt.disabled()
+ if llvm_jit_enabled
+ cdata.set('USE_LLVM', 1)
+ endif
llvm_binpath = llvm.get_variable(configtool: 'bindir')
@@ -941,17 +953,40 @@ if have_cxx
# Some distros put LLVM and clang in different paths, so fallback to
# find via PATH, too.
clang = find_program(llvm_binpath / 'clang', 'clang', required: true)
+ else
+ llvm_jit_enabled = false
endif
else
- msg = 'llvm requires a C++ compiler'
- if llvmopt.auto()
+ llvm_jit_enabled = false
+ msg = 'llvm/pg_tidy requires a C++ compiler'
+ if llvmopt.auto() and pg_tidy_opt.auto()
message(msg)
- elif llvmopt.enabled()
+ elif llvmopt.enabled() or pg_tidy_opt.enabled()
error(msg)
endif
endif
+###############################################################
+# Tool: pg-tidy (clang-tidy checks for PostgreSQL)
+###############################################################
+
+clang_tidy_prog = disabler()
+clang_cpp_dep = not_found_dep
+if not pg_tidy_opt.disabled() and llvm.found() and have_cxx
+ clang_tidy_prog = find_program(llvm_binpath / 'clang-tidy', 'clang-tidy',
+ required: pg_tidy_opt)
+ if clang_tidy_prog.found()
+ clang_cpp_dep = cxx.find_library('clang-cpp', required: pg_tidy_opt)
+ if clang_cpp_dep.found()
+ pg_tidy_enabled = true
+ endif
+ endif
+elif pg_tidy_opt.enabled()
+ error('pg_tidy requires LLVM and a C++ compiler')
+endif
+
+
###############################################################
# Library: icu
diff --git a/meson_options.txt b/meson_options.txt
index 6a793f3e479..f8f9b5f4835 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -121,6 +121,9 @@ option('libxslt', type: 'feature', value: 'auto',
option('llvm', type: 'feature', value: 'disabled',
description: 'LLVM support')
+option('pg_tidy', type: 'feature', value: 'disabled',
+ description: 'pg-tidy clang-tidy checks for PostgreSQL')
+
option('lz4', type: 'feature', value: 'auto',
description: 'LZ4 support')
diff --git a/src/backend/jit/llvm/meson.build b/src/backend/jit/llvm/meson.build
index 7df8453ad6f..1f6025c4d37 100644
--- a/src/backend/jit/llvm/meson.build
+++ b/src/backend/jit/llvm/meson.build
@@ -1,6 +1,6 @@
# Copyright (c) 2022-2026, PostgreSQL Global Development Group
-if not llvm.found()
+if not llvm_jit_enabled
subdir_done()
endif
diff --git a/src/meson.build b/src/meson.build
index b57d4a5c259..47d72b0252c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -15,6 +15,8 @@ subdir('interfaces')
subdir('tools/pg_bsd_indent')
+subdir('tools/pg-tidy')
+
### Generate a Makefile.global that's complete enough for PGXS to work.
#
diff --git a/src/tools/pg-tidy/include/pg_tidy.h b/src/tools/pg-tidy/include/pg_tidy.h
new file mode 100644
index 00000000000..8157794beca
--- /dev/null
+++ b/src/tools/pg-tidy/include/pg_tidy.h
@@ -0,0 +1,12 @@
+#ifndef PG_TIDY_H
+#define PG_TIDY_H
+
+#if defined(__clang__) || defined(__GNUC__)
+#define PG_NO_PADDING __attribute__((annotate("pg_no_padding")))
+#define PG_REQUIRE_NO_PADDING __attribute__((annotate("pg_requires_no_padding")))
+#else
+#define PG_NO_PADDING
+#define PG_REQUIRE_NO_PADDING
+#endif
+
+#endif
diff --git a/src/tools/pg-tidy/meson.build b/src/tools/pg-tidy/meson.build
new file mode 100644
index 00000000000..c307a8ec48e
--- /dev/null
+++ b/src/tools/pg-tidy/meson.build
@@ -0,0 +1,69 @@
+# pg-tidy: clang-tidy checks for PostgreSQL
+#
+# This builds a clang-tidy plugin with PostgreSQL-specific checks.
+# Requires LLVM/clang development libraries and clang-tidy.
+
+if not pg_tidy_enabled
+ subdir_done()
+endif
+
+pg_tidy_lib = shared_module('pg_tidy',
+ 'src/PgTidyModule.cpp',
+ 'src/PgNoPaddingCheck.cpp',
+ 'src/PgNoPaddingInitCheck.cpp',
+ 'src/PgRequiresNoPaddingCheck.cpp',
+ dependencies: [llvm, clang_cpp_dep],
+ cpp_args: ['-fno-exceptions'],
+ override_options: ['cpp_std=c++17'],
+)
+
+# Run clang-tidy with pg-specific checks on each backend source file.
+# Each file gets its own custom_target with a stamp file, so ninja can
+# parallelize the checks and only re-run them when sources change.
+python = find_program('python3')
+pg_tidy_wrapper = meson.current_source_dir() / 'run_pg_tidy_file.py'
+
+foreach srcfile : backend_sources
+ srcfilename = fs.parent(srcfile) / fs.name(srcfile)
+ targetname = 'pg_tidy_' + srcfilename.underscorify()
+
+ custom_target(targetname,
+ input: [srcfile],
+ output: targetname + '.stamp',
+ command: [
+ python, pg_tidy_wrapper,
+ clang_tidy_prog,
+ pg_tidy_lib,
+ meson.project_build_root(),
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ depends: [pg_tidy_lib, generated_backend_headers_stamp],
+ build_by_default: true,
+ )
+endforeach
+
+# Tests require lit and FileCheck from LLVM
+lit = find_program('lit', required: false)
+filecheck = find_program('FileCheck', required: false)
+
+if lit.found() and filecheck.found()
+ lit_cfg_data = configuration_data()
+ lit_cfg_data.set('CLANG_TIDY', clang_tidy_prog.full_path())
+ lit_cfg_data.set('FILECHECK', filecheck.full_path())
+ lit_cfg_data.set('PG_TIDY_LIB',
+ meson.current_build_dir() / 'lib' + pg_tidy_lib.name() + '.so')
+ lit_cfg_data.set('TEST_SOURCE_DIR', meson.current_source_dir() / 'test')
+ lit_cfg_data.set('INCLUDE_DIR', meson.current_source_dir() / 'include')
+
+ configure_file(
+ input: 'test/lit.site.cfg.py.in',
+ output: 'lit.site.cfg.py',
+ configuration: lit_cfg_data,
+ )
+
+ test('pg-tidy-lit-tests', lit,
+ args: [meson.current_build_dir(), '-v'],
+ depends: [pg_tidy_lib],
+ )
+endif
diff --git a/src/tools/pg-tidy/run_pg_tidy_file.py b/src/tools/pg-tidy/run_pg_tidy_file.py
new file mode 100644
index 00000000000..c85334bcc85
--- /dev/null
+++ b/src/tools/pg-tidy/run_pg_tidy_file.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+"""Run clang-tidy with pg-tidy checks on a single source file."""
+
+import subprocess
+import sys
+
+
+def main():
+ clang_tidy = sys.argv[1]
+ pg_tidy_lib = sys.argv[2]
+ build_dir = sys.argv[3]
+ source_file = sys.argv[4]
+ stamp_file = sys.argv[5]
+
+ result = subprocess.run([
+ clang_tidy,
+ '--load=' + pg_tidy_lib,
+ '-checks=-*,pg-*',
+ '-warnings-as-errors=pg-*',
+ '-p', build_dir,
+ source_file,
+ ], capture_output=True, text=True)
+
+ if result.returncode != 0:
+ # Print clang-tidy output so the user sees the actual diagnostics
+ if result.stdout:
+ print(result.stdout, file=sys.stderr, end='')
+ sys.exit(1)
+
+ with open(stamp_file, 'w'):
+ pass
+
+
+if __name__ == '__main__':
+ main()
diff --git a/src/tools/pg-tidy/src/PgNoPaddingCheck.cpp b/src/tools/pg-tidy/src/PgNoPaddingCheck.cpp
new file mode 100644
index 00000000000..da02607597f
--- /dev/null
+++ b/src/tools/pg-tidy/src/PgNoPaddingCheck.cpp
@@ -0,0 +1,108 @@
+#include "PgNoPaddingCheck.h"
+#include <clang/AST/ASTContext.h>
+#include <clang/AST/Attr.h>
+#include <clang/AST/RecordLayout.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::pg {
+
+static bool recordHasPadding(const RecordDecl *RD, const ASTContext &Ctx) {
+ if (RD->isUnion() || RD->isInvalidDecl() || !RD->isCompleteDefinition())
+ return false;
+
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ unsigned FieldIdx = 0;
+ uint64_t PrevEnd = 0;
+
+ for (const auto *Field : RD->fields()) {
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldIdx);
+ uint64_t FieldSize = Ctx.getTypeSize(Field->getType());
+
+ if (FieldOffset > PrevEnd)
+ return true;
+
+ QualType FieldType = Field->getType().getCanonicalType();
+ if (const auto *FieldRD = FieldType->getAsRecordDecl()) {
+ if (recordHasPadding(FieldRD, Ctx))
+ return true;
+ }
+
+ PrevEnd = FieldOffset + FieldSize;
+ ++FieldIdx;
+ }
+
+ uint64_t RecordSize = Ctx.getTypeSize(
+ RD->getTypeForDecl()->getCanonicalTypeInternal());
+ return PrevEnd < RecordSize;
+}
+
+static bool hasNoPaddingAnnotation(const RecordDecl *RD) {
+ for (const auto *Attr : RD->specific_attrs<AnnotateAttr>()) {
+ if (Attr->getAnnotation() == "pg_no_padding")
+ return true;
+ }
+ return false;
+}
+
+void PgNoPaddingCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ recordDecl(isDefinition(), hasAttr(attr::Annotate)).bind("record"),
+ this);
+}
+
+void PgNoPaddingCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *RD = Result.Nodes.getNodeAs<RecordDecl>("record");
+ if (!RD || !hasNoPaddingAnnotation(RD))
+ return;
+
+ const ASTContext &Ctx = *Result.Context;
+ checkRecordForPadding(RD, Ctx);
+}
+
+void PgNoPaddingCheck::checkRecordForPadding(const RecordDecl *RD,
+ const ASTContext &Ctx) {
+ if (RD->isUnion() || RD->isInvalidDecl() || !RD->isCompleteDefinition())
+ return;
+
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ unsigned FieldIdx = 0;
+ uint64_t PrevEnd = 0;
+
+ for (const auto *Field : RD->fields()) {
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldIdx);
+ uint64_t FieldSize = Ctx.getTypeSize(Field->getType());
+
+ if (FieldOffset > PrevEnd) {
+ uint64_t PadBytes = (FieldOffset - PrevEnd) / Ctx.getCharWidth();
+ diag(Field->getLocation(),
+ "%0 bytes of padding before field %1")
+ << static_cast<unsigned>(PadBytes) << Field;
+ }
+
+ QualType FieldType = Field->getType().getCanonicalType();
+ if (const auto *FieldRD = FieldType->getAsRecordDecl()) {
+ if (FieldRD->isCompleteDefinition() && !FieldRD->isUnion()) {
+ if (recordHasPadding(FieldRD, Ctx)) {
+ diag(Field->getLocation(),
+ "field %0 of type %1 contains internal padding")
+ << Field << FieldType;
+ }
+ }
+ }
+
+ PrevEnd = FieldOffset + FieldSize;
+ ++FieldIdx;
+ }
+
+ uint64_t RecordSize = Ctx.getTypeSize(RD->getTypeForDecl()->getCanonicalTypeInternal());
+ if (PrevEnd < RecordSize) {
+ uint64_t PadBytes = (RecordSize - PrevEnd) / Ctx.getCharWidth();
+ diag(RD->getBraceRange().getEnd(),
+ "%0 bytes of trailing padding in struct %1")
+ << static_cast<unsigned>(PadBytes) << RD;
+ }
+}
+
+} // namespace clang::tidy::pg
diff --git a/src/tools/pg-tidy/src/PgNoPaddingCheck.h b/src/tools/pg-tidy/src/PgNoPaddingCheck.h
new file mode 100644
index 00000000000..2e83c9b3fb2
--- /dev/null
+++ b/src/tools/pg-tidy/src/PgNoPaddingCheck.h
@@ -0,0 +1,21 @@
+#ifndef PG_NO_PADDING_CHECK_H
+#define PG_NO_PADDING_CHECK_H
+
+#include <clang-tidy/ClangTidyCheck.h>
+
+namespace clang::tidy::pg {
+
+class PgNoPaddingCheck : public ClangTidyCheck {
+public:
+ PgNoPaddingCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void checkRecordForPadding(const RecordDecl *RD, const ASTContext &Ctx);
+};
+
+} // namespace clang::tidy::pg
+
+#endif
diff --git a/src/tools/pg-tidy/src/PgNoPaddingInitCheck.cpp b/src/tools/pg-tidy/src/PgNoPaddingInitCheck.cpp
new file mode 100644
index 00000000000..dcb8793b7e1
--- /dev/null
+++ b/src/tools/pg-tidy/src/PgNoPaddingInitCheck.cpp
@@ -0,0 +1,44 @@
+#include "PgNoPaddingInitCheck.h"
+#include <clang/AST/ASTContext.h>
+#include <clang/AST/Attr.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::pg {
+
+static bool hasAnnotation(const Decl *D, StringRef Anno) {
+ for (const auto *Attr : D->specific_attrs<AnnotateAttr>()) {
+ if (Attr->getAnnotation() == Anno)
+ return true;
+ }
+ return false;
+}
+
+void PgNoPaddingInitCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ varDecl(hasLocalStorage(), unless(parmVarDecl())).bind("var"), this);
+}
+
+void PgNoPaddingInitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
+ if (!VD)
+ return;
+
+ QualType T = VD->getType().getCanonicalType();
+ const RecordDecl *RD = T->getAsRecordDecl();
+ if (!RD)
+ return;
+
+ if (!hasAnnotation(RD, "pg_no_padding"))
+ return;
+
+ if (VD->hasInit())
+ return;
+
+ diag(VD->getLocation(),
+ "variable %0 of type %1 (marked pg_no_padding) is not zero-initialized")
+ << VD << T;
+}
+
+} // namespace clang::tidy::pg
diff --git a/src/tools/pg-tidy/src/PgNoPaddingInitCheck.h b/src/tools/pg-tidy/src/PgNoPaddingInitCheck.h
new file mode 100644
index 00000000000..b74be98c95b
--- /dev/null
+++ b/src/tools/pg-tidy/src/PgNoPaddingInitCheck.h
@@ -0,0 +1,18 @@
+#ifndef PG_NO_PADDING_INIT_CHECK_H
+#define PG_NO_PADDING_INIT_CHECK_H
+
+#include <clang-tidy/ClangTidyCheck.h>
+
+namespace clang::tidy::pg {
+
+class PgNoPaddingInitCheck : public ClangTidyCheck {
+public:
+ PgNoPaddingInitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::pg
+
+#endif
diff --git a/src/tools/pg-tidy/src/PgRequiresNoPaddingCheck.cpp b/src/tools/pg-tidy/src/PgRequiresNoPaddingCheck.cpp
new file mode 100644
index 00000000000..b5315400fb7
--- /dev/null
+++ b/src/tools/pg-tidy/src/PgRequiresNoPaddingCheck.cpp
@@ -0,0 +1,89 @@
+#include "PgRequiresNoPaddingCheck.h"
+#include <clang/AST/ASTContext.h>
+#include <clang/AST/Attr.h>
+#include <clang/AST/Expr.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::pg {
+
+static bool hasAnnotation(const Decl *D, StringRef Anno) {
+ for (const auto *Attr : D->specific_attrs<AnnotateAttr>()) {
+ if (Attr->getAnnotation() == Anno)
+ return true;
+ }
+ return false;
+}
+
+static const QualType resolveArgType(const Expr *Arg) {
+ Arg = Arg->IgnoreParenImpCasts();
+
+ if (const auto *UO = dyn_cast<UnaryOperator>(Arg)) {
+ if (UO->getOpcode() == UO_AddrOf) {
+ return UO->getSubExpr()->IgnoreParenImpCasts()->getType().getCanonicalType();
+ }
+ }
+
+ QualType T = Arg->getType().getCanonicalType();
+ if (T->isPointerType())
+ return T->getPointeeType().getCanonicalType();
+ if (T->isArrayType())
+ return T->getAsArrayTypeUnsafe()->getElementType().getCanonicalType();
+
+ return QualType();
+}
+
+void PgRequiresNoPaddingCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(callExpr().bind("call"), this);
+}
+
+void PgRequiresNoPaddingCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ if (!Call)
+ return;
+
+ const FunctionDecl *FD = Call->getDirectCallee();
+ if (!FD)
+ return;
+
+ for (unsigned i = 0; i < FD->getNumParams() && i < Call->getNumArgs(); ++i) {
+ const ParmVarDecl *Param = FD->getParamDecl(i);
+ if (!hasAnnotation(Param, "pg_requires_no_padding"))
+ continue;
+
+ const Expr *Arg = Call->getArg(i);
+ QualType ArgType = resolveArgType(Arg);
+
+ if (ArgType.isNull()) {
+ diag(Arg->getExprLoc(),
+ "cannot verify no-padding requirement on void* argument");
+ continue;
+ }
+
+ if (ArgType->isVoidType()) {
+ diag(Arg->getExprLoc(),
+ "cannot verify no-padding requirement on void* argument");
+ continue;
+ }
+
+ if (ArgType->isBuiltinType())
+ continue;
+
+ const RecordDecl *RD = ArgType->getAsRecordDecl();
+ if (!RD) {
+ diag(Arg->getExprLoc(),
+ "cannot verify no-padding requirement on void* argument");
+ continue;
+ }
+
+ if (!hasAnnotation(RD, "pg_no_padding")) {
+ diag(Arg->getExprLoc(),
+ "argument type %0 passed to no-padding parameter lacks "
+ "pg_no_padding annotation")
+ << ArgType;
+ }
+ }
+}
+
+} // namespace clang::tidy::pg
diff --git a/src/tools/pg-tidy/src/PgRequiresNoPaddingCheck.h b/src/tools/pg-tidy/src/PgRequiresNoPaddingCheck.h
new file mode 100644
index 00000000000..494af66385d
--- /dev/null
+++ b/src/tools/pg-tidy/src/PgRequiresNoPaddingCheck.h
@@ -0,0 +1,18 @@
+#ifndef PG_REQUIRES_NO_PADDING_CHECK_H
+#define PG_REQUIRES_NO_PADDING_CHECK_H
+
+#include <clang-tidy/ClangTidyCheck.h>
+
+namespace clang::tidy::pg {
+
+class PgRequiresNoPaddingCheck : public ClangTidyCheck {
+public:
+ PgRequiresNoPaddingCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::pg
+
+#endif
diff --git a/src/tools/pg-tidy/src/PgTidyModule.cpp b/src/tools/pg-tidy/src/PgTidyModule.cpp
new file mode 100644
index 00000000000..3ab486dd087
--- /dev/null
+++ b/src/tools/pg-tidy/src/PgTidyModule.cpp
@@ -0,0 +1,22 @@
+#include "PgNoPaddingCheck.h"
+#include "PgNoPaddingInitCheck.h"
+#include "PgRequiresNoPaddingCheck.h"
+#include <clang-tidy/ClangTidyModule.h>
+#include <clang-tidy/ClangTidyModuleRegistry.h>
+
+namespace clang::tidy::pg {
+
+class PgTidyModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<PgNoPaddingCheck>("pg-no-padding");
+ CheckFactories.registerCheck<PgNoPaddingInitCheck>("pg-no-padding-init");
+ CheckFactories.registerCheck<PgRequiresNoPaddingCheck>(
+ "pg-requires-no-padding");
+ }
+};
+
+static ClangTidyModuleRegistry::Add<PgTidyModule>
+ X("pg-module", "Checks specific to PostgreSQL.");
+
+} // namespace clang::tidy::pg
diff --git a/src/tools/pg-tidy/test/lit.cfg.py b/src/tools/pg-tidy/test/lit.cfg.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/tools/pg-tidy/test/lit.site.cfg.py.in b/src/tools/pg-tidy/test/lit.site.cfg.py.in
new file mode 100644
index 00000000000..f208966b486
--- /dev/null
+++ b/src/tools/pg-tidy/test/lit.site.cfg.py.in
@@ -0,0 +1,15 @@
+import os
+import lit.formats
+
+config.name = "pg-tidy"
+config.test_format = lit.formats.ShTest(True)
+config.suffixes = ['.c']
+
+config.test_source_root = '@TEST_SOURCE_DIR@'
+
+config.substitutions.append(('%clang_tidy', '@CLANG_TIDY@'))
+config.substitutions.append(('%pg_tidy_lib', '@PG_TIDY_LIB@'))
+config.substitutions.append(('%FileCheck', '@FILECHECK@'))
+config.substitutions.append(('%include_dir', '@INCLUDE_DIR@'))
+
+lit_config.load_config(config, os.path.join(config.test_source_root, 'lit.cfg.py'))
diff --git a/src/tools/pg-tidy/test/pg-no-padding-init.c b/src/tools/pg-tidy/test/pg-no-padding-init.c
new file mode 100644
index 00000000000..28e7dc2e7df
--- /dev/null
+++ b/src/tools/pg-tidy/test/pg-no-padding-init.c
@@ -0,0 +1,28 @@
+// RUN: %clang_tidy --load=%pg_tidy_lib -checks=-*,pg-no-padding-init %s \
+// RUN: -- -I%include_dir 2>&1 | %FileCheck %s
+// CHECK: 1 warning generated.
+
+#include "pg_tidy.h"
+
+struct PG_NO_PADDING AnnotatedStruct {
+ int a;
+ int b;
+};
+
+struct PlainStruct {
+ int a;
+ int b;
+};
+
+void test(void) {
+ // CHECK: :[[@LINE+1]]:26: warning: variable 'bad' of type 'struct AnnotatedStruct' (marked pg_no_padding) is not zero-initialized [pg-no-padding-init]
+ struct AnnotatedStruct bad;
+ bad.a = 1;
+ bad.b = 2;
+
+ struct AnnotatedStruct good = {0};
+ good.a = 1;
+
+ struct PlainStruct no_warning;
+ no_warning.a = 1;
+}
diff --git a/src/tools/pg-tidy/test/pg-no-padding.c b/src/tools/pg-tidy/test/pg-no-padding.c
new file mode 100644
index 00000000000..eca3a84347a
--- /dev/null
+++ b/src/tools/pg-tidy/test/pg-no-padding.c
@@ -0,0 +1,118 @@
+// RUN: %clang_tidy --load=%pg_tidy_lib -checks=-*,pg-no-padding %s \
+// RUN: -- -I%include_dir 2>&1 | %FileCheck %s
+// CHECK: 10 warnings generated.
+
+#include "pg_tidy.h"
+
+// --- Non-annotated struct: no warnings ---
+struct NotAnnotated {
+ char a;
+ int b;
+};
+
+// --- Annotated struct with no padding: no warnings ---
+struct PG_NO_PADDING NoPadding {
+ int a;
+ int b;
+};
+
+// --- Annotated struct with inter-field padding ---
+// CHECK: :[[@LINE+3]]:7: warning: 3 bytes of padding before field 'b' [pg-no-padding]
+struct PG_NO_PADDING InterFieldPad {
+ char a;
+ int b;
+};
+
+// --- Annotated struct with trailing padding ---
+// CHECK: :[[@LINE+4]]:1: warning: 3 bytes of trailing padding in struct 'TrailingPad' [pg-no-padding]
+struct PG_NO_PADDING TrailingPad {
+ int a;
+ char b;
+};
+
+// --- Annotated struct with both inter-field and trailing padding ---
+// CHECK: :[[@LINE+4]]:7: warning: 3 bytes of padding before field 'b' [pg-no-padding]
+// CHECK: :[[@LINE+5]]:1: warning: 3 bytes of trailing padding in struct 'BothPad' [pg-no-padding]
+struct PG_NO_PADDING BothPad {
+ char a;
+ int b;
+ char c;
+};
+
+// --- Nested struct with internal padding ---
+struct InnerPadded {
+ char x;
+ int y;
+};
+
+// CHECK: :[[@LINE+3]]:22: warning: field 'inner' of type 'struct InnerPadded' contains internal padding [pg-no-padding]
+struct PG_NO_PADDING HasPaddedInner {
+ int a;
+ struct InnerPadded inner;
+};
+
+// --- Nested struct without padding: no extra warnings ---
+struct InnerClean {
+ int x;
+ int y;
+};
+
+struct PG_NO_PADDING HasCleanInner {
+ int a;
+ struct InnerClean inner;
+};
+
+// --- Deeply nested padding ---
+struct DeepInner {
+ char a;
+ long b;
+};
+
+struct MidLevel {
+ struct DeepInner d;
+};
+
+// CHECK: :[[@LINE+4]]:19: warning: 4 bytes of padding before field 'mid' [pg-no-padding]
+// CHECK: :[[@LINE+3]]:19: warning: field 'mid' of type 'struct MidLevel' contains internal padding [pg-no-padding]
+struct PG_NO_PADDING DeepNest {
+ int a;
+ struct MidLevel mid;
+};
+
+// --- Empty annotated struct: no warnings ---
+struct PG_NO_PADDING AnnotatedEmpty {};
+
+// --- Single field, no padding ---
+struct PG_NO_PADDING SingleField {
+ int x;
+};
+
+// --- All same-size fields, no padding ---
+struct PG_NO_PADDING AllSameSize {
+ int a;
+ int b;
+ int c;
+};
+
+// --- Multiple padding sites ---
+// CHECK: :[[@LINE+5]]:7: warning: 3 bytes of padding before field 'b' [pg-no-padding]
+// CHECK: :[[@LINE+6]]:7: warning: 3 bytes of padding before field 'c' [pg-no-padding]
+// CHECK: :[[@LINE+7]]:1: warning: 3 bytes of trailing padding in struct 'MultiPad' [pg-no-padding]
+struct PG_NO_PADDING MultiPad {
+ char a;
+ int b;
+ char x;
+ int c;
+ char z;
+};
+
+// --- Annotated struct that itself is nested in a non-annotated struct: should still check ---
+struct PG_NO_PADDING AnnotatedInner {
+ int a;
+ int b;
+};
+
+struct OuterNotAnnotated {
+ char x;
+ struct AnnotatedInner inner;
+};
diff --git a/src/tools/pg-tidy/test/pg-requires-no-padding.c b/src/tools/pg-tidy/test/pg-requires-no-padding.c
new file mode 100644
index 00000000000..8436bfed207
--- /dev/null
+++ b/src/tools/pg-tidy/test/pg-requires-no-padding.c
@@ -0,0 +1,54 @@
+// RUN: %clang_tidy --load=%pg_tidy_lib -checks=-*,pg-requires-no-padding %s \
+// RUN: -- -I%include_dir 2>&1 | %FileCheck %s
+// CHECK: 3 warnings generated.
+
+#include "pg_tidy.h"
+
+typedef unsigned int uint32;
+
+struct PG_NO_PADDING AnnotatedStruct {
+ int a;
+ int b;
+};
+
+struct NotAnnotatedStruct {
+ int a;
+ int b;
+};
+
+extern void XLogRegisterData(const void *data PG_REQUIRE_NO_PADDING, uint32 len);
+
+extern void NormalFunc(const void *data, uint32 len);
+
+void test_functions(void) {
+ struct AnnotatedStruct good;
+ struct NotAnnotatedStruct bad;
+ int primitive;
+ void *opaque = &good;
+
+ XLogRegisterData(&good, sizeof(good));
+
+ // CHECK: :[[@LINE+1]]:20: warning: argument type 'struct NotAnnotatedStruct' passed to no-padding parameter lacks pg_no_padding annotation [pg-requires-no-padding]
+ XLogRegisterData(&bad, sizeof(bad));
+
+ XLogRegisterData(&primitive, sizeof(primitive));
+
+ // CHECK: :[[@LINE+1]]:20: warning: cannot verify no-padding requirement on void* argument [pg-requires-no-padding]
+ XLogRegisterData(opaque, sizeof(good));
+
+ NormalFunc(&bad, sizeof(bad));
+ NormalFunc(opaque, sizeof(good));
+}
+
+void test_pointer_variable(void) {
+ struct AnnotatedStruct good;
+ struct NotAnnotatedStruct bad;
+
+ struct AnnotatedStruct *good_ptr = &good;
+ struct NotAnnotatedStruct *bad_ptr = &bad;
+
+ XLogRegisterData(good_ptr, sizeof(*good_ptr));
+
+ // CHECK: :[[@LINE+1]]:20: warning: argument type 'struct NotAnnotatedStruct' passed to no-padding parameter lacks pg_no_padding annotation [pg-requires-no-padding]
+ XLogRegisterData(bad_ptr, sizeof(*bad_ptr));
+}
--
2.43.0
[application/octet-stream] 0002-Add-PG_NO_PADDING-PG_REQUIRE_NO_PADDING-and-padding-.patch (3.2K, 4-0002-Add-PG_NO_PADDING-PG_REQUIRE_NO_PADDING-and-padding-.patch)
download | inline diff:
From 6eeeb7c3d17756e9916b4c0aeb2c993f9c3c013a Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <[email protected]>
Date: Tue, 17 Mar 2026 16:19:39 +0000
Subject: [PATCH 2/4] Add PG_NO_PADDING, PG_REQUIRE_NO_PADDING, and padding
helper macros
Introduce compiler annotation macros in c.h for enforcing struct padding
constraints at build time via the pg-tidy clang-tidy plugin:
- PG_NO_PADDING: marks a struct as requiring no implicit padding
- PG_REQUIRE_NO_PADDING: marks a function parameter as requiring that
the argument type be annotated with PG_NO_PADDING
- pg_padding_1/2/4: helper macros to declare explicit padding fields
using appropriately sized integer types
Annotate the data parameter of XLogRegisterData() with
PG_REQUIRE_NO_PADDING to enforce that all data written to WAL records
contains no uninitialized padding bytes.
---
src/include/access/xloginsert.h | 2 +-
src/include/c.h | 29 +++++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h
index 16ebc76e743..527d40c7531 100644
--- a/src/include/access/xloginsert.h
+++ b/src/include/access/xloginsert.h
@@ -46,7 +46,7 @@ extern void XLogSetRecordFlags(uint8 flags);
extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info);
extern XLogRecPtr XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value);
extern void XLogEnsureRecordSpace(int max_block_id, int ndatas);
-extern void XLogRegisterData(const void *data, uint32 len);
+extern void XLogRegisterData(const void *data PG_REQUIRE_NO_PADDING, uint32 len);
extern void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags);
extern void XLogRegisterBlock(uint8 block_id, RelFileLocator *rlocator,
ForkNumber forknum, BlockNumber blknum, const PageData *page,
diff --git a/src/include/c.h b/src/include/c.h
index fb0ea1bc680..9601455b7fb 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -274,6 +274,35 @@
*/
#endif
+/*
+ * PG_NO_PADDING marks a struct definition as requiring no implicit padding.
+ * When pg-tidy clang-tidy checks are enabled, structs with this annotation
+ * will be verified at build time to contain no compiler-inserted padding.
+ *
+ * PG_REQUIRE_NO_PADDING marks a function parameter as requiring that the
+ * argument type be annotated with PG_NO_PADDING.
+ *
+ * These use compiler annotations that are checked by the pg-tidy clang-tidy
+ * plugin. On compilers that don't support annotations, they expand to
+ * nothing.
+ */
+#ifdef __clang__
+#define PG_NO_PADDING __attribute__((annotate("pg_no_padding")))
+#define PG_REQUIRE_NO_PADDING __attribute__((annotate("pg_requires_no_padding")))
+#else
+#define PG_NO_PADDING
+#define PG_REQUIRE_NO_PADDING
+#endif
+
+/*
+ * Macros for explicit struct padding. Use these to replace implicit
+ * compiler-inserted padding in structs marked PG_NO_PADDING. Each macro
+ * declares a field of the appropriately sized integer type.
+ */
+#define pg_padding_1(name) uint8 name
+#define pg_padding_2(name) uint16 name
+#define pg_padding_4(name) uint32 name
+
/*
* Use "pg_attribute_always_inline" in place of "inline" for functions that
* we wish to force inlining of, even when the compiler's heuristics would
--
2.43.0
[application/octet-stream] 0003-Add-explicit-padding-to-WAL-record-structs-and-annot.patch (120.5K, 5-0003-Add-explicit-padding-to-WAL-record-structs-and-annot.patch)
download | inline diff:
From 460692de44296f32b9f4b5a2850e75ae47fa448d Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <[email protected]>
Date: Tue, 17 Mar 2026 16:20:11 +0000
Subject: [PATCH 3/4] Add explicit padding to WAL record structs and annotate
with PG_NO_PADDING
Annotate all struct types passed to XLogRegisterData() with PG_NO_PADDING
and add explicit padding fields where the compiler would insert implicit
padding. This ensures no uninitialized bytes are written to WAL records.
For structs that previously used SizeOfXXXX macros (via offsetof + sizeof
of last field) to skip trailing padding, the macros are replaced with
sizeof() since the explicit padding makes the full struct safe to write.
This is a WAL format change: records now include the previously-skipped
trailing padding bytes, explicitly initialized to zero.
SizeOfXXXX macros for structs with FLEXIBLE_ARRAY_MEMBER are kept, as
they use offsetof() to compute the fixed portion size.
---
src/backend/access/brin/brin.c | 2 +-
src/backend/access/brin/brin_pageops.c | 6 +-
src/backend/access/brin/brin_revmap.c | 4 +-
src/backend/access/gin/ginbtree.c | 6 +-
src/backend/access/gin/gindatapage.c | 2 +-
src/backend/access/gin/ginfast.c | 9 +--
src/backend/access/gin/ginutil.c | 2 +-
src/backend/access/gin/ginvacuum.c | 2 +-
src/backend/access/gist/gistxlog.c | 10 +--
src/backend/access/hash/hash.c | 4 +-
src/backend/access/hash/hashinsert.c | 4 +-
src/backend/access/hash/hashovfl.c | 6 +-
src/backend/access/hash/hashpage.c | 8 +-
src/backend/access/heap/heapam.c | 32 ++++----
src/backend/access/heap/heapam_xlog.c | 6 +-
src/backend/access/heap/pruneheap.c | 10 +--
src/backend/access/heap/rewriteheap.c | 2 +-
src/backend/access/nbtree/nbtdedup.c | 2 +-
src/backend/access/nbtree/nbtinsert.c | 10 +--
src/backend/access/nbtree/nbtpage.c | 20 ++---
src/backend/access/rmgrdesc/clogdesc.c | 2 +-
src/backend/access/rmgrdesc/xactdesc.c | 4 +-
src/backend/access/rmgrdesc/xlogdesc.c | 6 +-
src/backend/access/spgist/spgdoinsert.c | 10 +--
src/backend/access/spgist/spgvacuum.c | 6 +-
src/backend/access/spgist/spgxlog.c | 14 ++--
src/backend/access/transam/clog.c | 4 +-
src/backend/access/transam/commit_ts.c | 2 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/xact.c | 46 ++++++------
src/backend/access/transam/xlog.c | 25 ++++---
src/backend/access/transam/xloginsert.c | 5 +-
src/backend/access/transam/xlogreader.c | 3 +
src/backend/access/transam/xlogrecovery.c | 8 +-
src/backend/catalog/storage.c | 4 +-
src/backend/commands/dbcommands.c | 10 +--
src/backend/commands/sequence.c | 12 +--
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tablespace.c | 4 +-
src/backend/postmaster/walsummarizer.c | 6 +-
src/backend/replication/logical/decode.c | 2 +-
src/backend/replication/logical/message.c | 2 +-
src/backend/replication/logical/origin.c | 4 +-
src/backend/storage/ipc/standby.c | 14 ++--
src/backend/utils/cache/inval.c | 6 +-
src/backend/utils/cache/relmapper.c | 12 +--
src/bin/pg_resetwal/pg_resetwal.c | 1 +
src/include/access/brin_xlog.h | 30 ++++----
src/include/access/clog.h | 2 +-
src/include/access/commit_ts.h | 6 +-
src/include/access/ginblock.h | 6 +-
src/include/access/ginxlog.h | 19 +++--
src/include/access/gistxlog.h | 24 ++++--
src/include/access/hash_xlog.h | 56 +++++++-------
src/include/access/heapam_xlog.h | 75 ++++++++++++-------
src/include/access/multixact.h | 6 +-
src/include/access/nbtxlog.h | 53 +++++++------
src/include/access/spgist_private.h | 6 +-
src/include/access/spgxlog.h | 29 ++++---
src/include/access/xact.h | 24 +++---
src/include/access/xlog_internal.h | 15 ++--
src/include/access/xlogrecord.h | 19 ++---
src/include/catalog/pg_control.h | 8 +-
src/include/catalog/storage_xlog.h | 4 +-
src/include/commands/dbcommands_xlog.h | 6 +-
src/include/commands/sequence_xlog.h | 2 +-
src/include/commands/tablespace.h | 4 +-
src/include/replication/message.h | 4 +-
src/include/replication/origin.h | 6 +-
src/include/storage/lockdefs.h | 2 +-
src/include/storage/sinval.h | 28 +++++--
src/include/storage/standbydefs.h | 10 ++-
src/include/utils/relmapper.h | 2 +-
.../test_custom_rmgrs/test_custom_rmgrs.c | 2 +-
src/test/recovery/t/039_end_of_wal.pl | 5 +-
75 files changed, 457 insertions(+), 365 deletions(-)
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 6887e421442..8ef44a0075b 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1135,7 +1135,7 @@ brinbuild(Relation heap, Relation index, IndexInfo *indexInfo)
if (RelationNeedsWAL(index))
{
- xl_brin_createidx xlrec;
+ xl_brin_createidx xlrec = {0};
XLogRecPtr recptr;
Page page;
diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c
index 7da97bec43b..a1e8bd0e225 100644
--- a/src/backend/access/brin/brin_pageops.c
+++ b/src/backend/access/brin/brin_pageops.c
@@ -183,7 +183,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
/* XLOG stuff */
if (RelationNeedsWAL(idxrel))
{
- xl_brin_samepage_update xlrec;
+ xl_brin_samepage_update xlrec = {0};
XLogRecPtr recptr;
uint8 info = XLOG_BRIN_SAMEPAGE_UPDATE;
@@ -267,7 +267,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
/* XLOG stuff */
if (RelationNeedsWAL(idxrel))
{
- xl_brin_update xlrec;
+ xl_brin_update xlrec = {0};
XLogRecPtr recptr;
uint8 info;
@@ -423,7 +423,7 @@ brin_doinsert(Relation idxrel, BlockNumber pagesPerRange,
/* XLOG stuff */
if (RelationNeedsWAL(idxrel))
{
- xl_brin_insert xlrec;
+ xl_brin_insert xlrec = {0};
XLogRecPtr recptr;
uint8 info;
diff --git a/src/backend/access/brin/brin_revmap.c b/src/backend/access/brin/brin_revmap.c
index 233355cb2d5..57ac044497a 100644
--- a/src/backend/access/brin/brin_revmap.c
+++ b/src/backend/access/brin/brin_revmap.c
@@ -408,7 +408,7 @@ brinRevmapDesummarizeRange(Relation idxrel, BlockNumber heapBlk)
if (RelationNeedsWAL(idxrel))
{
- xl_brin_desummarize xlrec;
+ xl_brin_desummarize xlrec = {0};
XLogRecPtr recptr;
xlrec.pagesPerRange = revmap->rm_pagesPerRange;
@@ -621,7 +621,7 @@ revmap_physical_extend(BrinRevmap *revmap)
if (RelationNeedsWAL(revmap->rm_irel))
{
- xl_brin_revmap_extend xlrec;
+ xl_brin_revmap_extend xlrec = {0};
XLogRecPtr recptr;
xlrec.targetBlk = mapBlk;
diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c
index 3d3a9da56b1..d28f79b8dce 100644
--- a/src/backend/access/gin/ginbtree.c
+++ b/src/backend/access/gin/ginbtree.c
@@ -418,7 +418,7 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
if (RelationNeedsWAL(btree->index) && !btree->isBuild)
{
XLogRecPtr recptr;
- ginxlogInsert xlrec;
+ ginxlogInsert xlrec = {0};
BlockIdData childblknos[2];
xlrec.flags = xlflags;
@@ -433,7 +433,7 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
{
BlockIdSet(&childblknos[0], BufferGetBlockNumber(childbuf));
BlockIdSet(&childblknos[1], GinPageGetOpaque(childpage)->rightlink);
- XLogRegisterData(childblknos,
+ XLogRegisterData((char *) childblknos,
sizeof(BlockIdData) * 2);
}
@@ -457,7 +457,7 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
*/
Buffer rbuffer;
BlockNumber savedRightLink;
- ginxlogSplit data;
+ ginxlogSplit data = {0};
Buffer lbuffer = InvalidBuffer;
Page newrootpg = NULL;
diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c
index c5d7db28077..7d9a466f1e5 100644
--- a/src/backend/access/gin/gindatapage.c
+++ b/src/backend/access/gin/gindatapage.c
@@ -1839,7 +1839,7 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems,
if (RelationNeedsWAL(index) && !is_build)
{
XLogRecPtr recptr;
- ginxlogCreatePostingTree data;
+ ginxlogCreatePostingTree data = {0};
data.size = rootsize;
diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c
index f50848eb65a..63a072a5688 100644
--- a/src/backend/access/gin/ginfast.c
+++ b/src/backend/access/gin/ginfast.c
@@ -115,7 +115,7 @@ writeListPage(Relation index, Buffer buffer,
if (RelationNeedsWAL(index))
{
- ginxlogInsertListPage data;
+ ginxlogInsertListPage data = {0};
XLogRecPtr recptr;
data.rightlink = rightlink;
@@ -224,7 +224,7 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
GinMetaPageData *metadata = NULL;
Buffer buffer = InvalidBuffer;
Page page = NULL;
- ginxlogUpdateMeta data;
+ ginxlogUpdateMeta data = {0};
bool separateList = false;
bool needCleanup = false;
int cleanupSize;
@@ -281,9 +281,8 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
/*
* We should make sublist separately and append it to the tail
*/
- GinMetaPageData sublist;
+ GinMetaPageData sublist = {0};
- memset(&sublist, 0, sizeof(GinMetaPageData));
makeSublist(index, collector->tuples, collector->ntuples, &sublist);
/*
@@ -567,7 +566,7 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
Page page;
int i;
int64 nDeletedHeapTuples = 0;
- ginxlogDeleteListPages data;
+ ginxlogDeleteListPages data = {0};
Buffer buffers[GIN_NDELETE_AT_ONCE];
BlockNumber freespace[GIN_NDELETE_AT_ONCE];
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index ff927279cc3..1b228c17540 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -648,7 +648,7 @@ ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
if (RelationNeedsWAL(index) && !is_build)
{
XLogRecPtr recptr;
- ginxlogUpdateMeta data;
+ ginxlogUpdateMeta data = {0};
data.locator = index->rd_locator;
data.ntuples = 0;
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index c9f143f6c31..5b488e89a56 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -197,7 +197,7 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
if (RelationNeedsWAL(gvs->index))
{
XLogRecPtr recptr;
- ginxlogDeletePage data;
+ ginxlogDeletePage data = {0};
/*
* We can't pass REGBUF_STANDARD for the deleted page, because we
diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c
index c783838495f..b93e831b829 100644
--- a/src/backend/access/gist/gistxlog.c
+++ b/src/backend/access/gist/gistxlog.c
@@ -495,7 +495,7 @@ gistXLogSplit(bool page_is_leaf,
BlockNumber origrlink, GistNSN orignsn,
Buffer leftchildbuf, bool markfollowright)
{
- gistxlogPageSplit xlrec;
+ gistxlogPageSplit xlrec = {0};
SplitPageLayout *ptr;
int npage = 0;
XLogRecPtr recptr;
@@ -550,7 +550,7 @@ XLogRecPtr
gistXLogPageDelete(Buffer buffer, FullTransactionId xid,
Buffer parentBuffer, OffsetNumber downlinkOffset)
{
- gistxlogPageDelete xlrec;
+ gistxlogPageDelete xlrec = {0};
XLogRecPtr recptr;
xlrec.deleteXid = xid;
@@ -592,7 +592,7 @@ void
gistXLogPageReuse(Relation rel, Relation heaprel,
BlockNumber blkno, FullTransactionId deleteXid)
{
- gistxlogPageReuse xlrec_reuse;
+ gistxlogPageReuse xlrec_reuse = {0};
/*
* Note that we don't register the buffer with the record, because this
@@ -629,7 +629,7 @@ gistXLogUpdate(Buffer buffer,
IndexTuple *itup, int ituplen,
Buffer leftchildbuf)
{
- gistxlogPageUpdate xlrec;
+ gistxlogPageUpdate xlrec = {0};
int i;
XLogRecPtr recptr;
@@ -668,7 +668,7 @@ XLogRecPtr
gistXLogDelete(Buffer buffer, OffsetNumber *todelete, int ntodelete,
TransactionId snapshotConflictHorizon, Relation heaprel)
{
- gistxlogDelete xlrec;
+ gistxlogDelete xlrec = {0};
XLogRecPtr recptr;
xlrec.isCatalogRel = RelationIsAccessibleInLogicalDecoding(heaprel);
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index e88ddb32a05..f565cfc77a8 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -613,7 +613,7 @@ loop_top:
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_hash_update_meta_page xlrec;
+ xl_hash_update_meta_page xlrec = {0};
XLogRecPtr recptr;
xlrec.ntuples = metap->hashm_ntuples;
@@ -819,7 +819,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_hash_delete xlrec;
+ xl_hash_delete xlrec = {0};
XLogRecPtr recptr;
xlrec.clear_dead_marking = clear_dead_marking;
diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c
index 0cefbacc96e..5ba623393a8 100644
--- a/src/backend/access/hash/hashinsert.c
+++ b/src/backend/access/hash/hashinsert.c
@@ -215,7 +215,7 @@ restart_insert:
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_hash_insert xlrec;
+ xl_hash_insert xlrec = {0};
XLogRecPtr recptr;
xlrec.offnum = itup_off;
@@ -423,7 +423,7 @@ _hash_vacuum_one_page(Relation rel, Relation hrel, Buffer metabuf, Buffer buf)
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_hash_vacuum_one_page xlrec;
+ xl_hash_vacuum_one_page xlrec = {0};
XLogRecPtr recptr;
xlrec.isCatalogRel = RelationIsAccessibleInLogicalDecoding(hrel);
diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c
index 8cfb6ce75d6..69e90ffac5b 100644
--- a/src/backend/access/hash/hashovfl.c
+++ b/src/backend/access/hash/hashovfl.c
@@ -382,7 +382,7 @@ found:
if (RelationNeedsWAL(rel))
{
XLogRecPtr recptr;
- xl_hash_add_ovfl_page xlrec;
+ xl_hash_add_ovfl_page xlrec = {0};
xlrec.bmpage_found = page_found;
xlrec.bmsize = metap->hashm_bmsize;
@@ -644,7 +644,7 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_hash_squeeze_page xlrec;
+ xl_hash_squeeze_page xlrec = {0};
XLogRecPtr recptr;
int i;
bool mod_wbuf = false;
@@ -987,7 +987,7 @@ readpage:
if (RelationNeedsWAL(rel))
{
XLogRecPtr recptr;
- xl_hash_move_page_contents xlrec;
+ xl_hash_move_page_contents xlrec = {0};
xlrec.ntups = nitups;
xlrec.is_prim_bucket_same_wrt = (wbuf == bucket_buf);
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 8e220a3ae16..61a0badbfaa 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -386,7 +386,7 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
/* XLOG stuff */
if (use_wal)
{
- xl_hash_init_meta_page xlrec;
+ xl_hash_init_meta_page xlrec = {0};
XLogRecPtr recptr;
xlrec.num_tuples = num_tuples;
@@ -462,7 +462,7 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
/* XLOG stuff */
if (use_wal)
{
- xl_hash_init_bitmap_page xlrec;
+ xl_hash_init_bitmap_page xlrec = {0};
XLogRecPtr recptr;
xlrec.bmsize = metap->hashm_bmsize;
@@ -899,7 +899,7 @@ restart_expand:
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_hash_split_allocate_page xlrec;
+ xl_hash_split_allocate_page xlrec = {0};
XLogRecPtr recptr;
xlrec.new_bucket = maxbucket;
@@ -1297,7 +1297,7 @@ _hash_splitbucket(Relation rel,
if (RelationNeedsWAL(rel))
{
XLogRecPtr recptr;
- xl_hash_split_complete xlrec;
+ xl_hash_split_complete xlrec = {0};
xlrec.old_bucket_flag = oopaque->hasho_flag;
xlrec.new_bucket_flag = nopaque->hasho_flag;
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 98d53caeea8..c8b1ef7d372 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2218,8 +2218,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
/* XLOG stuff */
if (RelationNeedsWAL(relation))
{
- xl_heap_insert xlrec;
- xl_heap_header xlhdr;
+ xl_heap_insert xlrec = {0};
+ xl_heap_header xlhdr = {0};
XLogRecPtr recptr;
Page page = BufferGetPage(buffer);
uint8 info = XLOG_HEAP_INSERT;
@@ -3149,8 +3149,8 @@ l1:
*/
if (RelationNeedsWAL(relation))
{
- xl_heap_delete xlrec;
- xl_heap_header xlhdr;
+ xl_heap_delete xlrec = {0};
+ xl_heap_header xlhdr = {0};
XLogRecPtr recptr;
/*
@@ -3948,7 +3948,7 @@ l2:
if (RelationNeedsWAL(relation))
{
- xl_heap_lock xlrec;
+ xl_heap_lock xlrec = {0};
XLogRecPtr recptr;
XLogBeginInsert();
@@ -5283,7 +5283,7 @@ failed:
*/
if (RelationNeedsWAL(relation))
{
- xl_heap_lock xlrec;
+ xl_heap_lock xlrec = {0};
XLogRecPtr recptr;
XLogBeginInsert();
@@ -6034,7 +6034,7 @@ l4:
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_heap_lock_updated xlrec;
+ xl_heap_lock_updated xlrec = {0};
XLogRecPtr recptr;
Page page = BufferGetPage(buf);
@@ -6201,7 +6201,7 @@ heap_finish_speculative(Relation relation, const ItemPointerData *tid)
/* XLOG stuff */
if (RelationNeedsWAL(relation))
{
- xl_heap_confirm xlrec;
+ xl_heap_confirm xlrec = {0};
XLogRecPtr recptr;
xlrec.offnum = ItemPointerGetOffsetNumber(tid);
@@ -6346,7 +6346,7 @@ heap_abort_speculative(Relation relation, const ItemPointerData *tid)
*/
if (RelationNeedsWAL(relation))
{
- xl_heap_delete xlrec;
+ xl_heap_delete xlrec = {0};
XLogRecPtr recptr;
xlrec.flags = XLH_DELETE_IS_SUPER;
@@ -6646,7 +6646,7 @@ heap_inplace_update_and_unlock(Relation relation,
/* XLOG stuff */
if (RelationNeedsWAL(relation))
{
- xl_heap_inplace xlrec;
+ xl_heap_inplace xlrec = {0};
PGAlignedBlock copied_buffer;
char *origdata = (char *) BufferGetBlock(buffer);
Page page = BufferGetPage(buffer);
@@ -6667,7 +6667,7 @@ heap_inplace_update_and_unlock(Relation relation,
XLogBeginInsert();
XLogRegisterData(&xlrec, MinSizeOfHeapInplace);
if (nmsgs != 0)
- XLogRegisterData(invalMessages,
+ XLogRegisterData((char *) invalMessages,
nmsgs * sizeof(SharedInvalidationMessage));
/* register block matching what buffer will look like after changes */
@@ -8884,7 +8884,7 @@ XLogRecPtr
log_heap_visible(Relation rel, Buffer heap_buffer, Buffer vm_buffer,
TransactionId snapshotConflictHorizon, uint8 vmflags)
{
- xl_heap_visible xlrec;
+ xl_heap_visible xlrec = {0};
XLogRecPtr recptr;
uint8 flags;
@@ -8920,9 +8920,9 @@ log_heap_update(Relation reln, Buffer oldbuf,
HeapTuple old_key_tuple,
bool all_visible_cleared, bool new_all_visible_cleared)
{
- xl_heap_update xlrec;
- xl_heap_header xlhdr;
- xl_heap_header xlhdr_idx;
+ xl_heap_update xlrec = {0};
+ xl_heap_header xlhdr = {0};
+ xl_heap_header xlhdr_idx = {0};
uint8 info;
uint16 prefix_suffix[2];
uint16 prefixlen = 0,
@@ -9139,7 +9139,7 @@ log_heap_update(Relation reln, Buffer oldbuf,
static XLogRecPtr
log_heap_new_cid(Relation relation, HeapTuple tup)
{
- xl_heap_new_cid xlrec;
+ xl_heap_new_cid xlrec = {0};
XLogRecPtr recptr;
HeapTupleHeader hdr = tup->t_data;
diff --git a/src/backend/access/heap/heapam_xlog.c b/src/backend/access/heap/heapam_xlog.c
index f765345e9e4..46fc689302d 100644
--- a/src/backend/access/heap/heapam_xlog.c
+++ b/src/backend/access/heap/heapam_xlog.c
@@ -31,7 +31,7 @@ heap_xlog_prune_freeze(XLogReaderState *record)
{
XLogRecPtr lsn = record->EndRecPtr;
char *maindataptr = XLogRecGetData(record);
- xl_heap_prune xlrec;
+ xl_heap_prune xlrec = {0};
Buffer buffer;
RelFileLocator rlocator;
BlockNumber blkno;
@@ -504,7 +504,7 @@ heap_xlog_insert(XLogReaderState *record)
char data[MaxHeapTupleSize];
} tbuf;
HeapTupleHeader htup;
- xl_heap_header xlhdr;
+ xl_heap_header xlhdr = {0};
uint32 newlen;
Size freespace = 0;
RelFileLocator target_locator;
@@ -828,7 +828,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
HeapTupleHeaderData hdr;
char data[MaxHeapTupleSize];
} tbuf;
- xl_heap_header xlhdr;
+ xl_heap_header xlhdr = {0};
uint32 newlen;
Size freespace = 0;
XLogRedoAction oldaction;
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 632c2427952..d609b63ef97 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -2174,17 +2174,17 @@ log_heap_prune_and_freeze(Relation relation, Buffer buffer,
OffsetNumber *dead, int ndead,
OffsetNumber *unused, int nunused)
{
- xl_heap_prune xlrec;
+ xl_heap_prune xlrec = {0};
XLogRecPtr recptr;
uint8 info;
uint8 regbuf_flags_heap;
/* The following local variables hold data registered in the WAL record: */
xlhp_freeze_plan plans[MaxHeapTuplesPerPage];
- xlhp_freeze_plans freeze_plans;
- xlhp_prune_items redirect_items;
- xlhp_prune_items dead_items;
- xlhp_prune_items unused_items;
+ xlhp_freeze_plans freeze_plans = {0};
+ xlhp_prune_items redirect_items = {0};
+ xlhp_prune_items dead_items = {0};
+ xlhp_prune_items unused_items = {0};
OffsetNumber frz_offsets[MaxHeapTuplesPerPage];
bool do_prune = nredirected > 0 || ndead > 0 || nunused > 0;
bool do_set_vm = vmflags & VISIBILITYMAP_VALID_BITS;
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 77fd48eb59e..2f47222a5c0 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -826,7 +826,7 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
{
char *waldata;
char *waldata_start;
- xl_heap_rewrite_mapping xlrec;
+ xl_heap_rewrite_mapping xlrec = {0};
Oid dboid;
uint32 len;
int written;
diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c
index 95be0b17939..e20590a5547 100644
--- a/src/backend/access/nbtree/nbtdedup.c
+++ b/src/backend/access/nbtree/nbtdedup.c
@@ -246,7 +246,7 @@ _bt_dedup_pass(Relation rel, Buffer buf, IndexTuple newitem, Size newitemsz,
if (RelationNeedsWAL(rel))
{
XLogRecPtr recptr;
- xl_btree_dedup xlrec_dedup;
+ xl_btree_dedup xlrec_dedup = {0};
xlrec_dedup.nintervals = state->nintervals;
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index d17aaa5aa0f..71a62b06692 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1319,8 +1319,8 @@ _bt_insertonpg(Relation rel,
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_btree_insert xlrec;
- xl_btree_metadata xlmeta;
+ xl_btree_insert xlrec = {0};
+ xl_btree_metadata xlmeta = {0};
uint8 xlinfo;
XLogRecPtr recptr;
uint16 upostingoff;
@@ -1981,7 +1981,7 @@ _bt_split(Relation rel, Relation heaprel, BTScanInsert itup_key, Buffer buf,
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_btree_split xlrec;
+ xl_btree_split xlrec = {0};
uint8 xlinfo;
XLogRecPtr recptr;
@@ -2570,9 +2570,9 @@ _bt_newlevel(Relation rel, Relation heaprel, Buffer lbuf, Buffer rbuf)
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_btree_newroot xlrec;
+ xl_btree_newroot xlrec = {0};
XLogRecPtr recptr;
- xl_btree_metadata md;
+ xl_btree_metadata md = {0};
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 4125c185e8b..80f9ec2c846 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -285,7 +285,7 @@ _bt_set_cleanup_info(Relation rel, BlockNumber num_delpages)
/* write wal record if needed */
if (RelationNeedsWAL(rel))
{
- xl_btree_metadata md;
+ xl_btree_metadata md = {0};
XLogRecPtr recptr;
XLogBeginInsert();
@@ -472,9 +472,9 @@ _bt_getroot(Relation rel, Relation heaprel, int access)
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_btree_newroot xlrec;
+ xl_btree_newroot xlrec = {0};
XLogRecPtr recptr;
- xl_btree_metadata md;
+ xl_btree_metadata md = {0};
XLogBeginInsert();
XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT);
@@ -933,7 +933,7 @@ _bt_allocbuf(Relation rel, Relation heaprel)
*/
if (RelationNeedsWAL(rel) && XLogStandbyInfoActive())
{
- xl_btree_reuse_page xlrec_reuse;
+ xl_btree_reuse_page xlrec_reuse = {0};
/*
* Note that we don't register the buffer with the record,
@@ -1227,7 +1227,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf,
if (needswal)
{
XLogRecPtr recptr;
- xl_btree_vacuum xlrec_vacuum;
+ xl_btree_vacuum xlrec_vacuum = {0};
xlrec_vacuum.ndeleted = ndeletable;
xlrec_vacuum.nupdated = nupdatable;
@@ -1343,7 +1343,7 @@ _bt_delitems_delete(Relation rel, Buffer buf,
if (needswal)
{
XLogRecPtr recptr;
- xl_btree_delete xlrec_delete;
+ xl_btree_delete xlrec_delete = {0};
xlrec_delete.snapshotConflictHorizon = snapshotConflictHorizon;
xlrec_delete.ndeleted = ndeletable;
@@ -1439,7 +1439,7 @@ _bt_delitems_update(BTVacuumPosting *updatable, int nupdatable,
{
BTVacuumPosting vacposting = updatable[i];
Size itemsz;
- xl_btree_update update;
+ xl_btree_update update = {0};
update.ndeletedtids = vacposting->ndeletedtids;
memcpy(updatedbuf + offset, &update.ndeletedtids,
@@ -2252,7 +2252,7 @@ _bt_mark_page_halfdead(Relation rel, Relation heaprel, Buffer leafbuf,
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_btree_mark_page_halfdead xlrec;
+ xl_btree_mark_page_halfdead xlrec = {0};
XLogRecPtr recptr;
xlrec.poffset = poffset;
@@ -2673,8 +2673,8 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
- xl_btree_unlink_page xlrec;
- xl_btree_metadata xlmeta;
+ xl_btree_unlink_page xlrec = {0};
+ xl_btree_metadata xlmeta = {0};
uint8 xlinfo;
XLogRecPtr recptr;
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index 022376045d7..5669f0387c6 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -32,7 +32,7 @@ clog_desc(StringInfo buf, XLogReaderState *record)
}
else if (info == CLOG_TRUNCATE)
{
- xl_clog_truncate xlrec;
+ xl_clog_truncate xlrec = {0};
memcpy(&xlrec, rec, sizeof(xl_clog_truncate));
appendStringInfo(buf, "page %" PRId64 "; oldestXact %u",
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 4f53d3035cc..5e9b08b1dac 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -125,7 +125,7 @@ ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *pars
if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
{
- xl_xact_origin xl_origin;
+ xl_xact_origin xl_origin = {0};
/* no alignment is guaranteed, so copy onto stack */
memcpy(&xl_origin, data, sizeof(xl_origin));
@@ -220,7 +220,7 @@ ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
{
- xl_xact_origin xl_origin;
+ xl_xact_origin xl_origin = {0};
/* no alignment is guaranteed, so copy onto stack */
memcpy(&xl_origin, data, sizeof(xl_origin));
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index ff078f22264..6b3341d746e 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -116,7 +116,7 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
}
else if (info == XLOG_PARAMETER_CHANGE)
{
- xl_parameter_change xlrec;
+ xl_parameter_change xlrec = {0};
const char *wal_level_str;
memcpy(&xlrec, rec, sizeof(xl_parameter_change));
@@ -144,7 +144,7 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
}
else if (info == XLOG_END_OF_RECOVERY)
{
- xl_end_of_recovery xlrec;
+ xl_end_of_recovery xlrec = {0};
memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
appendStringInfo(buf, "tli %u; prev tli %u; time %s; wal_level %s",
@@ -154,7 +154,7 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
}
else if (info == XLOG_OVERWRITE_CONTRECORD)
{
- xl_overwrite_contrecord xlrec;
+ xl_overwrite_contrecord xlrec = {0};
memcpy(&xlrec, rec, sizeof(xl_overwrite_contrecord));
appendStringInfo(buf, "lsn %X/%08X; time %s",
diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index 7c7371c69e8..44e29814b10 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -202,7 +202,7 @@ static void
addLeafTuple(Relation index, SpGistState *state, SpGistLeafTuple leafTuple,
SPPageDesc *current, SPPageDesc *parent, bool isNulls, bool isNew)
{
- spgxlogAddLeaf xlrec;
+ spgxlogAddLeaf xlrec = {0};
xlrec.newPage = isNew;
xlrec.storesNulls = isNulls;
@@ -399,7 +399,7 @@ moveLeafs(Relation index, SpGistState *state,
OffsetNumber *toDelete;
OffsetNumber *toInsert;
BlockNumber nblkno;
- spgxlogMoveLeafs xlrec;
+ spgxlogMoveLeafs xlrec = {0};
char *leafdata,
*leafptr;
@@ -702,7 +702,7 @@ doPickSplit(Relation index, SpGistState *state,
int currentFreeSpace;
int totalLeafSizes;
bool allTheSame;
- spgxlogPickSplit xlrec;
+ spgxlogPickSplit xlrec = {0};
char *leafdata,
*leafptr;
SPPageDesc saveCurrent;
@@ -1512,7 +1512,7 @@ spgAddNodeAction(Relation index, SpGistState *state,
int nodeN, Datum nodeLabel)
{
SpGistInnerTuple newInnerTuple;
- spgxlogAddNode xlrec;
+ spgxlogAddNode xlrec = {0};
/* Should not be applied to nulls */
Assert(!SpGistPageStoresNulls(current->page));
@@ -1719,7 +1719,7 @@ spgSplitNodeAction(Relation index, SpGistState *state,
BlockNumber postfixBlkno;
OffsetNumber postfixOffset;
int i;
- spgxlogSplitTuple xlrec;
+ spgxlogSplitTuple xlrec = {0};
Buffer newBuffer = InvalidBuffer;
/* Should not be applied to nulls */
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index 6b7117b56b2..77947723d04 100644
--- a/src/backend/access/spgist/spgvacuum.c
+++ b/src/backend/access/spgist/spgvacuum.c
@@ -127,7 +127,7 @@ vacuumLeafPage(spgBulkDeleteState *bds, Relation index, Buffer buffer,
bool forPending)
{
Page page = BufferGetPage(buffer);
- spgxlogVacuumLeaf xlrec;
+ spgxlogVacuumLeaf xlrec = {0};
OffsetNumber toDead[MaxIndexTuplesPerPage];
OffsetNumber toPlaceholder[MaxIndexTuplesPerPage];
OffsetNumber moveSrc[MaxIndexTuplesPerPage];
@@ -409,7 +409,7 @@ static void
vacuumLeafRoot(spgBulkDeleteState *bds, Relation index, Buffer buffer)
{
Page page = BufferGetPage(buffer);
- spgxlogVacuumRoot xlrec;
+ spgxlogVacuumRoot xlrec = {0};
OffsetNumber toDelete[MaxIndexTuplesPerPage];
OffsetNumber i,
max = PageGetMaxOffsetNumber(page);
@@ -502,7 +502,7 @@ vacuumRedirectAndPlaceholder(Relation index, Relation heaprel, Buffer buffer)
bool hasUpdate = false;
OffsetNumber itemToPlaceholder[MaxIndexTuplesPerPage];
OffsetNumber itemnos[MaxIndexTuplesPerPage];
- spgxlogVacuumRedirect xlrec;
+ spgxlogVacuumRedirect xlrec = {0};
GlobalVisState *vistest;
xlrec.isCatalogRel = RelationIsAccessibleInLogicalDecoding(heaprel);
diff --git a/src/backend/access/spgist/spgxlog.c b/src/backend/access/spgist/spgxlog.c
index 55e8066a77b..b2d258f6c28 100644
--- a/src/backend/access/spgist/spgxlog.c
+++ b/src/backend/access/spgist/spgxlog.c
@@ -77,7 +77,7 @@ spgRedoAddLeaf(XLogReaderState *record)
char *ptr = XLogRecGetData(record);
spgxlogAddLeaf *xldata = (spgxlogAddLeaf *) ptr;
char *leafTuple;
- SpGistLeafTupleData leafTupleHdr;
+ SpGistLeafTupleData leafTupleHdr = {0};
Buffer buffer;
Page page;
XLogRedoAction action;
@@ -221,7 +221,7 @@ spgRedoMoveLeafs(XLogReaderState *record)
for (i = 0; i < nInsert; i++)
{
char *leafTuple;
- SpGistLeafTupleData leafTupleHdr;
+ SpGistLeafTupleData leafTupleHdr = {0};
/*
* the tuples are not aligned, so must copy to access the size
@@ -285,7 +285,7 @@ spgRedoAddNode(XLogReaderState *record)
char *ptr = XLogRecGetData(record);
spgxlogAddNode *xldata = (spgxlogAddNode *) ptr;
char *innerTuple;
- SpGistInnerTupleData innerTupleHdr;
+ SpGistInnerTupleData innerTupleHdr = {0};
SpGistState state;
Buffer buffer;
Page page;
@@ -451,9 +451,9 @@ spgRedoSplitTuple(XLogReaderState *record)
char *ptr = XLogRecGetData(record);
spgxlogSplitTuple *xldata = (spgxlogSplitTuple *) ptr;
char *prefixTuple;
- SpGistInnerTupleData prefixTupleHdr;
+ SpGistInnerTupleData prefixTupleHdr = {0};
char *postfixTuple;
- SpGistInnerTupleData postfixTupleHdr;
+ SpGistInnerTupleData postfixTupleHdr = {0};
Buffer buffer;
Page page;
XLogRedoAction action;
@@ -526,7 +526,7 @@ spgRedoPickSplit(XLogReaderState *record)
char *ptr = XLogRecGetData(record);
spgxlogPickSplit *xldata = (spgxlogPickSplit *) ptr;
char *innerTuple;
- SpGistInnerTupleData innerTupleHdr;
+ SpGistInnerTupleData innerTupleHdr = {0};
SpGistState state;
OffsetNumber *toDelete;
OffsetNumber *toInsert;
@@ -645,7 +645,7 @@ spgRedoPickSplit(XLogReaderState *record)
for (i = 0; i < xldata->nInsert; i++)
{
char *leafTuple;
- SpGistLeafTupleData leafTupleHdr;
+ SpGistLeafTupleData leafTupleHdr = {0};
/* the tuples are not aligned, so must copy to access the size field. */
leafTuple = ptr;
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index b5c38bbb162..d62d22ef444 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -1044,7 +1044,7 @@ static void
WriteTruncateXlogRec(int64 pageno, TransactionId oldestXact, Oid oldestXactDb)
{
XLogRecPtr recptr;
- xl_clog_truncate xlrec;
+ xl_clog_truncate xlrec = {0};
xlrec.pageno = pageno;
xlrec.oldestXact = oldestXact;
@@ -1076,7 +1076,7 @@ clog_redo(XLogReaderState *record)
}
else if (info == CLOG_TRUNCATE)
{
- xl_clog_truncate xlrec;
+ xl_clog_truncate xlrec = {0};
memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_clog_truncate));
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 6fa2178f1dd..55349042ed7 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -966,7 +966,7 @@ CommitTsPagePrecedes(int64 page1, int64 page2)
static void
WriteTruncateXlogRec(int64 pageno, TransactionId oldestXid)
{
- xl_commit_ts_truncate xlrec;
+ xl_commit_ts_truncate xlrec = {0};
xlrec.pageno = pageno;
xlrec.oldestXid = oldestXid;
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 90ec87d9dd6..a005bbed209 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -657,7 +657,7 @@ MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
{
MultiXactId multi;
MultiXactOffset offset;
- xl_multixact_create xlrec;
+ xl_multixact_create xlrec = {0};
debug_elog3(DEBUG2, "Create: %s",
mxid_to_string(InvalidMultiXactId, nmembers, members));
@@ -728,7 +728,7 @@ MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
*/
XLogBeginInsert();
XLogRegisterData(&xlrec, SizeOfMultiXactCreate);
- XLogRegisterData(members, nmembers * sizeof(MultiXactMember));
+ XLogRegisterData((char *) members, nmembers * sizeof(MultiXactMember));
(void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID);
@@ -2796,7 +2796,7 @@ WriteMTruncateXlogRec(Oid oldestMultiDB,
MultiXactOffset oldestOffset)
{
XLogRecPtr recptr;
- xl_multixact_truncate xlrec;
+ xl_multixact_truncate xlrec = {0};
xlrec.oldestMultiDB = oldestMultiDB;
xlrec.oldestMulti = oldestMulti;
@@ -2864,7 +2864,7 @@ multixact_redo(XLogReaderState *record)
}
else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
{
- xl_multixact_truncate xlrec;
+ xl_multixact_truncate xlrec = {0};
int64 pageno;
memcpy(&xlrec, XLogRecGetData(record),
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index eba4f063168..df72a2566e6 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -761,7 +761,7 @@ AssignTransactionId(TransactionState s)
if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS ||
log_unknown_top)
{
- xl_xact_assignment xlrec;
+ xl_xact_assignment xlrec = {0};
/*
* xtop is always set by now because we recurse up transaction
@@ -5842,15 +5842,15 @@ XactLogCommitRecord(TimestampTz commit_time,
int xactflags, TransactionId twophase_xid,
const char *twophase_gid)
{
- xl_xact_commit xlrec;
- xl_xact_xinfo xl_xinfo;
- xl_xact_dbinfo xl_dbinfo;
- xl_xact_subxacts xl_subxacts;
- xl_xact_relfilelocators xl_relfilelocators;
- xl_xact_stats_items xl_dropped_stats;
- xl_xact_invals xl_invals;
- xl_xact_twophase xl_twophase;
- xl_xact_origin xl_origin;
+ xl_xact_commit xlrec = {0};
+ xl_xact_xinfo xl_xinfo = {0};
+ xl_xact_dbinfo xl_dbinfo = {0};
+ xl_xact_subxacts xl_subxacts = {0};
+ xl_xact_relfilelocators xl_relfilelocators = {0};
+ xl_xact_stats_items xl_dropped_stats = {0};
+ xl_xact_invals xl_invals = {0};
+ xl_xact_twophase xl_twophase = {0};
+ xl_xact_origin xl_origin = {0};
uint8 info;
Assert(CritSectionCount > 0);
@@ -5963,7 +5963,7 @@ XactLogCommitRecord(TimestampTz commit_time,
{
XLogRegisterData(&xl_relfilelocators,
MinSizeOfXactRelfileLocators);
- XLogRegisterData(rels,
+ XLogRegisterData((char *) rels,
nrels * sizeof(RelFileLocator));
}
@@ -5971,14 +5971,14 @@ XactLogCommitRecord(TimestampTz commit_time,
{
XLogRegisterData(&xl_dropped_stats,
MinSizeOfXactStatsItems);
- XLogRegisterData(droppedstats,
+ XLogRegisterData((char *) droppedstats,
ndroppedstats * sizeof(xl_xact_stats_item));
}
if (xl_xinfo.xinfo & XACT_XINFO_HAS_INVALS)
{
XLogRegisterData(&xl_invals, MinSizeOfXactInvals);
- XLogRegisterData(msgs,
+ XLogRegisterData((char *) msgs,
nmsgs * sizeof(SharedInvalidationMessage));
}
@@ -6012,14 +6012,14 @@ XactLogAbortRecord(TimestampTz abort_time,
int xactflags, TransactionId twophase_xid,
const char *twophase_gid)
{
- xl_xact_abort xlrec;
- xl_xact_xinfo xl_xinfo;
- xl_xact_subxacts xl_subxacts;
- xl_xact_relfilelocators xl_relfilelocators;
- xl_xact_stats_items xl_dropped_stats;
- xl_xact_twophase xl_twophase;
- xl_xact_dbinfo xl_dbinfo;
- xl_xact_origin xl_origin;
+ xl_xact_abort xlrec = {0};
+ xl_xact_xinfo xl_xinfo = {0};
+ xl_xact_subxacts xl_subxacts = {0};
+ xl_xact_relfilelocators xl_relfilelocators = {0};
+ xl_xact_stats_items xl_dropped_stats = {0};
+ xl_xact_twophase xl_twophase = {0};
+ xl_xact_dbinfo xl_dbinfo = {0};
+ xl_xact_origin xl_origin = {0};
uint8 info;
@@ -6116,7 +6116,7 @@ XactLogAbortRecord(TimestampTz abort_time,
{
XLogRegisterData(&xl_relfilelocators,
MinSizeOfXactRelfileLocators);
- XLogRegisterData(rels,
+ XLogRegisterData((char *) rels,
nrels * sizeof(RelFileLocator));
}
@@ -6124,7 +6124,7 @@ XactLogAbortRecord(TimestampTz abort_time,
{
XLogRegisterData(&xl_dropped_stats,
MinSizeOfXactStatsItems);
- XLogRegisterData(droppedstats,
+ XLogRegisterData((char *) droppedstats,
ndroppedstats * sizeof(xl_xact_stats_item));
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13cce9b49f1..45832a59e1d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5125,7 +5125,7 @@ XLOGShmemInit(void)
void
BootStrapXLOG(uint32 data_checksum_version)
{
- CheckPoint checkPoint;
+ CheckPoint checkPoint = {0};
PGAlignedXLogBlock buffer;
XLogPageHeader page;
XLogLongPageHeader longpage;
@@ -5207,6 +5207,7 @@ BootStrapXLOG(uint32 data_checksum_version)
/* Insert the initial checkpoint record */
recptr = ((char *) page + SizeOfXLogLongPHD);
record = (XLogRecord *) recptr;
+ memset(record, 0, SizeOfXLogRecord);
record->xl_prev = InvalidXLogRecPtr;
record->xl_xid = InvalidTransactionId;
record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(checkPoint);
@@ -5517,7 +5518,7 @@ void
StartupXLOG(void)
{
XLogCtlInsert *Insert;
- CheckPoint checkPoint;
+ CheckPoint checkPoint = {0};
bool wasShutdown;
bool didCrash;
bool haveTblspcMap;
@@ -7025,7 +7026,7 @@ bool
CreateCheckPoint(int flags)
{
bool shutdown;
- CheckPoint checkPoint;
+ CheckPoint checkPoint = {0};
XLogRecPtr recptr;
XLogSegNo _logSegNo;
XLogCtlInsert *Insert = &XLogCtl->Insert;
@@ -7515,7 +7516,7 @@ CreateCheckPoint(int flags)
static void
CreateEndOfRecoveryRecord(void)
{
- xl_end_of_recovery xlrec;
+ xl_end_of_recovery xlrec = {0};
XLogRecPtr recptr;
/* sanity check */
@@ -7581,7 +7582,7 @@ static XLogRecPtr
CreateOverwriteContrecordRecord(XLogRecPtr aborted_lsn, XLogRecPtr pagePtr,
TimeLineID newTLI)
{
- xl_overwrite_contrecord xlrec;
+ xl_overwrite_contrecord xlrec = {0};
XLogRecPtr recptr;
XLogPageHeader pagehdr;
XLogRecPtr startPos;
@@ -7732,7 +7733,7 @@ CreateRestartPoint(int flags)
{
XLogRecPtr lastCheckPointRecPtr;
XLogRecPtr lastCheckPointEndPtr;
- CheckPoint lastCheckPoint;
+ CheckPoint lastCheckPoint = {0};
XLogRecPtr PriorRedoPtr;
XLogRecPtr receivePtr;
XLogRecPtr replayPtr;
@@ -8223,7 +8224,7 @@ XLogRecPtr
XLogRestorePoint(const char *rpName)
{
XLogRecPtr RecPtr;
- xl_restore_point xlrec;
+ xl_restore_point xlrec = {0};
xlrec.rp_time = GetCurrentTimestamp();
strlcpy(xlrec.rp_name, rpName, MAXFNAMELEN);
@@ -8265,7 +8266,7 @@ XLogReportParameters(void)
*/
if (wal_level != ControlFile->wal_level || XLogIsNeeded())
{
- xl_parameter_change xlrec;
+ xl_parameter_change xlrec = {0};
XLogRecPtr recptr;
xlrec.MaxConnections = MaxConnections;
@@ -8408,7 +8409,7 @@ xlog_redo(XLogReaderState *record)
}
else if (info == XLOG_CHECKPOINT_SHUTDOWN)
{
- CheckPoint checkPoint;
+ CheckPoint checkPoint = {0};
TimeLineID replayTLI;
memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
@@ -8509,7 +8510,7 @@ xlog_redo(XLogReaderState *record)
}
else if (info == XLOG_CHECKPOINT_ONLINE)
{
- CheckPoint checkPoint;
+ CheckPoint checkPoint = {0};
TimeLineID replayTLI;
memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
@@ -8574,7 +8575,7 @@ xlog_redo(XLogReaderState *record)
}
else if (info == XLOG_END_OF_RECOVERY)
{
- xl_end_of_recovery xlrec;
+ xl_end_of_recovery xlrec = {0};
TimeLineID replayTLI;
memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_end_of_recovery));
@@ -8647,7 +8648,7 @@ xlog_redo(XLogReaderState *record)
}
else if (info == XLOG_PARAMETER_CHANGE)
{
- xl_parameter_change xlrec;
+ xl_parameter_change xlrec = {0};
/* Update our copy of the parameters in pg_control */
memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_parameter_change));
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index a9a1678acc9..d1b6fbea81c 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -584,6 +584,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
/* The record begins with the fixed-size header */
rechdr = (XLogRecord *) scratch;
+ memset(rechdr, 0, SizeOfXLogRecord);
scratch += SizeOfXLogRecord;
hdr_rdt.next = NULL;
@@ -610,8 +611,8 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
registered_buffer *regbuf = ®istered_buffers[block_id];
bool needs_backup;
bool needs_data;
- XLogRecordBlockHeader bkpb;
- XLogRecordBlockImageHeader bimg;
+ XLogRecordBlockHeader bkpb = {0};
+ XLogRecordBlockImageHeader bimg = {0};
XLogRecordBlockCompressHeader cbimg = {0};
bool samerel;
bool is_compressed = false;
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 03ada8aa0c5..6c743f8c98d 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -1806,9 +1806,12 @@ DecodeXLogRecord(XLogReaderState *state,
if (blk->has_image)
{
+ uint8 bimg_pad;
+
COPY_HEADER_FIELD(&blk->bimg_len, sizeof(uint16));
COPY_HEADER_FIELD(&blk->hole_offset, sizeof(uint16));
COPY_HEADER_FIELD(&blk->bimg_info, sizeof(uint8));
+ COPY_HEADER_FIELD(&bimg_pad, sizeof(uint8));
blk->apply_image = ((blk->bimg_info & BKPIMAGE_APPLY) != 0);
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index ecd66fd86a4..75bd50ec278 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -526,7 +526,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
DBState dbstate_at_startup;
bool haveTblspcMap = false;
bool haveBackupLabel = false;
- CheckPoint checkPoint;
+ CheckPoint checkPoint = {0};
bool backupFromStandby = false;
dbstate_at_startup = ControlFile->state;
@@ -1971,7 +1971,7 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl
if (info == XLOG_CHECKPOINT_SHUTDOWN)
{
- CheckPoint checkPoint;
+ CheckPoint checkPoint = {0};
memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
newReplayTLI = checkPoint.ThisTimeLineID;
@@ -1979,7 +1979,7 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl
}
else if (info == XLOG_END_OF_RECOVERY)
{
- xl_end_of_recovery xlrec;
+ xl_end_of_recovery xlrec = {0};
memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
newReplayTLI = xlrec.ThisTimeLineID;
@@ -2113,7 +2113,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
if (info == XLOG_OVERWRITE_CONTRECORD)
{
/* Verify the payload of a XLOG_OVERWRITE_CONTRECORD record. */
- xl_overwrite_contrecord xlrec;
+ xl_overwrite_contrecord xlrec = {0};
memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_overwrite_contrecord));
if (xlrec.overwritten_lsn != record->overwrittenRecPtr)
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index e443a4993c5..f82fce1f929 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -186,7 +186,7 @@ RelationCreateStorage(RelFileLocator rlocator, char relpersistence,
void
log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
{
- xl_smgr_create xlrec;
+ xl_smgr_create xlrec = {0};
/*
* Make an XLOG entry reporting the file creation.
@@ -391,7 +391,7 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
* Make an XLOG entry reporting the file truncation.
*/
XLogRecPtr lsn;
- xl_smgr_truncate xlrec;
+ xl_smgr_truncate xlrec = {0};
xlrec.blkno = nblocks;
xlrec.rlocator = rel->rd_locator;
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 740c526e92d..42f3fd1c931 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -524,7 +524,7 @@ CreateDirAndVersionFile(char *dbpath, Oid dbid, Oid tsid, bool isRedo)
/* If we are not in WAL replay then write the WAL. */
if (!isRedo)
{
- xl_dbase_create_wal_log_rec xlrec;
+ xl_dbase_create_wal_log_rec xlrec = {0};
START_CRIT_SECTION();
@@ -620,7 +620,7 @@ CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, Oid src_tsid,
/* Record the filesystem change in XLOG */
{
- xl_dbase_create_file_copy_rec xlrec;
+ xl_dbase_create_file_copy_rec xlrec = {0};
xlrec.db_id = dst_dboid;
xlrec.tablespace_id = dsttablespace;
@@ -2215,7 +2215,7 @@ movedb(const char *dbname, const char *tblspcname)
* Record the filesystem change in XLOG
*/
{
- xl_dbase_create_file_copy_rec xlrec;
+ xl_dbase_create_file_copy_rec xlrec = {0};
xlrec.db_id = db_id;
xlrec.tablespace_id = dst_tblspcoid;
@@ -2313,7 +2313,7 @@ movedb(const char *dbname, const char *tblspcname)
* Record the filesystem change in XLOG
*/
{
- xl_dbase_drop_rec xlrec;
+ xl_dbase_drop_rec xlrec = {0};
xlrec.db_id = db_id;
xlrec.ntablespaces = 1;
@@ -3072,7 +3072,7 @@ remove_dbtablespaces(Oid db_id)
/* Record the filesystem change in XLOG */
{
- xl_dbase_drop_rec xlrec;
+ xl_dbase_drop_rec xlrec = {0};
xlrec.db_id = db_id;
xlrec.ntablespaces = ntblspc;
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index e1b808bbb60..f59be766238 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -399,7 +399,7 @@ fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum)
/* XLOG stuff */
if (RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM)
{
- xl_seq_rec xlrec;
+ xl_seq_rec xlrec = {0};
XLogRecPtr recptr;
XLogBeginInsert();
@@ -408,7 +408,7 @@ fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum)
xlrec.locator = rel->rd_locator;
XLogRegisterData(&xlrec, sizeof(xl_seq_rec));
- XLogRegisterData(tuple->t_data, tuple->t_len);
+ XLogRegisterData((char *) tuple->t_data, tuple->t_len);
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
@@ -822,7 +822,7 @@ nextval_internal(Oid relid, bool check_permissions)
/* XLOG stuff */
if (logit && RelationNeedsWAL(seqrel))
{
- xl_seq_rec xlrec;
+ xl_seq_rec xlrec = {0};
XLogRecPtr recptr;
/*
@@ -842,7 +842,7 @@ nextval_internal(Oid relid, bool check_permissions)
xlrec.locator = seqrel->rd_locator;
XLogRegisterData(&xlrec, sizeof(xl_seq_rec));
- XLogRegisterData(seqdatatuple.t_data, seqdatatuple.t_len);
+ XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
@@ -1019,7 +1019,7 @@ SetSequence(Oid relid, int64 next, bool iscalled)
/* XLOG stuff */
if (RelationNeedsWAL(seqrel))
{
- xl_seq_rec xlrec;
+ xl_seq_rec xlrec = {0};
XLogRecPtr recptr;
Page page = BufferGetPage(buf);
@@ -1028,7 +1028,7 @@ SetSequence(Oid relid, int64 next, bool iscalled)
xlrec.locator = seqrel->rd_locator;
XLogRegisterData(&xlrec, sizeof(xl_seq_rec));
- XLogRegisterData(seqdatatuple.t_data, seqdatatuple.t_len);
+ XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b04b0dbd2a0..f04d647186c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2307,7 +2307,7 @@ ExecuteTruncateGuts(List *explicit_rels,
*/
if (relids_logged != NIL)
{
- xl_heap_truncate xlrec;
+ xl_heap_truncate xlrec = {0};
int i = 0;
/* should only get here if effective_wal_level is 'logical' */
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index ed2a93a09db..fca45c5137a 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -365,7 +365,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
/* Record the filesystem change in XLOG */
{
- xl_tblspc_create_rec xlrec;
+ xl_tblspc_create_rec xlrec = {0};
xlrec.ts_id = tablespaceoid;
@@ -535,7 +535,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
/* Record the filesystem change in XLOG */
{
- xl_tblspc_drop_rec xlrec;
+ xl_tblspc_drop_rec xlrec = {0};
xlrec.ts_id = tablespaceoid;
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index 742137edad6..e0eb2bea0f1 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -1431,7 +1431,7 @@ SummarizeXlogRecord(XLogReaderState *xlogreader, bool *new_fast_forward)
}
else if (info == XLOG_CHECKPOINT_SHUTDOWN)
{
- CheckPoint rec_ckpt;
+ CheckPoint rec_ckpt = {0};
/* Extract wal_level at time record was written from payload. */
memcpy(&rec_ckpt, XLogRecGetData(xlogreader), sizeof(CheckPoint));
@@ -1439,7 +1439,7 @@ SummarizeXlogRecord(XLogReaderState *xlogreader, bool *new_fast_forward)
}
else if (info == XLOG_PARAMETER_CHANGE)
{
- xl_parameter_change xlrec;
+ xl_parameter_change xlrec = {0};
/* Extract wal_level at time record was written from payload. */
memcpy(&xlrec, XLogRecGetData(xlogreader),
@@ -1448,7 +1448,7 @@ SummarizeXlogRecord(XLogReaderState *xlogreader, bool *new_fast_forward)
}
else if (info == XLOG_END_OF_RECOVERY)
{
- xl_end_of_recovery xlrec;
+ xl_end_of_recovery xlrec = {0};
/* Extract wal_level at time record was written from payload. */
memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 21f03864a66..867cf9d0158 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -1245,7 +1245,7 @@ DecodeSpecConfirm(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
static void
DecodeXLogTuple(char *data, Size len, HeapTuple tuple)
{
- xl_heap_header xlhdr;
+ xl_heap_header xlhdr = {0};
int datalen = len - SizeOfHeapHeader;
HeapTupleHeader header;
diff --git a/src/backend/replication/logical/message.c b/src/backend/replication/logical/message.c
index 06825d66e7f..5a165c591cb 100644
--- a/src/backend/replication/logical/message.c
+++ b/src/backend/replication/logical/message.c
@@ -43,7 +43,7 @@ XLogRecPtr
LogLogicalMessage(const char *prefix, const char *message, size_t size,
bool transactional, bool flush)
{
- xl_logical_message xlrec;
+ xl_logical_message xlrec = {0};
XLogRecPtr lsn;
/*
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index c3271a6fd0e..3a3dee4c411 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -419,7 +419,7 @@ restart:
/* first make a WAL log entry */
{
- xl_replorigin_drop xlrec;
+ xl_replorigin_drop xlrec = {0};
xlrec.node_id = roident;
XLogBeginInsert();
@@ -1008,7 +1008,7 @@ replorigin_advance(ReplOriginId node,
*/
if (wal_log)
{
- xl_replorigin_set xlrec;
+ xl_replorigin_set xlrec = {0};
xlrec.remote_lsn = remote_commit;
xlrec.node_id = node;
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index d83afbfb9d6..6b950fbab86 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -987,7 +987,7 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
{
RecoveryLockXidEntry *xidentry;
RecoveryLockEntry *lockentry;
- xl_standby_lock key;
+ xl_standby_lock key = {0};
LOCKTAG locktag;
bool found;
@@ -1353,7 +1353,7 @@ LogStandbySnapshot(void)
static XLogRecPtr
LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
{
- xl_running_xacts xlrec;
+ xl_running_xacts xlrec = {0};
XLogRecPtr recptr;
xlrec.xcnt = CurrRunningXacts->xcnt;
@@ -1413,7 +1413,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
static void
LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
{
- xl_standby_locks xlrec;
+ xl_standby_locks xlrec = {0};
xlrec.nlocks = nlocks;
@@ -1431,7 +1431,7 @@ LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
void
LogAccessExclusiveLock(Oid dbOid, Oid relOid)
{
- xl_standby_lock xlrec;
+ xl_standby_lock xlrec = {0};
xlrec.xid = GetCurrentTransactionId();
@@ -1471,10 +1471,8 @@ void
LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs,
bool relcacheInitFileInval)
{
- xl_invalidations xlrec;
+ xl_invalidations xlrec = {0};
- /* prepare record */
- memset(&xlrec, 0, sizeof(xlrec));
xlrec.dbId = MyDatabaseId;
xlrec.tsId = MyDatabaseTableSpace;
xlrec.relcacheInitFileInval = relcacheInitFileInval;
@@ -1483,7 +1481,7 @@ LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs,
/* perform insertion */
XLogBeginInsert();
XLogRegisterData(&xlrec, MinSizeOfInvalidations);
- XLogRegisterData(msgs,
+ XLogRegisterData((char *) msgs,
nmsgs * sizeof(SharedInvalidationMessage));
XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS);
}
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index d59216b28f1..389b493e21b 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -1938,7 +1938,7 @@ CallRelSyncCallbacks(Oid relid)
void
LogLogicalInvalidations(void)
{
- xl_xact_invals xlrec;
+ xl_xact_invals xlrec = {0};
InvalidationMsgsGroup *group;
int nmsgs;
@@ -1959,10 +1959,10 @@ LogLogicalInvalidations(void)
XLogBeginInsert();
XLogRegisterData(&xlrec, MinSizeOfXactInvals);
ProcessMessageSubGroupMulti(group, CatCacheMsgs,
- XLogRegisterData(msgs,
+ XLogRegisterData((char *) msgs,
n * sizeof(SharedInvalidationMessage)));
ProcessMessageSubGroupMulti(group, RelCacheMsgs,
- XLogRegisterData(msgs,
+ XLogRegisterData((char *) msgs,
n * sizeof(SharedInvalidationMessage)));
XLogInsert(RM_XACT_ID, XLOG_XACT_INVALIDATIONS);
}
diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c
index 778b14a2318..896c153bf87 100644
--- a/src/backend/utils/cache/relmapper.c
+++ b/src/backend/utils/cache/relmapper.c
@@ -86,7 +86,7 @@ typedef struct RelMapping
RelFileNumber mapfilenumber; /* its rel file number */
} RelMapping;
-typedef struct RelMapFile
+typedef struct PG_NO_PADDING RelMapFile
{
int32 magic; /* always RELMAPPER_FILEMAGIC */
int32 num_mappings; /* number of valid RelMapping entries */
@@ -264,7 +264,7 @@ RelationMapFilenumberToOid(RelFileNumber filenumber, bool shared)
RelFileNumber
RelationMapOidToFilenumberForDatabase(char *dbpath, Oid relationId)
{
- RelMapFile map;
+ RelMapFile map = {0};
int i;
/* Read the relmap file from the source database. */
@@ -291,7 +291,7 @@ RelationMapOidToFilenumberForDatabase(char *dbpath, Oid relationId)
void
RelationMapCopy(Oid dbid, Oid tsid, char *srcdbpath, char *dstdbpath)
{
- RelMapFile map;
+ RelMapFile map = {0};
/*
* Read the relmap file from the source database.
@@ -958,7 +958,7 @@ write_relmap_file(RelMapFile *newmap, bool write_wal, bool send_sinval,
if (write_wal)
{
- xl_relmap_update xlrec;
+ xl_relmap_update xlrec = {0};
XLogRecPtr lsn;
/* now errors are fatal ... */
@@ -1038,7 +1038,7 @@ write_relmap_file(RelMapFile *newmap, bool write_wal, bool send_sinval,
static void
perform_relmap_update(bool shared, const RelMapFile *updates)
{
- RelMapFile newmap;
+ RelMapFile newmap = {0};
/*
* Anyone updating a relation's mapping info should take exclusive lock on
@@ -1103,7 +1103,7 @@ relmap_redo(XLogReaderState *record)
if (info == XLOG_RELMAP_UPDATE)
{
xl_relmap_update *xlrec = (xl_relmap_update *) XLogRecGetData(record);
- RelMapFile newmap;
+ RelMapFile newmap = {0};
char *dbpath;
if (xlrec->nbytes != sizeof(RelMapFile))
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index ab766c34d4b..04a7168240a 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -1152,6 +1152,7 @@ WriteEmptyXLOG(void)
/* Insert the initial checkpoint record */
recptr = (char *) page + SizeOfXLogLongPHD;
record = (XLogRecord *) recptr;
+ memset(record, 0, SizeOfXLogRecord);
record->xl_prev = InvalidXLogRecPtr;
record->xl_xid = InvalidTransactionId;
record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
diff --git a/src/include/access/brin_xlog.h b/src/include/access/brin_xlog.h
index 1c60dc8adb9..b22137970d3 100644
--- a/src/include/access/brin_xlog.h
+++ b/src/include/access/brin_xlog.h
@@ -47,12 +47,13 @@
*
* Backup block 0: metapage
*/
-typedef struct xl_brin_createidx
+typedef struct PG_NO_PADDING xl_brin_createidx
{
BlockNumber pagesPerRange;
uint16 version;
+ pg_padding_2(pg_pad);
} xl_brin_createidx;
-#define SizeOfBrinCreateIdx (offsetof(xl_brin_createidx, version) + sizeof(uint16))
+#define SizeOfBrinCreateIdx (sizeof(xl_brin_createidx))
/*
* This is what we need to know about a BRIN tuple insert
@@ -60,7 +61,7 @@ typedef struct xl_brin_createidx
* Backup block 0: main page, block data is the new BrinTuple.
* Backup block 1: revmap page
*/
-typedef struct xl_brin_insert
+typedef struct PG_NO_PADDING xl_brin_insert
{
BlockNumber heapBlk;
@@ -69,9 +70,10 @@ typedef struct xl_brin_insert
/* offset number in the main page to insert the tuple to. */
OffsetNumber offnum;
+ pg_padding_2(pg_pad);
} xl_brin_insert;
-#define SizeOfBrinInsert (offsetof(xl_brin_insert, offnum) + sizeof(OffsetNumber))
+#define SizeOfBrinInsert (sizeof(xl_brin_insert))
/*
* A cross-page update is the same as an insert, but also stores information
@@ -84,27 +86,28 @@ typedef struct xl_brin_insert
* And in addition:
* Backup block 2: old page
*/
-typedef struct xl_brin_update
+typedef struct PG_NO_PADDING xl_brin_update
{
/* offset number of old tuple on old page */
OffsetNumber oldOffnum;
+ pg_padding_2(pg_pad);
xl_brin_insert insert;
} xl_brin_update;
-#define SizeOfBrinUpdate (offsetof(xl_brin_update, insert) + SizeOfBrinInsert)
+#define SizeOfBrinUpdate (sizeof(xl_brin_update))
/*
* This is what we need to know about a BRIN tuple samepage update
*
* Backup block 0: updated page, with new BrinTuple as block data
*/
-typedef struct xl_brin_samepage_update
+typedef struct PG_NO_PADDING xl_brin_samepage_update
{
OffsetNumber offnum;
} xl_brin_samepage_update;
-#define SizeOfBrinSamepageUpdate (sizeof(OffsetNumber))
+#define SizeOfBrinSamepageUpdate (sizeof(xl_brin_samepage_update))
/*
* This is what we need to know about a revmap extension
@@ -112,7 +115,7 @@ typedef struct xl_brin_samepage_update
* Backup block 0: metapage
* Backup block 1: new revmap page
*/
-typedef struct xl_brin_revmap_extend
+typedef struct PG_NO_PADDING xl_brin_revmap_extend
{
/*
* XXX: This is actually redundant - the block number is stored as part of
@@ -121,8 +124,7 @@ typedef struct xl_brin_revmap_extend
BlockNumber targetBlk;
} xl_brin_revmap_extend;
-#define SizeOfBrinRevmapExtend (offsetof(xl_brin_revmap_extend, targetBlk) + \
- sizeof(BlockNumber))
+#define SizeOfBrinRevmapExtend (sizeof(xl_brin_revmap_extend))
/*
* This is what we need to know about a range de-summarization
@@ -130,17 +132,17 @@ typedef struct xl_brin_revmap_extend
* Backup block 0: revmap page
* Backup block 1: regular page
*/
-typedef struct xl_brin_desummarize
+typedef struct PG_NO_PADDING xl_brin_desummarize
{
BlockNumber pagesPerRange;
/* page number location to set to invalid */
BlockNumber heapBlk;
/* offset of item to delete in regular index page */
OffsetNumber regOffset;
+ pg_padding_2(pg_pad);
} xl_brin_desummarize;
-#define SizeOfBrinDesummarize (offsetof(xl_brin_desummarize, regOffset) + \
- sizeof(OffsetNumber))
+#define SizeOfBrinDesummarize (sizeof(xl_brin_desummarize))
extern void brin_redo(XLogReaderState *record);
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index a1cfed5f43c..ee949ca108c 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -29,7 +29,7 @@ typedef int XidStatus;
#define TRANSACTION_STATUS_ABORTED 0x02
#define TRANSACTION_STATUS_SUB_COMMITTED 0x03
-typedef struct xl_clog_truncate
+typedef struct PG_NO_PADDING xl_clog_truncate
{
int64 pageno;
TransactionId oldestXact;
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 49ee21cd5d2..92e50b0c806 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -46,14 +46,14 @@ extern int committssyncfiletag(const FileTag *ftag, char *path);
#define COMMIT_TS_ZEROPAGE 0x00
#define COMMIT_TS_TRUNCATE 0x10
-typedef struct xl_commit_ts_truncate
+typedef struct PG_NO_PADDING xl_commit_ts_truncate
{
int64 pageno;
TransactionId oldestXid;
+ pg_padding_4(pg_pad);
} xl_commit_ts_truncate;
-#define SizeOfCommitTsTruncate (offsetof(xl_commit_ts_truncate, oldestXid) + \
- sizeof(TransactionId))
+#define SizeOfCommitTsTruncate (sizeof(xl_commit_ts_truncate))
extern void commit_ts_redo(XLogReaderState *record);
extern void commit_ts_desc(StringInfo buf, XLogReaderState *record);
diff --git a/src/include/access/ginblock.h b/src/include/access/ginblock.h
index 2d75023179a..903c518df39 100644
--- a/src/include/access/ginblock.h
+++ b/src/include/access/ginblock.h
@@ -52,7 +52,7 @@ typedef GinPageOpaqueData *GinPageOpaque;
#define GIN_METAPAGE_BLKNO (0)
#define GIN_ROOT_BLKNO (1)
-typedef struct GinMetaPageData
+typedef struct PG_NO_PADDING GinMetaPageData
{
/*
* Pointers to head and tail of pending list, which consists of GIN_LIST
@@ -80,6 +80,7 @@ typedef struct GinMetaPageData
BlockNumber nTotalPages;
BlockNumber nEntryPages;
BlockNumber nDataPages;
+ pg_padding_4(pg_pad1);
int64 nEntries;
/*
@@ -98,6 +99,7 @@ typedef struct GinMetaPageData
* Reject full-index-scan attempts on such indexes.
*/
int32 ginVersion;
+ pg_padding_4(pg_pad2);
} GinMetaPageData;
#define GIN_CURRENT_VERSION 2
@@ -333,7 +335,7 @@ typedef signed char GinNullCategory;
*
* Note: This requires 2-byte alignment.
*/
-typedef struct
+typedef struct PG_NO_PADDING
{
ItemPointerData first; /* first item in this posting list (unpacked) */
uint16 nbytes; /* number of bytes that follow */
diff --git a/src/include/access/ginxlog.h b/src/include/access/ginxlog.h
index 74fdf9b3d7e..7df3b38737c 100644
--- a/src/include/access/ginxlog.h
+++ b/src/include/access/ginxlog.h
@@ -18,7 +18,7 @@
#define XLOG_GIN_CREATE_PTREE 0x10
-typedef struct ginxlogCreatePostingTree
+typedef struct PG_NO_PADDING ginxlogCreatePostingTree
{
uint32 size;
/* A compressed posting list follows */
@@ -34,7 +34,7 @@ typedef struct ginxlogCreatePostingTree
#define XLOG_GIN_INSERT 0x20
-typedef struct
+typedef struct PG_NO_PADDING
{
uint16 flags; /* GIN_INSERT_ISLEAF and/or GIN_INSERT_ISDATA */
@@ -108,7 +108,7 @@ typedef struct
*/
#define XLOG_GIN_SPLIT 0x30
-typedef struct ginxlogSplit
+typedef struct PG_NO_PADDING ginxlogSplit
{
RelFileLocator locator;
BlockNumber rrlink; /* right link, or root's blocknumber if root
@@ -116,6 +116,7 @@ typedef struct ginxlogSplit
BlockNumber leftChildBlkno; /* valid on a non-leaf split */
BlockNumber rightChildBlkno;
uint16 flags; /* see below */
+ pg_padding_2(pg_pad);
} ginxlogSplit;
/*
@@ -152,9 +153,10 @@ typedef struct ginxlogVacuumDataLeafPage
*/
#define XLOG_GIN_DELETE_PAGE 0x50
-typedef struct ginxlogDeletePage
+typedef struct PG_NO_PADDING ginxlogDeletePage
{
OffsetNumber parentOffset;
+ pg_padding_2(pg_pad);
BlockNumber rightLink;
TransactionId deleteXid; /* last Xid which could see this page in scan */
} ginxlogDeletePage;
@@ -165,15 +167,17 @@ typedef struct ginxlogDeletePage
* Backup Blk 0: metapage
* Backup Blk 1: tail page
*/
-typedef struct ginxlogUpdateMeta
+typedef struct PG_NO_PADDING ginxlogUpdateMeta
{
RelFileLocator locator;
+ pg_padding_4(pg_pad1);
GinMetaPageData metadata;
BlockNumber prevTail;
BlockNumber newRightlink;
int32 ntuples; /* if ntuples > 0 then metadata.tail was
* updated with that many tuples; else new sub
* list was inserted */
+ pg_padding_4(pg_pad2);
/* array of inserted tuples follows */
} ginxlogUpdateMeta;
@@ -182,7 +186,7 @@ typedef struct ginxlogUpdateMeta
/*
* Backup Blk 0: list page with inserted tuples
*/
-typedef struct ginxlogInsertListPage
+typedef struct PG_NO_PADDING ginxlogInsertListPage
{
BlockNumber rightlink;
int32 ntuples;
@@ -203,10 +207,11 @@ typedef struct ginxlogInsertListPage
* metapage.)
*/
#define GIN_NDELETE_AT_ONCE Min(16, XLR_MAX_BLOCK_ID - 1)
-typedef struct ginxlogDeleteListPages
+typedef struct PG_NO_PADDING ginxlogDeleteListPages
{
GinMetaPageData metadata;
int32 ndeleted;
+ pg_padding_4(pg_pad);
} ginxlogDeleteListPages;
extern void gin_redo(XLogReaderState *record);
diff --git a/src/include/access/gistxlog.h b/src/include/access/gistxlog.h
index d3d1c6549be..f19d4e8dfe6 100644
--- a/src/include/access/gistxlog.h
+++ b/src/include/access/gistxlog.h
@@ -33,7 +33,7 @@
* Backup Blk 1: If this operation completes a page split, by inserting a
* downlink for the split page, the left half of the split
*/
-typedef struct gistxlogPageUpdate
+typedef struct PG_NO_PADDING gistxlogPageUpdate
{
/* number of deleted offsets */
uint16 ntodelete;
@@ -47,12 +47,13 @@ typedef struct gistxlogPageUpdate
/*
* Backup Blk 0: Leaf page, whose index tuples are deleted.
*/
-typedef struct gistxlogDelete
+typedef struct PG_NO_PADDING gistxlogDelete
{
TransactionId snapshotConflictHorizon;
uint16 ntodelete; /* number of deleted offsets */
bool isCatalogRel; /* to handle recovery conflict during logical
* decoding on standby */
+ pg_padding_1(pg_pad);
/* TODELETE OFFSET NUMBERS */
OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
@@ -65,14 +66,18 @@ typedef struct gistxlogDelete
* downlink for the split page, the left half of the split
* Backup Blk 1 - npage: split pages (1 is the original page)
*/
-typedef struct gistxlogPageSplit
+typedef struct PG_NO_PADDING gistxlogPageSplit
{
BlockNumber origrlink; /* rightlink of the page before split */
+ pg_padding_4(pg_pad1);
GistNSN orignsn; /* NSN of the page before split */
bool origleaf; /* was split page a leaf page? */
+ pg_padding_1(pg_pad2);
uint16 npage; /* # of pages in the split */
bool markfollowright; /* set F_FOLLOW_RIGHT flags */
+ pg_padding_1(pg_pad3);
+ pg_padding_2(pg_pad4);
/*
* follow: 1. gistxlogPage and array of IndexTupleData per page
@@ -83,29 +88,34 @@ typedef struct gistxlogPageSplit
* Backup Blk 0: page that was deleted.
* Backup Blk 1: parent page, containing the downlink to the deleted page.
*/
-typedef struct gistxlogPageDelete
+typedef struct PG_NO_PADDING gistxlogPageDelete
{
FullTransactionId deleteXid; /* last Xid which could see page in scan */
OffsetNumber downlinkOffset; /* Offset of downlink referencing this
* page */
+ pg_padding_2(pg_pad1);
+ pg_padding_4(pg_pad2);
} gistxlogPageDelete;
-#define SizeOfGistxlogPageDelete (offsetof(gistxlogPageDelete, downlinkOffset) + sizeof(OffsetNumber))
+#define SizeOfGistxlogPageDelete (sizeof(gistxlogPageDelete))
/*
* This is what we need to know about page reuse, for hot standby.
*/
-typedef struct gistxlogPageReuse
+typedef struct PG_NO_PADDING gistxlogPageReuse
{
RelFileLocator locator;
BlockNumber block;
FullTransactionId snapshotConflictHorizon;
bool isCatalogRel; /* to handle recovery conflict during logical
* decoding on standby */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
+ pg_padding_4(pg_pad4);
} gistxlogPageReuse;
-#define SizeOfGistxlogPageReuse (offsetof(gistxlogPageReuse, isCatalogRel) + sizeof(bool))
+#define SizeOfGistxlogPageReuse (sizeof(gistxlogPageReuse))
extern void gist_redo(XLogReaderState *record);
extern void gist_desc(StringInfo buf, XLogReaderState *record);
diff --git a/src/include/access/hash_xlog.h b/src/include/access/hash_xlog.h
index 149aed69dc5..bb6b9d0fe11 100644
--- a/src/include/access/hash_xlog.h
+++ b/src/include/access/hash_xlog.h
@@ -59,12 +59,12 @@
* Backup Blk 0: original page (data contains the inserted tuple)
* Backup Blk 1: metapage (HashMetaPageData)
*/
-typedef struct xl_hash_insert
+typedef struct PG_NO_PADDING xl_hash_insert
{
OffsetNumber offnum;
} xl_hash_insert;
-#define SizeOfHashInsert (offsetof(xl_hash_insert, offnum) + sizeof(OffsetNumber))
+#define SizeOfHashInsert (sizeof(xl_hash_insert))
/*
* This is what we need to know about addition of overflow page.
@@ -77,14 +77,14 @@ typedef struct xl_hash_insert
* Backup Blk 3: new bitmap page
* Backup Blk 4: metapage
*/
-typedef struct xl_hash_add_ovfl_page
+typedef struct PG_NO_PADDING xl_hash_add_ovfl_page
{
uint16 bmsize;
bool bmpage_found;
+ pg_padding_1(pg_pad);
} xl_hash_add_ovfl_page;
-#define SizeOfHashAddOvflPage \
- (offsetof(xl_hash_add_ovfl_page, bmpage_found) + sizeof(bool))
+#define SizeOfHashAddOvflPage (sizeof(xl_hash_add_ovfl_page))
/*
* This is what we need to know about allocating a page for split.
@@ -95,16 +95,17 @@ typedef struct xl_hash_add_ovfl_page
* Backup Blk 1: page for new bucket
* Backup Blk 2: metapage
*/
-typedef struct xl_hash_split_allocate_page
+typedef struct PG_NO_PADDING xl_hash_split_allocate_page
{
uint32 new_bucket;
uint16 old_bucket_flag;
uint16 new_bucket_flag;
uint8 flags;
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
} xl_hash_split_allocate_page;
-#define SizeOfHashSplitAllocPage \
- (offsetof(xl_hash_split_allocate_page, flags) + sizeof(uint8))
+#define SizeOfHashSplitAllocPage (sizeof(xl_hash_split_allocate_page))
/*
* This is what we need to know about completing the split operation.
@@ -114,14 +115,13 @@ typedef struct xl_hash_split_allocate_page
* Backup Blk 0: page for old bucket
* Backup Blk 1: page for new bucket
*/
-typedef struct xl_hash_split_complete
+typedef struct PG_NO_PADDING xl_hash_split_complete
{
uint16 old_bucket_flag;
uint16 new_bucket_flag;
} xl_hash_split_complete;
-#define SizeOfHashSplitComplete \
- (offsetof(xl_hash_split_complete, new_bucket_flag) + sizeof(uint16))
+#define SizeOfHashSplitComplete (sizeof(xl_hash_split_complete))
/*
* This is what we need to know about move page contents required during
@@ -133,16 +133,16 @@ typedef struct xl_hash_split_complete
* Backup Blk 1: page containing moved tuples
* Backup Blk 2: page from which tuples will be removed
*/
-typedef struct xl_hash_move_page_contents
+typedef struct PG_NO_PADDING xl_hash_move_page_contents
{
uint16 ntups;
bool is_prim_bucket_same_wrt; /* true if the page to which
* tuples are moved is same as
* primary bucket page */
+ pg_padding_1(pg_pad);
} xl_hash_move_page_contents;
-#define SizeOfHashMovePageContents \
- (offsetof(xl_hash_move_page_contents, is_prim_bucket_same_wrt) + sizeof(bool))
+#define SizeOfHashMovePageContents (sizeof(xl_hash_move_page_contents))
/*
* This is what we need to know about the squeeze page operation.
@@ -157,7 +157,7 @@ typedef struct xl_hash_move_page_contents
* Backup Blk 5: bitmap page containing info of freed overflow page
* Backup Blk 6: meta page
*/
-typedef struct xl_hash_squeeze_page
+typedef struct PG_NO_PADDING xl_hash_squeeze_page
{
BlockNumber prevblkno;
BlockNumber nextblkno;
@@ -171,8 +171,7 @@ typedef struct xl_hash_squeeze_page
* page */
} xl_hash_squeeze_page;
-#define SizeOfHashSqueezePage \
- (offsetof(xl_hash_squeeze_page, is_prev_bucket_same_wrt) + sizeof(bool))
+#define SizeOfHashSqueezePage (sizeof(xl_hash_squeeze_page))
/*
* This is what we need to know about the deletion of index tuples from a page.
@@ -182,7 +181,7 @@ typedef struct xl_hash_squeeze_page
* Backup Blk 0: primary bucket page
* Backup Blk 1: page from which tuples are deleted
*/
-typedef struct xl_hash_delete
+typedef struct PG_NO_PADDING xl_hash_delete
{
bool clear_dead_marking; /* true if this operation clears
* LH_PAGE_HAS_DEAD_TUPLES flag */
@@ -190,7 +189,7 @@ typedef struct xl_hash_delete
* primary bucket page */
} xl_hash_delete;
-#define SizeOfHashDelete (offsetof(xl_hash_delete, is_primary_bucket_page) + sizeof(bool))
+#define SizeOfHashDelete (sizeof(xl_hash_delete))
/*
* This is what we need for metapage update operation.
@@ -199,13 +198,12 @@ typedef struct xl_hash_delete
*
* Backup Blk 0: meta page
*/
-typedef struct xl_hash_update_meta_page
+typedef struct PG_NO_PADDING xl_hash_update_meta_page
{
double ntuples;
} xl_hash_update_meta_page;
-#define SizeOfHashUpdateMetaPage \
- (offsetof(xl_hash_update_meta_page, ntuples) + sizeof(double))
+#define SizeOfHashUpdateMetaPage (sizeof(xl_hash_update_meta_page))
/*
* This is what we need to initialize metapage.
@@ -214,15 +212,15 @@ typedef struct xl_hash_update_meta_page
*
* Backup Blk 0: meta page
*/
-typedef struct xl_hash_init_meta_page
+typedef struct PG_NO_PADDING xl_hash_init_meta_page
{
double num_tuples;
RegProcedure procid;
uint16 ffactor;
+ pg_padding_2(pg_pad);
} xl_hash_init_meta_page;
-#define SizeOfHashInitMetaPage \
- (offsetof(xl_hash_init_meta_page, ffactor) + sizeof(uint16))
+#define SizeOfHashInitMetaPage (sizeof(xl_hash_init_meta_page))
/*
* This is what we need to initialize bitmap page.
@@ -232,13 +230,12 @@ typedef struct xl_hash_init_meta_page
* Backup Blk 0: bitmap page
* Backup Blk 1: meta page
*/
-typedef struct xl_hash_init_bitmap_page
+typedef struct PG_NO_PADDING xl_hash_init_bitmap_page
{
uint16 bmsize;
} xl_hash_init_bitmap_page;
-#define SizeOfHashInitBitmapPage \
- (offsetof(xl_hash_init_bitmap_page, bmsize) + sizeof(uint16))
+#define SizeOfHashInitBitmapPage (sizeof(xl_hash_init_bitmap_page))
/*
* This is what we need for index tuple deletion and to
@@ -249,12 +246,13 @@ typedef struct xl_hash_init_bitmap_page
* Backup Blk 0: primary bucket page
* Backup Blk 1: meta page
*/
-typedef struct xl_hash_vacuum_one_page
+typedef struct PG_NO_PADDING xl_hash_vacuum_one_page
{
TransactionId snapshotConflictHorizon;
uint16 ntuples;
bool isCatalogRel; /* to handle recovery conflict during logical
* decoding on standby */
+ pg_padding_1(pg_pad);
/* TARGET OFFSET NUMBERS */
OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index ce3566ba949..74a3803ad14 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -110,7 +110,7 @@
(XLH_DELETE_CONTAINS_OLD_TUPLE | XLH_DELETE_CONTAINS_OLD_KEY)
/* This is what we need to know about delete */
-typedef struct xl_heap_delete
+typedef struct PG_NO_PADDING xl_heap_delete
{
TransactionId xmax; /* xmax of the deleted tuple */
OffsetNumber offnum; /* deleted tuple's offset */
@@ -118,7 +118,7 @@ typedef struct xl_heap_delete
uint8 flags;
} xl_heap_delete;
-#define SizeOfHeapDelete (offsetof(xl_heap_delete, flags) + sizeof(uint8))
+#define SizeOfHeapDelete sizeof(xl_heap_delete)
/*
* xl_heap_truncate flag values, 8 bits are available.
@@ -131,11 +131,13 @@ typedef struct xl_heap_delete
* sequence relids that need to be restarted, if any.
* All rels are always within the same database, so we just list dbid once.
*/
-typedef struct xl_heap_truncate
+typedef struct PG_NO_PADDING xl_heap_truncate
{
Oid dbId;
uint32 nrelids;
uint8 flags;
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
Oid relids[FLEXIBLE_ARRAY_MEMBER];
} xl_heap_truncate;
@@ -147,25 +149,27 @@ typedef struct xl_heap_truncate
* fields that are available elsewhere in the WAL record, or perhaps just
* plain needn't be reconstructed. These are the fields we must store.
*/
-typedef struct xl_heap_header
+typedef struct PG_NO_PADDING xl_heap_header
{
uint16 t_infomask2;
uint16 t_infomask;
uint8 t_hoff;
+ pg_padding_1(pg_pad);
} xl_heap_header;
-#define SizeOfHeapHeader (offsetof(xl_heap_header, t_hoff) + sizeof(uint8))
+#define SizeOfHeapHeader sizeof(xl_heap_header)
/* This is what we need to know about insert */
-typedef struct xl_heap_insert
+typedef struct PG_NO_PADDING xl_heap_insert
{
OffsetNumber offnum; /* inserted tuple's offset */
uint8 flags;
+ pg_padding_1(pg_pad);
/* xl_heap_header & TUPLE DATA in backup block 0 */
} xl_heap_insert;
-#define SizeOfHeapInsert (offsetof(xl_heap_insert, flags) + sizeof(uint8))
+#define SizeOfHeapInsert sizeof(xl_heap_insert)
/*
* This is what we need to know about a multi-insert.
@@ -178,25 +182,27 @@ typedef struct xl_heap_insert
* followed by the tuple data for each tuple. There is padding to align
* each xl_multi_insert_tuple struct.
*/
-typedef struct xl_heap_multi_insert
+typedef struct PG_NO_PADDING xl_heap_multi_insert
{
uint8 flags;
+ pg_padding_1(pg_pad);
uint16 ntuples;
OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} xl_heap_multi_insert;
#define SizeOfHeapMultiInsert offsetof(xl_heap_multi_insert, offsets)
-typedef struct xl_multi_insert_tuple
+typedef struct PG_NO_PADDING xl_multi_insert_tuple
{
uint16 datalen; /* size of tuple data that follows */
uint16 t_infomask2;
uint16 t_infomask;
uint8 t_hoff;
+ pg_padding_1(pg_pad);
/* TUPLE DATA FOLLOWS AT END OF STRUCT */
} xl_multi_insert_tuple;
-#define SizeOfMultiInsertTuple (offsetof(xl_multi_insert_tuple, t_hoff) + sizeof(uint8))
+#define SizeOfMultiInsertTuple sizeof(xl_multi_insert_tuple)
/*
* This is what we need to know about update|hot_update
@@ -215,7 +221,7 @@ typedef struct xl_multi_insert_tuple
*
* Backup blk 1: old page, if different. (no data, just a reference to the blk)
*/
-typedef struct xl_heap_update
+typedef struct PG_NO_PADDING xl_heap_update
{
TransactionId old_xmax; /* xmax of the old tuple */
OffsetNumber old_offnum; /* old tuple's offset */
@@ -223,6 +229,7 @@ typedef struct xl_heap_update
uint8 flags;
TransactionId new_xmax; /* xmax of the new tuple */
OffsetNumber new_offnum; /* new tuple's offset */
+ pg_padding_2(pg_pad);
/*
* If XLH_UPDATE_CONTAINS_OLD_TUPLE or XLH_UPDATE_CONTAINS_OLD_KEY flags
@@ -230,7 +237,7 @@ typedef struct xl_heap_update
*/
} xl_heap_update;
-#define SizeOfHeapUpdate (offsetof(xl_heap_update, new_offnum) + sizeof(OffsetNumber))
+#define SizeOfHeapUpdate sizeof(xl_heap_update)
/*
* These structures and flags encode VACUUM pruning and freezing and on-access
@@ -282,7 +289,7 @@ typedef struct xl_heap_update
* other fields require only 2-byte alignment. This is also the reason that
* 'frz_offsets' is stored separately from the xlhp_freeze_plan structs.
*/
-typedef struct xl_heap_prune
+typedef struct PG_NO_PADDING xl_heap_prune
{
uint16 flags;
@@ -292,7 +299,7 @@ typedef struct xl_heap_prune
*/
} xl_heap_prune;
-#define SizeOfHeapPrune (offsetof(xl_heap_prune, flags) + sizeof(uint16))
+#define SizeOfHeapPrune sizeof(xl_heap_prune)
/* to handle recovery conflict during logical decoding on standby */
#define XLHP_IS_CATALOG_REL (1 << 1)
@@ -347,12 +354,13 @@ typedef struct xl_heap_prune
#define XLH_FREEZE_XVAC 0x02
#define XLH_INVALID_XVAC 0x04
-typedef struct xlhp_freeze_plan
+typedef struct PG_NO_PADDING xlhp_freeze_plan
{
TransactionId xmax;
uint16 t_infomask2;
uint16 t_infomask;
uint8 frzflags;
+ pg_padding_1(pg_pad);
/* Length of individual page offset numbers array for this plan */
uint16 ntuples;
@@ -370,9 +378,10 @@ typedef struct xlhp_freeze_plan
* (As of PostgreSQL 17, XLOG_HEAP2_PRUNE_VACUUM_SCAN records replace the
* separate XLOG_HEAP2_FREEZE_PAGE records.)
*/
-typedef struct xlhp_freeze_plans
+typedef struct PG_NO_PADDING xlhp_freeze_plans
{
uint16 nplans;
+ pg_padding_2(pg_pad);
xlhp_freeze_plan plans[FLEXIBLE_ARRAY_MEMBER];
} xlhp_freeze_plans;
@@ -383,7 +392,7 @@ typedef struct xlhp_freeze_plans
* set. Note that in the XLHP_HAS_REDIRECTIONS variant, there are actually 2
* * length number of OffsetNumbers in the data.
*/
-typedef struct xlhp_prune_items
+typedef struct PG_NO_PADDING xlhp_prune_items
{
uint16 ntargets;
OffsetNumber data[FLEXIBLE_ARRAY_MEMBER];
@@ -401,7 +410,7 @@ typedef struct xlhp_prune_items
#define XLH_LOCK_ALL_FROZEN_CLEARED 0x01
/* This is what we need to know about lock */
-typedef struct xl_heap_lock
+typedef struct PG_NO_PADDING xl_heap_lock
{
TransactionId xmax; /* might be a MultiXactId */
OffsetNumber offnum; /* locked tuple's offset on page */
@@ -409,10 +418,10 @@ typedef struct xl_heap_lock
uint8 flags; /* XLH_LOCK_* flag bits */
} xl_heap_lock;
-#define SizeOfHeapLock (offsetof(xl_heap_lock, flags) + sizeof(uint8))
+#define SizeOfHeapLock sizeof(xl_heap_lock)
/* This is what we need to know about locking an updated version of a row */
-typedef struct xl_heap_lock_updated
+typedef struct PG_NO_PADDING xl_heap_lock_updated
{
TransactionId xmax;
OffsetNumber offnum;
@@ -420,23 +429,26 @@ typedef struct xl_heap_lock_updated
uint8 flags;
} xl_heap_lock_updated;
-#define SizeOfHeapLockUpdated (offsetof(xl_heap_lock_updated, flags) + sizeof(uint8))
+#define SizeOfHeapLockUpdated sizeof(xl_heap_lock_updated)
/* This is what we need to know about confirmation of speculative insertion */
-typedef struct xl_heap_confirm
+typedef struct PG_NO_PADDING xl_heap_confirm
{
OffsetNumber offnum; /* confirmed tuple's offset on page */
} xl_heap_confirm;
-#define SizeOfHeapConfirm (offsetof(xl_heap_confirm, offnum) + sizeof(OffsetNumber))
+#define SizeOfHeapConfirm sizeof(xl_heap_confirm)
/* This is what we need to know about in-place update */
-typedef struct xl_heap_inplace
+typedef struct PG_NO_PADDING xl_heap_inplace
{
OffsetNumber offnum; /* updated tuple's offset on page */
+ pg_padding_2(pg_pad1);
Oid dbId; /* MyDatabaseId */
Oid tsId; /* MyDatabaseTableSpace */
bool relcacheInitFileInval; /* invalidate relcache init files */
+ pg_padding_1(pg_pad2);
+ pg_padding_2(pg_pad3);
int nmsgs; /* number of shared inval msgs */
SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER];
} xl_heap_inplace;
@@ -449,15 +461,17 @@ typedef struct xl_heap_inplace
* Backup blk 0: visibility map buffer
* Backup blk 1: heap buffer
*/
-typedef struct xl_heap_visible
+typedef struct PG_NO_PADDING xl_heap_visible
{
TransactionId snapshotConflictHorizon;
uint8 flags;
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
} xl_heap_visible;
-#define SizeOfHeapVisible (offsetof(xl_heap_visible, flags) + sizeof(uint8))
+#define SizeOfHeapVisible sizeof(xl_heap_visible)
-typedef struct xl_heap_new_cid
+typedef struct PG_NO_PADDING xl_heap_new_cid
{
/*
* store toplevel xid so we don't have to merge cids from different
@@ -473,18 +487,21 @@ typedef struct xl_heap_new_cid
*/
RelFileLocator target_locator;
ItemPointerData target_tid;
+ pg_padding_2(pg_pad);
} xl_heap_new_cid;
-#define SizeOfHeapNewCid (offsetof(xl_heap_new_cid, target_tid) + sizeof(ItemPointerData))
+#define SizeOfHeapNewCid sizeof(xl_heap_new_cid)
/* logical rewrite xlog record header */
-typedef struct xl_heap_rewrite_mapping
+typedef struct PG_NO_PADDING xl_heap_rewrite_mapping
{
TransactionId mapped_xid; /* xid that might need to see the row */
Oid mapped_db; /* DbOid or InvalidOid for shared rels */
Oid mapped_rel; /* Oid of the mapped relation */
+ pg_padding_4(pg_pad1);
off_t offset; /* How far have we written so far */
uint32 num_mappings; /* Number of in-memory mappings */
+ pg_padding_4(pg_pad2);
XLogRecPtr start_lsn; /* Insert LSN at begin of rewrite */
} xl_heap_rewrite_mapping;
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 2ae8b571dcc..3fe4501d27f 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -69,17 +69,19 @@ typedef struct MultiXactMember
#define XLOG_MULTIXACT_CREATE_ID 0x20
#define XLOG_MULTIXACT_TRUNCATE_ID 0x30
-typedef struct xl_multixact_create
+typedef struct PG_NO_PADDING xl_multixact_create
{
MultiXactId mid; /* new MultiXact's ID */
+ pg_padding_4(pg_pad1);
MultiXactOffset moff; /* its starting offset in members file */
int32 nmembers; /* number of member XIDs */
+ pg_padding_4(pg_pad2);
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER];
} xl_multixact_create;
#define SizeOfMultiXactCreate (offsetof(xl_multixact_create, members))
-typedef struct xl_multixact_truncate
+typedef struct PG_NO_PADDING xl_multixact_truncate
{
Oid oldestMultiDB;
diff --git a/src/include/access/nbtxlog.h b/src/include/access/nbtxlog.h
index 3a78ec27fe8..8918d675dce 100644
--- a/src/include/access/nbtxlog.h
+++ b/src/include/access/nbtxlog.h
@@ -46,7 +46,7 @@
/*
* All that we need to regenerate the meta-data page
*/
-typedef struct xl_btree_metadata
+typedef struct PG_NO_PADDING xl_btree_metadata
{
uint32 version;
BlockNumber root;
@@ -55,6 +55,8 @@ typedef struct xl_btree_metadata
uint32 fastlevel;
uint32 last_cleanup_num_delpages;
bool allequalimage;
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
} xl_btree_metadata;
/*
@@ -76,7 +78,7 @@ typedef struct xl_btree_metadata
* that was split as an extra step. Also, recovery generates a "final"
* newitem. See _bt_swap_posting() for details on posting list splits.
*/
-typedef struct xl_btree_insert
+typedef struct PG_NO_PADDING xl_btree_insert
{
OffsetNumber offnum;
@@ -84,7 +86,7 @@ typedef struct xl_btree_insert
/* NEW TUPLE ALWAYS FOLLOWS AT THE END */
} xl_btree_insert;
-#define SizeOfBtreeInsert (offsetof(xl_btree_insert, offnum) + sizeof(OffsetNumber))
+#define SizeOfBtreeInsert sizeof(xl_btree_insert)
/*
* On insert with split, we save all the items going into the right sibling
@@ -150,15 +152,16 @@ typedef struct xl_btree_insert
* Backup Blk 2: next block (orig page's rightlink), if any
* Backup Blk 3: child's left sibling, if non-leaf split
*/
-typedef struct xl_btree_split
+typedef struct PG_NO_PADDING xl_btree_split
{
uint32 level; /* tree level of page being split */
OffsetNumber firstrightoff; /* first origpage item on rightpage */
OffsetNumber newitemoff; /* new item's offset */
uint16 postingoff; /* offset inside orig posting tuple */
+ pg_padding_2(pg_pad);
} xl_btree_split;
-#define SizeOfBtreeSplit (offsetof(xl_btree_split, postingoff) + sizeof(uint16))
+#define SizeOfBtreeSplit sizeof(xl_btree_split)
/*
* When page is deduplicated, consecutive groups of tuples with equal keys are
@@ -167,14 +170,14 @@ typedef struct xl_btree_split
* The WAL record represents a deduplication pass for a leaf page. An array
* of BTDedupInterval structs follows.
*/
-typedef struct xl_btree_dedup
+typedef struct PG_NO_PADDING xl_btree_dedup
{
uint16 nintervals;
/* DEDUPLICATION INTERVALS FOLLOW */
} xl_btree_dedup;
-#define SizeOfBtreeDedup (offsetof(xl_btree_dedup, nintervals) + sizeof(uint16))
+#define SizeOfBtreeDedup sizeof(xl_btree_dedup)
/*
* This is what we need to know about page reuse within btree. This record
@@ -183,16 +186,19 @@ typedef struct xl_btree_dedup
* Note that we must include a RelFileLocator in the record because we don't
* actually register the buffer with the record.
*/
-typedef struct xl_btree_reuse_page
+typedef struct PG_NO_PADDING xl_btree_reuse_page
{
RelFileLocator locator;
BlockNumber block;
FullTransactionId snapshotConflictHorizon;
bool isCatalogRel; /* to handle recovery conflict during logical
* decoding on standby */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
+ pg_padding_4(pg_pad4);
} xl_btree_reuse_page;
-#define SizeOfBtreeReusePage (offsetof(xl_btree_reuse_page, isCatalogRel) + sizeof(bool))
+#define SizeOfBtreeReusePage sizeof(xl_btree_reuse_page)
/*
* xl_btree_vacuum and xl_btree_delete records describe deletion of index
@@ -220,7 +226,7 @@ typedef struct xl_btree_reuse_page
* Updates are only used when there will be some remaining TIDs left by the
* REDO routine. Otherwise the posting list tuple just gets deleted outright.
*/
-typedef struct xl_btree_vacuum
+typedef struct PG_NO_PADDING xl_btree_vacuum
{
uint16 ndeleted;
uint16 nupdated;
@@ -234,15 +240,17 @@ typedef struct xl_btree_vacuum
*/
} xl_btree_vacuum;
-#define SizeOfBtreeVacuum (offsetof(xl_btree_vacuum, nupdated) + sizeof(uint16))
+#define SizeOfBtreeVacuum sizeof(xl_btree_vacuum)
-typedef struct xl_btree_delete
+typedef struct PG_NO_PADDING xl_btree_delete
{
TransactionId snapshotConflictHorizon;
uint16 ndeleted;
uint16 nupdated;
bool isCatalogRel; /* to handle recovery conflict during logical
* decoding on standby */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
/*----
* In payload of blk 0 :
@@ -253,7 +261,7 @@ typedef struct xl_btree_delete
*/
} xl_btree_delete;
-#define SizeOfBtreeDelete (offsetof(xl_btree_delete, isCatalogRel) + sizeof(bool))
+#define SizeOfBtreeDelete sizeof(xl_btree_delete)
/*
* The offsets that appear in xl_btree_update metadata are offsets into the
@@ -261,14 +269,14 @@ typedef struct xl_btree_delete
* 0-based. The page offset number for the original posting list tuple comes
* from the main xl_btree_vacuum/xl_btree_delete record.
*/
-typedef struct xl_btree_update
+typedef struct PG_NO_PADDING xl_btree_update
{
uint16 ndeletedtids;
/* POSTING LIST uint16 OFFSETS TO A DELETED TID FOLLOW */
} xl_btree_update;
-#define SizeOfBtreeUpdate (offsetof(xl_btree_update, ndeletedtids) + sizeof(uint16))
+#define SizeOfBtreeUpdate sizeof(xl_btree_update)
/*
* This is what we need to know about marking an empty subtree for deletion.
@@ -280,9 +288,10 @@ typedef struct xl_btree_update
* Backup Blk 0: leaf block
* Backup Blk 1: top parent
*/
-typedef struct xl_btree_mark_page_halfdead
+typedef struct PG_NO_PADDING xl_btree_mark_page_halfdead
{
OffsetNumber poffset; /* deleted tuple id in parent page */
+ pg_padding_2(pg_pad);
/* information needed to recreate the leaf page: */
BlockNumber leafblk; /* leaf block ultimately being deleted */
@@ -291,7 +300,7 @@ typedef struct xl_btree_mark_page_halfdead
BlockNumber topparent; /* topmost internal page in the subtree */
} xl_btree_mark_page_halfdead;
-#define SizeOfBtreeMarkPageHalfDead (offsetof(xl_btree_mark_page_halfdead, topparent) + sizeof(BlockNumber))
+#define SizeOfBtreeMarkPageHalfDead sizeof(xl_btree_mark_page_halfdead)
/*
* This is what we need to know about deletion of a btree page. Note that we
@@ -307,11 +316,12 @@ typedef struct xl_btree_mark_page_halfdead
* Backup Blk 3: leaf block (if different from target)
* Backup Blk 4: metapage (if rightsib becomes new fast root)
*/
-typedef struct xl_btree_unlink_page
+typedef struct PG_NO_PADDING xl_btree_unlink_page
{
BlockNumber leftsib; /* target block's left sibling, if any */
BlockNumber rightsib; /* target block's right sibling */
uint32 level; /* target block's level */
+ pg_padding_4(pg_pad1);
FullTransactionId safexid; /* target block's BTPageSetDeleted() XID */
/*
@@ -324,11 +334,12 @@ typedef struct xl_btree_unlink_page
BlockNumber leafleftsib;
BlockNumber leafrightsib;
BlockNumber leaftopparent; /* next child down in the subtree */
+ pg_padding_4(pg_pad2);
/* xl_btree_metadata FOLLOWS IF XLOG_BTREE_UNLINK_PAGE_META */
} xl_btree_unlink_page;
-#define SizeOfBtreeUnlinkPage (offsetof(xl_btree_unlink_page, leaftopparent) + sizeof(BlockNumber))
+#define SizeOfBtreeUnlinkPage sizeof(xl_btree_unlink_page)
/*
* New root log record. There are zero tuples if this is to establish an
@@ -341,13 +352,13 @@ typedef struct xl_btree_unlink_page
* Backup Blk 1: left child (if splitting an old root)
* Backup Blk 2: metapage
*/
-typedef struct xl_btree_newroot
+typedef struct PG_NO_PADDING xl_btree_newroot
{
BlockNumber rootblk; /* location of new root (redundant with blk 0) */
uint32 level; /* its tree level */
} xl_btree_newroot;
-#define SizeOfBtreeNewroot (offsetof(xl_btree_newroot, level) + sizeof(uint32))
+#define SizeOfBtreeNewroot sizeof(xl_btree_newroot)
/*
diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h
index ec6d6f5f74d..c05693846d8 100644
--- a/src/include/access/spgist_private.h
+++ b/src/include/access/spgist_private.h
@@ -292,14 +292,14 @@ typedef struct SpGistCache
* opclasses. Going forward, we will be using a fixed size of Datum so that
* there's no longer any pressing reason to change this.
*/
-typedef struct SpGistInnerTupleData
+typedef struct PG_NO_PADDING SpGistInnerTupleData
{
unsigned int tupstate:2, /* LIVE/REDIRECT/DEAD/PLACEHOLDER */
allTheSame:1, /* all nodes in tuple are equivalent */
nNodes:13, /* number of nodes within inner tuple */
prefixSize:16; /* size of prefix, or 0 if none */
uint16 size; /* total size of inner tuple */
- /* On most machines there will be a couple of wasted bytes here */
+ pg_padding_2(pg_pad);
/* prefix datum follows, then nodes */
} SpGistInnerTupleData;
@@ -382,7 +382,7 @@ typedef SpGistNodeTupleData *SpGistNodeTuple;
* restriction only adds bytes for a NULL leaf datum; otherwise alignment
* restrictions force it anyway.)
*/
-typedef struct SpGistLeafTupleData
+typedef struct PG_NO_PADDING SpGistLeafTupleData
{
unsigned int tupstate:2, /* LIVE/REDIRECT/DEAD/PLACEHOLDER */
size:30; /* large enough for any palloc'able value */
diff --git a/src/include/access/spgxlog.h b/src/include/access/spgxlog.h
index c257408be66..fc1431407fd 100644
--- a/src/include/access/spgxlog.h
+++ b/src/include/access/spgxlog.h
@@ -33,17 +33,19 @@
* need to be valid. spgxlogState carries the required info in xlog records.
* (See fillFakeState in spgxlog.c for more comments.)
*/
-typedef struct spgxlogState
+typedef struct PG_NO_PADDING spgxlogState
{
TransactionId redirectXid;
bool isBuild;
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
} spgxlogState;
/*
* Backup Blk 0: destination page for leaf tuple
* Backup Blk 1: parent page (if any)
*/
-typedef struct spgxlogAddLeaf
+typedef struct PG_NO_PADDING spgxlogAddLeaf
{
bool newPage; /* init dest page? */
bool storesNulls; /* page is in the nulls tree? */
@@ -61,17 +63,19 @@ typedef struct spgxlogAddLeaf
* Backup Blk 1: destination leaf page
* Backup Blk 2: parent page
*/
-typedef struct spgxlogMoveLeafs
+typedef struct PG_NO_PADDING spgxlogMoveLeafs
{
uint16 nMoves; /* number of tuples moved from source page */
bool newPage; /* init dest page? */
bool replaceDead; /* are we replacing a DEAD source tuple? */
bool storesNulls; /* pages are in the nulls tree? */
+ pg_padding_1(pg_pad1);
/* where the parent downlink is */
OffsetNumber offnumParent;
uint16 nodeI;
+ pg_padding_2(pg_pad2);
spgxlogState stateSrc;
/*----------
@@ -96,7 +100,7 @@ typedef struct spgxlogMoveLeafs
* Backup Blk 2: where parent downlink is, if updated and different from
* the old and new
*/
-typedef struct spgxlogAddNode
+typedef struct PG_NO_PADDING spgxlogAddNode
{
/*
* Offset of the original inner tuple, in the original page (on backup
@@ -127,6 +131,7 @@ typedef struct spgxlogAddNode
uint16 nodeI;
+ pg_padding_2(pg_pad);
spgxlogState stateSrc;
/*
@@ -138,7 +143,7 @@ typedef struct spgxlogAddNode
* Backup Blk 0: where the prefix tuple goes
* Backup Blk 1: where the postfix tuple goes (if different page)
*/
-typedef struct spgxlogSplitTuple
+typedef struct PG_NO_PADDING spgxlogSplitTuple
{
/* where the prefix tuple goes */
OffsetNumber offnumPrefix;
@@ -162,9 +167,10 @@ typedef struct spgxlogSplitTuple
* Backup Blk 2: Inner page
* Backup Blk 3: Parent page (if any, and different from Inner)
*/
-typedef struct spgxlogPickSplit
+typedef struct PG_NO_PADDING spgxlogPickSplit
{
bool isRootSplit;
+ pg_padding_1(pg_pad1);
uint16 nDelete; /* n to delete from Src */
uint16 nInsert; /* n to insert on Src and/or Dest */
@@ -179,9 +185,11 @@ typedef struct spgxlogPickSplit
/* where the parent downlink is, if any */
bool innerIsParent; /* is parent the same as inner page? */
+ pg_padding_1(pg_pad2);
OffsetNumber offnumParent;
uint16 nodeI;
+ pg_padding_2(pg_pad3);
spgxlogState stateSrc;
/*----------
@@ -198,7 +206,7 @@ typedef struct spgxlogPickSplit
#define SizeOfSpgxlogPickSplit offsetof(spgxlogPickSplit, offsets)
-typedef struct spgxlogVacuumLeaf
+typedef struct PG_NO_PADDING spgxlogVacuumLeaf
{
uint16 nDead; /* number of tuples to become DEAD */
uint16 nPlaceholder; /* number of tuples to become PLACEHOLDER */
@@ -222,10 +230,11 @@ typedef struct spgxlogVacuumLeaf
#define SizeOfSpgxlogVacuumLeaf offsetof(spgxlogVacuumLeaf, offsets)
-typedef struct spgxlogVacuumRoot
+typedef struct PG_NO_PADDING spgxlogVacuumRoot
{
/* vacuum a root page when it is also a leaf */
uint16 nDelete; /* number of tuples to delete */
+ pg_padding_2(pg_pad);
spgxlogState stateSrc;
@@ -235,13 +244,15 @@ typedef struct spgxlogVacuumRoot
#define SizeOfSpgxlogVacuumRoot offsetof(spgxlogVacuumRoot, offsets)
-typedef struct spgxlogVacuumRedirect
+typedef struct PG_NO_PADDING spgxlogVacuumRedirect
{
uint16 nToPlaceholder; /* number of redirects to make placeholders */
OffsetNumber firstPlaceholder; /* first placeholder tuple to remove */
TransactionId snapshotConflictHorizon; /* newest XID of removed redirects */
bool isCatalogRel; /* to handle recovery conflict during logical
* decoding on standby */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
/* offsets of redirect tuples to make placeholders follow */
OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index f0b4d795071..d9617b235bd 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -216,7 +216,7 @@ typedef struct SavedTransactionCharacteristics
#define XactCompletionForceSyncCommit(xinfo) \
((xinfo & XACT_COMPLETION_FORCE_SYNC_COMMIT) != 0)
-typedef struct xl_xact_assignment
+typedef struct PG_NO_PADDING xl_xact_assignment
{
TransactionId xtop; /* assigned XID's top-level XID */
int nsubxacts; /* number of subtransaction XIDs */
@@ -242,7 +242,7 @@ typedef struct xl_xact_assignment
/* sub-records for commit/abort */
-typedef struct xl_xact_xinfo
+typedef struct PG_NO_PADDING xl_xact_xinfo
{
/*
* Even though we right now only require two bytes of space in xinfo we
@@ -253,20 +253,20 @@ typedef struct xl_xact_xinfo
uint32 xinfo;
} xl_xact_xinfo;
-typedef struct xl_xact_dbinfo
+typedef struct PG_NO_PADDING xl_xact_dbinfo
{
Oid dbId; /* MyDatabaseId */
Oid tsId; /* MyDatabaseTableSpace */
} xl_xact_dbinfo;
-typedef struct xl_xact_subxacts
+typedef struct PG_NO_PADDING xl_xact_subxacts
{
int nsubxacts; /* number of subtransaction XIDs */
TransactionId subxacts[FLEXIBLE_ARRAY_MEMBER];
} xl_xact_subxacts;
#define MinSizeOfXactSubxacts offsetof(xl_xact_subxacts, subxacts)
-typedef struct xl_xact_relfilelocators
+typedef struct PG_NO_PADDING xl_xact_relfilelocators
{
int nrels; /* number of relations */
RelFileLocator xlocators[FLEXIBLE_ARRAY_MEMBER];
@@ -280,7 +280,7 @@ typedef struct xl_xact_relfilelocators
* frontend code, but the WAL format needs to be readable by frontend
* programs.
*/
-typedef struct xl_xact_stats_item
+typedef struct PG_NO_PADDING xl_xact_stats_item
{
int kind;
Oid dboid;
@@ -293,32 +293,32 @@ typedef struct xl_xact_stats_item
uint32 objid_hi;
} xl_xact_stats_item;
-typedef struct xl_xact_stats_items
+typedef struct PG_NO_PADDING xl_xact_stats_items
{
int nitems;
xl_xact_stats_item items[FLEXIBLE_ARRAY_MEMBER];
} xl_xact_stats_items;
#define MinSizeOfXactStatsItems offsetof(xl_xact_stats_items, items)
-typedef struct xl_xact_invals
+typedef struct PG_NO_PADDING xl_xact_invals
{
int nmsgs; /* number of shared inval msgs */
SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER];
} xl_xact_invals;
#define MinSizeOfXactInvals offsetof(xl_xact_invals, msgs)
-typedef struct xl_xact_twophase
+typedef struct PG_NO_PADDING xl_xact_twophase
{
TransactionId xid;
} xl_xact_twophase;
-typedef struct xl_xact_origin
+typedef struct PG_NO_PADDING xl_xact_origin
{
XLogRecPtr origin_lsn;
TimestampTz origin_timestamp;
} xl_xact_origin;
-typedef struct xl_xact_commit
+typedef struct PG_NO_PADDING xl_xact_commit
{
TimestampTz xact_time; /* time of commit */
@@ -334,7 +334,7 @@ typedef struct xl_xact_commit
} xl_xact_commit;
#define MinSizeOfXactCommit (offsetof(xl_xact_commit, xact_time) + sizeof(TimestampTz))
-typedef struct xl_xact_abort
+typedef struct PG_NO_PADDING xl_xact_abort
{
TimestampTz xact_time; /* time of abort */
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index fbc5d77ab39..a8c07b20fe5 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -33,7 +33,7 @@
*/
#define XLOG_PAGE_MAGIC 0xD11B /* can be used as WAL version indicator */
-typedef struct XLogPageHeaderData
+typedef struct PG_NO_PADDING XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
@@ -47,6 +47,7 @@ typedef struct XLogPageHeaderData
* header. Note that the continuation data isn't necessarily aligned.
*/
uint32 xlp_rem_len; /* total len of remaining data for record */
+ pg_padding_4(pg_pad);
} XLogPageHeaderData;
#define SizeOfXLogShortPHD MAXALIGN(sizeof(XLogPageHeaderData))
@@ -58,7 +59,7 @@ typedef XLogPageHeaderData *XLogPageHeader;
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
-typedef struct XLogLongPageHeaderData
+typedef struct PG_NO_PADDING XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
@@ -270,7 +271,7 @@ BackupHistoryFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr
* Information logged when we detect a change in one of the parameters
* important for Hot Standby.
*/
-typedef struct xl_parameter_change
+typedef struct PG_NO_PADDING xl_parameter_change
{
int MaxConnections;
int max_worker_processes;
@@ -280,29 +281,31 @@ typedef struct xl_parameter_change
int wal_level;
bool wal_log_hints;
bool track_commit_timestamp;
+ pg_padding_2(pg_pad);
} xl_parameter_change;
/* logs restore point */
-typedef struct xl_restore_point
+typedef struct PG_NO_PADDING xl_restore_point
{
TimestampTz rp_time;
char rp_name[MAXFNAMELEN];
} xl_restore_point;
/* Overwrite of prior contrecord */
-typedef struct xl_overwrite_contrecord
+typedef struct PG_NO_PADDING xl_overwrite_contrecord
{
XLogRecPtr overwritten_lsn;
TimestampTz overwrite_time;
} xl_overwrite_contrecord;
/* End of recovery mark, when we don't do an END_OF_RECOVERY checkpoint */
-typedef struct xl_end_of_recovery
+typedef struct PG_NO_PADDING xl_end_of_recovery
{
TimestampTz end_time;
TimeLineID ThisTimeLineID; /* new TLI */
TimeLineID PrevTimeLineID; /* previous TLI we forked off from */
int wal_level;
+ pg_padding_4(pg_pad);
} xl_end_of_recovery;
/*
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index e8999d3fe91..8c74998607d 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -38,14 +38,14 @@
* XLogRecordDataHeaderLong structs all begin with a single 'id' byte. It's
* used to distinguish between block references, and the main data structs.
*/
-typedef struct XLogRecord
+typedef struct PG_NO_PADDING XLogRecord
{
uint32 xl_tot_len; /* total len of entire record */
TransactionId xl_xid; /* xact id */
XLogRecPtr xl_prev; /* ptr to previous record in log */
uint8 xl_info; /* flag bits, see below */
RmgrId xl_rmid; /* resource manager for this record */
- /* 2 bytes of padding here, initialize to zero */
+ pg_padding_2(pg_pad);
pg_crc32c xl_crc; /* CRC for this record */
/* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */
@@ -100,7 +100,7 @@ typedef struct XLogRecord
* Note that we don't attempt to align the XLogRecordBlockHeader struct!
* So, the struct must be copied to aligned local storage before use.
*/
-typedef struct XLogRecordBlockHeader
+typedef struct PG_NO_PADDING XLogRecordBlockHeader
{
uint8 id; /* block reference ID */
uint8 fork_flags; /* fork within the relation, and flags */
@@ -112,7 +112,7 @@ typedef struct XLogRecordBlockHeader
/* BlockNumber follows */
} XLogRecordBlockHeader;
-#define SizeOfXLogRecordBlockHeader (offsetof(XLogRecordBlockHeader, data_length) + sizeof(uint16))
+#define SizeOfXLogRecordBlockHeader (sizeof(XLogRecordBlockHeader))
/*
* Additional header information when a full-page image is included
@@ -138,11 +138,12 @@ typedef struct XLogRecordBlockHeader
* compressed, the amount of block data actually present is less than
* BLCKSZ - the length of "hole" bytes - the length of extra information.
*/
-typedef struct XLogRecordBlockImageHeader
+typedef struct PG_NO_PADDING XLogRecordBlockImageHeader
{
uint16 length; /* number of page image bytes */
uint16 hole_offset; /* number of bytes before "hole" */
uint8 bimg_info; /* flag bits, see below */
+ pg_padding_1(pg_pad);
/*
* If BKPIMAGE_HAS_HOLE and BKPIMAGE_COMPRESSED(), an
@@ -151,7 +152,7 @@ typedef struct XLogRecordBlockImageHeader
} XLogRecordBlockImageHeader;
#define SizeOfXLogRecordBlockImageHeader \
- (offsetof(XLogRecordBlockImageHeader, bimg_info) + sizeof(uint8))
+ (sizeof(XLogRecordBlockImageHeader))
/* Information stored in bimg_info */
#define BKPIMAGE_HAS_HOLE 0x01 /* page image has "hole" */
@@ -170,7 +171,7 @@ typedef struct XLogRecordBlockImageHeader
* Extra header information used when page image has "hole" and
* is compressed.
*/
-typedef struct XLogRecordBlockCompressHeader
+typedef struct PG_NO_PADDING XLogRecordBlockCompressHeader
{
uint16 hole_length; /* number of bytes in "hole" */
} XLogRecordBlockCompressHeader;
@@ -210,7 +211,7 @@ typedef struct XLogRecordBlockCompressHeader
* (These structs are currently not used in the code, they are here just for
* documentation purposes).
*/
-typedef struct XLogRecordDataHeaderShort
+typedef struct PG_NO_PADDING XLogRecordDataHeaderShort
{
uint8 id; /* XLR_BLOCK_ID_DATA_SHORT */
uint8 data_length; /* number of payload bytes */
@@ -218,7 +219,7 @@ typedef struct XLogRecordDataHeaderShort
#define SizeOfXLogRecordDataHeaderShort (sizeof(uint8) * 2)
-typedef struct XLogRecordDataHeaderLong
+typedef struct PG_NO_PADDING XLogRecordDataHeaderLong
{
uint8 id; /* XLR_BLOCK_ID_DATA_LONG */
/* followed by uint32 data_length, unaligned */
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 7503db1af51..9e745b14177 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -32,7 +32,7 @@
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
-typedef struct CheckPoint
+typedef struct PG_NO_PADDING CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
@@ -40,8 +40,13 @@ typedef struct CheckPoint
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
int wal_level; /* current wal_level */
bool logicalDecodingEnabled; /* current logical decoding status */
+ pg_padding_1(pg_pad3);
+ pg_padding_2(pg_pad4);
+ pg_padding_4(pg_pad5);
FullTransactionId nextXid; /* next free transaction ID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
@@ -63,6 +68,7 @@ typedef struct CheckPoint
* set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
+ pg_padding_4(pg_pad6);
} CheckPoint;
/* XLOG info values for XLOG rmgr */
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index c1b2f736669..89b1bfeef6e 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -30,7 +30,7 @@
#define XLOG_SMGR_CREATE 0x10
#define XLOG_SMGR_TRUNCATE 0x20
-typedef struct xl_smgr_create
+typedef struct PG_NO_PADDING xl_smgr_create
{
RelFileLocator rlocator;
ForkNumber forkNum;
@@ -43,7 +43,7 @@ typedef struct xl_smgr_create
#define SMGR_TRUNCATE_ALL \
(SMGR_TRUNCATE_HEAP|SMGR_TRUNCATE_VM|SMGR_TRUNCATE_FSM)
-typedef struct xl_smgr_truncate
+typedef struct PG_NO_PADDING xl_smgr_truncate
{
BlockNumber blkno;
RelFileLocator rlocator;
diff --git a/src/include/commands/dbcommands_xlog.h b/src/include/commands/dbcommands_xlog.h
index 4ff3d0c82c9..04c4f35c160 100644
--- a/src/include/commands/dbcommands_xlog.h
+++ b/src/include/commands/dbcommands_xlog.h
@@ -26,7 +26,7 @@
* Single WAL record for an entire CREATE DATABASE operation. This is used
* by the FILE_COPY strategy.
*/
-typedef struct xl_dbase_create_file_copy_rec
+typedef struct PG_NO_PADDING xl_dbase_create_file_copy_rec
{
Oid db_id;
Oid tablespace_id;
@@ -39,13 +39,13 @@ typedef struct xl_dbase_create_file_copy_rec
* WAL_LOG strategy is used. Each individual block will be logged separately
* afterward.
*/
-typedef struct xl_dbase_create_wal_log_rec
+typedef struct PG_NO_PADDING xl_dbase_create_wal_log_rec
{
Oid db_id;
Oid tablespace_id;
} xl_dbase_create_wal_log_rec;
-typedef struct xl_dbase_drop_rec
+typedef struct PG_NO_PADDING xl_dbase_drop_rec
{
Oid db_id;
int ntablespaces; /* number of tablespace IDs */
diff --git a/src/include/commands/sequence_xlog.h b/src/include/commands/sequence_xlog.h
index b0495f41b43..81685f6bf04 100644
--- a/src/include/commands/sequence_xlog.h
+++ b/src/include/commands/sequence_xlog.h
@@ -31,7 +31,7 @@ typedef struct sequence_magic
} sequence_magic;
/* Sequence WAL record */
-typedef struct xl_seq_rec
+typedef struct PG_NO_PADDING xl_seq_rec
{
RelFileLocator locator;
/* SEQUENCE TUPLE DATA FOLLOWS AT THE END */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index 4fa85c2906b..f4e0be425ba 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -27,13 +27,13 @@ extern PGDLLIMPORT bool allow_in_place_tablespaces;
#define XLOG_TBLSPC_CREATE 0x00
#define XLOG_TBLSPC_DROP 0x10
-typedef struct xl_tblspc_create_rec
+typedef struct PG_NO_PADDING xl_tblspc_create_rec
{
Oid ts_id;
char ts_path[FLEXIBLE_ARRAY_MEMBER]; /* null-terminated string */
} xl_tblspc_create_rec;
-typedef struct xl_tblspc_drop_rec
+typedef struct PG_NO_PADDING xl_tblspc_drop_rec
{
Oid ts_id;
} xl_tblspc_drop_rec;
diff --git a/src/include/replication/message.h b/src/include/replication/message.h
index d1c72755084..574ae407406 100644
--- a/src/include/replication/message.h
+++ b/src/include/replication/message.h
@@ -17,10 +17,12 @@
/*
* Generic logical decoding message wal record.
*/
-typedef struct xl_logical_message
+typedef struct PG_NO_PADDING xl_logical_message
{
Oid dbId; /* database Oid emitted from */
bool transactional; /* is message transactional? */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
Size prefix_size; /* length of prefix */
Size message_size; /* size of the message */
/* payload, including null-terminated prefix of length prefix_size */
diff --git a/src/include/replication/origin.h b/src/include/replication/origin.h
index eb46b41b4b7..f7c7ee58bd9 100644
--- a/src/include/replication/origin.h
+++ b/src/include/replication/origin.h
@@ -15,14 +15,16 @@
#include "access/xlogreader.h"
#include "catalog/pg_replication_origin.h"
-typedef struct xl_replorigin_set
+typedef struct PG_NO_PADDING xl_replorigin_set
{
XLogRecPtr remote_lsn;
ReplOriginId node_id;
bool force;
+ pg_padding_1(pg_pad1);
+ pg_padding_4(pg_pad2);
} xl_replorigin_set;
-typedef struct xl_replorigin_drop
+typedef struct PG_NO_PADDING xl_replorigin_drop
{
ReplOriginId node_id;
} xl_replorigin_drop;
diff --git a/src/include/storage/lockdefs.h b/src/include/storage/lockdefs.h
index b73bb5618e6..ea95983f1e2 100644
--- a/src/include/storage/lockdefs.h
+++ b/src/include/storage/lockdefs.h
@@ -51,7 +51,7 @@ typedef int LOCKMODE;
#define InplaceUpdateTupleLock ExclusiveLock
/* WAL representation of an AccessExclusiveLock on a table */
-typedef struct xl_standby_lock
+typedef struct PG_NO_PADDING xl_standby_lock
{
TransactionId xid; /* xid of holder of AccessExclusiveLock */
Oid dbOid; /* DB containing table */
diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h
index 4d33fdcabe1..d66a095f0ea 100644
--- a/src/include/storage/sinval.h
+++ b/src/include/storage/sinval.h
@@ -58,34 +58,40 @@
* sent immediately when the underlying file change is made.
*/
-typedef struct
+typedef struct SharedInvalCatcacheMsg
{
int8 id; /* cache ID --- must be first */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
Oid dbId; /* database ID, or 0 if a shared relation */
uint32 hashValue; /* hash value of key for this catcache */
} SharedInvalCatcacheMsg;
#define SHAREDINVALCATALOG_ID (-1)
-typedef struct
+typedef struct SharedInvalCatalogMsg
{
int8 id; /* type field --- must be first */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
Oid dbId; /* database ID, or 0 if a shared catalog */
Oid catId; /* ID of catalog whose contents are invalid */
} SharedInvalCatalogMsg;
#define SHAREDINVALRELCACHE_ID (-2)
-typedef struct
+typedef struct SharedInvalRelcacheMsg
{
int8 id; /* type field --- must be first */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
Oid dbId; /* database ID, or 0 if a shared relation */
Oid relId; /* relation ID, or 0 if whole relcache */
} SharedInvalRelcacheMsg;
#define SHAREDINVALSMGR_ID (-3)
-typedef struct
+typedef struct SharedInvalSmgrMsg
{
/* note: field layout chosen to pack into 16 bytes */
int8 id; /* type field --- must be first */
@@ -96,32 +102,38 @@ typedef struct
#define SHAREDINVALRELMAP_ID (-4)
-typedef struct
+typedef struct SharedInvalRelmapMsg
{
int8 id; /* type field --- must be first */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
Oid dbId; /* database ID, or 0 for shared catalogs */
} SharedInvalRelmapMsg;
#define SHAREDINVALSNAPSHOT_ID (-5)
-typedef struct
+typedef struct SharedInvalSnapshotMsg
{
int8 id; /* type field --- must be first */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
Oid dbId; /* database ID, or 0 if a shared relation */
Oid relId; /* relation ID */
} SharedInvalSnapshotMsg;
#define SHAREDINVALRELSYNC_ID (-6)
-typedef struct
+typedef struct SharedInvalRelSyncMsg
{
int8 id; /* type field --- must be first */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
Oid dbId; /* database ID */
Oid relid; /* relation ID, or 0 if whole
* RelationSyncCache */
} SharedInvalRelSyncMsg;
-typedef union
+typedef union SharedInvalidationMessage
{
int8 id; /* type field --- must be first */
SharedInvalCatcacheMsg cc;
diff --git a/src/include/storage/standbydefs.h b/src/include/storage/standbydefs.h
index 231d251fd51..c1053cbdf22 100644
--- a/src/include/storage/standbydefs.h
+++ b/src/include/storage/standbydefs.h
@@ -35,7 +35,7 @@ extern void standby_desc_invalidations(StringInfo buf,
#define XLOG_RUNNING_XACTS 0x10
#define XLOG_INVALIDATIONS 0x20
-typedef struct xl_standby_locks
+typedef struct PG_NO_PADDING xl_standby_locks
{
int nlocks; /* number of entries in locks array */
xl_standby_lock locks[FLEXIBLE_ARRAY_MEMBER];
@@ -44,11 +44,13 @@ typedef struct xl_standby_locks
/*
* When we write running xact data to WAL, we use this structure.
*/
-typedef struct xl_running_xacts
+typedef struct PG_NO_PADDING xl_running_xacts
{
int xcnt; /* # of xact ids in xids[] */
int subxcnt; /* # of subxact ids in xids[] */
bool subxid_overflow; /* snapshot overflowed, subxids missing */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
TransactionId nextXid; /* xid from TransamVariables->nextXid */
TransactionId oldestRunningXid; /* *not* oldestXmin */
TransactionId latestCompletedXid; /* so we can set xmax */
@@ -60,11 +62,13 @@ typedef struct xl_running_xacts
* Invalidations for standby, currently only when transactions without an
* assigned xid commit.
*/
-typedef struct xl_invalidations
+typedef struct PG_NO_PADDING xl_invalidations
{
Oid dbId; /* MyDatabaseId */
Oid tsId; /* MyDatabaseTableSpace */
bool relcacheInitFileInval; /* invalidate relcache init files */
+ pg_padding_1(pg_pad1);
+ pg_padding_2(pg_pad2);
int nmsgs; /* number of shared inval msgs */
SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER];
} xl_invalidations;
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index aa9226edac3..e60f495d5d4 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -24,7 +24,7 @@
#define XLOG_RELMAP_UPDATE 0x00
-typedef struct xl_relmap_update
+typedef struct PG_NO_PADDING xl_relmap_update
{
Oid dbid; /* database ID, or 0 for shared map */
Oid tsid; /* database's tablespace, or pg_global */
diff --git a/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c b/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
index 6333661e437..2cd2ee0de14 100644
--- a/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
+++ b/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
@@ -29,7 +29,7 @@ PG_MODULE_MAGIC;
/*
* test_custom_rmgrs WAL record message.
*/
-typedef struct xl_testcustomrmgrs_message
+typedef struct PG_NO_PADDING xl_testcustomrmgrs_message
{
Size message_size; /* size of the message */
char message[FLEXIBLE_ARRAY_MEMBER]; /* payload */
diff --git a/src/test/recovery/t/039_end_of_wal.pl b/src/test/recovery/t/039_end_of_wal.pl
index f46d089a0fb..766e660988e 100644
--- a/src/test/recovery/t/039_end_of_wal.pl
+++ b/src/test/recovery/t/039_end_of_wal.pl
@@ -100,10 +100,11 @@ sub build_page_header
# I for xlp_tli
# II for xlp_pageaddr
# I for xlp_rem_len
- return pack("SSIIII",
+ # I for pg_pad
+ return pack("SSIIIII",
$xlp_magic, $xlp_info, $xlp_tli,
$BIG_ENDIAN ? 0 : $xlp_pageaddr,
- $BIG_ENDIAN ? $xlp_pageaddr : 0, $xlp_rem_len);
+ $BIG_ENDIAN ? $xlp_pageaddr : 0, $xlp_rem_len, 0);
}
# Setup a new node. The configuration chosen here minimizes the number
--
2.43.0
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-18 02:20 Michael Paquier <[email protected]>
parent: Zsolt Parragi <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Michael Paquier @ 2026-03-18 02:20 UTC (permalink / raw)
To: Zsolt Parragi <[email protected]>; +Cc: Bertrand Drouvot <[email protected]>; Alexander Kuzmenkov <[email protected]>; Heikki Linnakangas <[email protected]>; Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On Tue, Mar 17, 2026 at 06:45:46PM +0000, Zsolt Parragi wrote:
> What do you think? I'm interested in opinions about both the specific
> case, and the generic idea of using custom clang-tidy checks for
> various postgres-specific checks. As I mentioned at the beginning of
> the message I think this could be useful for other things and doesn't
> always require custom annotations, in several cases it could work
> without any C code change.
That's an interesting idea to be more aggressive in terms of the
checks done, but the invasiveness and the footprint this involves in
the WAL insertion code paths makes it a no-go for me.
Valgrind has proved to be quite useful over the years. Sure, it takes
more time to run it, but for this specific issue I don't see why we
should not continue relying on it, not reinventing the wheel, and it's
served us pretty well. While removing padding is a nice practice on
clean ground to make WAL records reproducible, that would mean forcing
the rule even for custom WAL RMGRs. Some could say that they're OK to
live with some padding, and that we don't have to be strictly
aggressive at the code level.
Different opinions are of course welcome, that's just my feeling on
the matter about your proposal.
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, 2-signature.asc)
download
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-18 06:33 Zsolt Parragi <[email protected]>
parent: Michael Paquier <[email protected]>
0 siblings, 0 replies; 16+ messages in thread
From: Zsolt Parragi @ 2026-03-18 06:33 UTC (permalink / raw)
To: Michael Paquier <[email protected]>; +Cc: Bertrand Drouvot <[email protected]>; Alexander Kuzmenkov <[email protected]>; Heikki Linnakangas <[email protected]>; Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
Thank you for the feedback!
> but the invasiveness and the footprint this involves in
> the WAL insertion code paths makes it a no-go for me.
Invasiveness is an option I choose, not a requirement.
In an alternative version, this could work in a "less strict" mode, on
top of Alexander's memset patch, verifying that: if we see a function
that uses XLogRegisterData, and the variable passed to it is defined
in the same function/translation unit (which is most of the case), we
require that variable to be well initialized - either all fields have
to be specified by hand, or it needs an initializer block/memset at
the beginning -- or if it has compiler generated padding inside, it
requires memset, as that's the only thing guaranteed to initialize it.
Similarly instead of requiring explicit padding added to the end of
the struct, it could instead verify that 1. the SizeOf macros are
correctly defined, refer to the proper size 2. if a SizeOf macro is
defined, the struct is properly memset at every location where it it
used
In that version, there would be little or no change over Alexander's
previous patch, other than adding pg-tidy itself to the build. I can
also create a version with that approach, it should be relatively
simply as I won't have to modify the WAL structs/calls like in this
version.
> Valgrind has proved to be quite useful over the years. Sure, it takes
> more time to run it, but for this specific issue I don't see why we
> should not continue relying on it
I'm not saying that we should rely on valgrind, it is a good tool and
it possibly catches things this wouldn't. This would be an additional
tool, offering the advantage of being quick and integrated into the
build. (Valgrind is also integrated, but it is also slow, I don't
think everyone runs it regularly as part of normal development)
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-18 06:59 Michael Paquier <[email protected]>
parent: Alexander Kuzmenkov <[email protected]>
1 sibling, 1 reply; 16+ messages in thread
From: Michael Paquier @ 2026-03-18 06:59 UTC (permalink / raw)
To: Alexander Kuzmenkov <[email protected]>; +Cc: Heikki Linnakangas <[email protected]>; Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On Mon, Mar 16, 2026 at 05:14:10PM +0100, Alexander Kuzmenkov wrote:
> +-- Test insert-driven cleanup of dead index tuples (_hash_vacuum_one_page).
> +TRUNCATE hash_cleanup_heap;
> +INSERT INTO hash_cleanup_heap SELECT 1 FROM generate_series(1, 1000) as i;
> +DELETE FROM hash_cleanup_heap
> + WHERE ctid IN ('(0,5)','(0,10)','(0,15)','(0,20)','(0,25)',
> + '(0,30)','(0,35)','(0,40)','(0,45)','(0,50)');
> +SET enable_seqscan = off;
> +SET enable_bitmapscan = off;
> +SELECT count(*) FROM hash_cleanup_heap WHERE keycol = 1;
> +INSERT INTO hash_cleanup_heap SELECT 1 FROM generate_series(1, 200) as i;
> +RESET enable_seqscan;
> +RESET enable_bitmapscan;
> +
> -- Clean up.
> DROP TABLE hash_cleanup_heap;
Hmm. If I take this SQL sequence independently or with an
installcheck, the one-page VACUUM path is taken during the final
INSERT, but that's not the case of a `make check`. Could this be made
more stable? I have not spent a lot of time on it, so I may be
missing something obvious, of course.
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, 2-signature.asc)
download
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-18 10:42 Alexander Kuzmenkov <[email protected]>
parent: Michael Paquier <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Alexander Kuzmenkov @ 2026-03-18 10:42 UTC (permalink / raw)
To: Michael Paquier <[email protected]>; +Cc: Heikki Linnakangas <[email protected]>; Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On Wed, Mar 18, 2026 at 7:59 AM Michael Paquier <[email protected]> wrote:
> Hmm. If I take this SQL sequence independently or with an
> installcheck, the one-page VACUUM path is taken during the final
> INSERT, but that's not the case of a `make check`. Could this be made
> more stable? I have not spent a lot of time on it, so I may be
> missing something obvious, of course.
I think this might be caused by "make check" running many tests in
parallel, so the deleting transaction is visible to some snapshots, and the
cleanup is not done. Not sure what's the best way to improve this.
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-18 12:18 Heikki Linnakangas <[email protected]>
parent: Alexander Kuzmenkov <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Heikki Linnakangas @ 2026-03-18 12:18 UTC (permalink / raw)
To: Alexander Kuzmenkov <[email protected]>; Michael Paquier <[email protected]>; +Cc: Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On 18/03/2026 12:42, Alexander Kuzmenkov wrote:
> On Wed, Mar 18, 2026 at 7:59 AM Michael Paquier <[email protected]
> <mailto:[email protected]>> wrote:
>
> Hmm. If I take this SQL sequence independently or with an
> installcheck, the one-page VACUUM path is taken during the final
> INSERT, but that's not the case of a `make check`. Could this be made
> more stable? I have not spent a lot of time on it, so I may be
> missing something obvious, of course.
>
>
> I think this might be caused by "make check" running many tests in
> parallel, so the deleting transaction is visible to some snapshots, and
> the cleanup is not done. Not sure what's the best way to improve this.
I think if you use "BEGIN; INSERT ...; ROLLBACK;" to generate the dead
tuples instead of DELETE, it will not be sensitive to concurrent
snapshots like that.
- Heikki
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: Fix uninitialized xl_running_xacts padding
@ 2026-03-22 06:50 Michael Paquier <[email protected]>
parent: Heikki Linnakangas <[email protected]>
0 siblings, 0 replies; 16+ messages in thread
From: Michael Paquier @ 2026-03-22 06:50 UTC (permalink / raw)
To: Heikki Linnakangas <[email protected]>; +Cc: Alexander Kuzmenkov <[email protected]>; Andres Freund <[email protected]>; Anthonin Bonnefoy <[email protected]>; Bertrand Drouvot <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers
On Wed, Mar 18, 2026 at 02:18:45PM +0200, Heikki Linnakangas wrote:
> I think if you use "BEGIN; INSERT ...; ROLLBACK;" to generate the dead
> tuples instead of DELETE, it will not be sensitive to concurrent snapshots
> like that.
Nice trick, this makes the test stable. I have reused it and applied
this part to take care of the coverage hole.
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, 2-signature.asc)
download
^ permalink raw reply [nested|flat] 16+ messages in thread
end of thread, other threads:[~2026-03-22 06:50 UTC | newest]
Thread overview: 16+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-02-16 20:10 Re: Fix uninitialized xl_running_xacts padding Andres Freund <[email protected]>
2026-03-10 21:51 ` Alexander Kuzmenkov <[email protected]>
2026-03-10 22:09 ` Heikki Linnakangas <[email protected]>
2026-03-11 10:45 ` Alexander Kuzmenkov <[email protected]>
2026-03-11 11:07 ` Alexander Kuzmenkov <[email protected]>
2026-03-12 12:54 ` Heikki Linnakangas <[email protected]>
2026-03-12 18:23 ` Alexander Kuzmenkov <[email protected]>
2026-03-16 16:14 ` Alexander Kuzmenkov <[email protected]>
2026-03-17 12:43 ` Bertrand Drouvot <[email protected]>
2026-03-17 18:45 ` Zsolt Parragi <[email protected]>
2026-03-18 02:20 ` Michael Paquier <[email protected]>
2026-03-18 06:33 ` Zsolt Parragi <[email protected]>
2026-03-18 06:59 ` Michael Paquier <[email protected]>
2026-03-18 10:42 ` Alexander Kuzmenkov <[email protected]>
2026-03-18 12:18 ` Heikki Linnakangas <[email protected]>
2026-03-22 06:50 ` Michael Paquier <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox