PgStat_HashKey padding issue when passed by reference

Started by Sami Imseih4 months ago29 messages
#1Sami Imseih
samimseih@gmail.com
1 attachment(s)

Hi,

I was experimenting with adding a new OID field to PgStat_HashKey:

```
typedef struct PgStat_HashKey
{
PgStat_Kind kind; /* statistics entry kind */
Oid dboid; /* database ID. InvalidOid for shared objects. */
Oid newfield;
uint64 objid; /* object ID (table, function, etc.), or
* identifier. */
} PgStat_HashKey;
```

It's important to observe that hole padding is added with this new
field:

```
(gdb) ptype /o PgStat_HashKey
type = struct PgStat_HashKey {
/* 0 | 4 */ uint32 kind;
/* 4 | 4 */ Oid dboid;
/* 8 | 4 */ Oid newfield;
/* XXX 4-byte hole */
/* 16 | 8 */ uint64 objid;

/* total size (bytes): 24 */
}
```

With "newfield" added, I started seeing the error "entry ref vanished
before deletion" when creating the cluster (or selecting from
pg_stat_database, etc.).

This error occurs when the local reference to a pgstat entry is deleted
and the entry can't be found in the simplehash pgStatEntryRefHash,
based on the key.

```
if (!pgstat_entry_ref_hash_delete(pgStatEntryRefHash, key))
elog(ERROR, "entry ref vanished before deletion");
```

This is surprising because this entry with the key is created earlier
via pgstat_get_entry_ref_cached -> pgstat_entry_ref_hash_insert.

When I brought this up to Bertrand (CC'd), he was not able to reproduce the
ERROR by adding a new field, and we quickly realized that it is related
to the compiler optimization (-O) flags we were using. He was building
with -O0 (no optimization) and I was building with -O2. So something
with optimization was causing the issue.

Starting a problematic cluster with Valgrind:

```
valgrind --leak-check=full --track-origins=yes \
$PGHOME/bin/postgres -D $PGDATA --single -P
```

shows messages like "Use of uninitialised value of size 8":

```
==26625== Use of uninitialised value of size 8
==26625== at 0x61D04F: pgstat_get_entry_ref_cached (pgstat_shmem.c:405)
==26625== by 0x61D04F: pgstat_get_entry_ref (pgstat_shmem.c:488)
==26625== by 0x6177B9: pgstat_fetch_entry (pgstat.c:977)
==26625== by 0x5433B2: rebuild_database_list (autovacuum.c:1002)
```

Further debugging led us to the fact that the key is passed-by-value to

```
pgstat_get_entry_ref_cached(PgStat_HashKey key, PgStat_EntryRef **entry_ref_p)
```

and in that routine the entry is created:

```
cache_entry = pgstat_entry_ref_hash_insert(pgStatEntryRefHash, key, &found);
``

The hash for the key is created with fasthash32(key, size, 0) and
compared against another key using memcmp(a, b, sizeof(PgStat_HashKey))
in the "pgstat_hash_hash_key" and "pgstat_cmp_hash_key" routines,
respectively.

With -O2, we observed that (on our testing environment):

pgstat_get_entry_ref_cached() is inlined
the inlined code does not copy the hole padding content when the key
is passed-by-value

So that while the hole initially contains zeroes:

```
/* clear padding */
memset(&key, 0, sizeof(struct PgStat_HashKey));
```

We observed that the zeroes in the hole are not copied to
pgstat_get_entry_ref_cached()
when passed-by-value with -O2.

GDB when setting a breakpoint at pgstat_entry_ref_hash_insert (which
is called inside
pgstat_get_entry_ref_cached) shows that the padding has some unexpected
values, see the 12-15th byte "0x00 0x23 0x21 0x21" which based on the
memset done earlier should be 0.

```
(gdb) x/24xb d
0x7fff68cc16f0: 0x02 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x7fff68cc16f8: 0x00 0x00 0x00 0x00 0x00 0x23 0x21 0x21
0x7fff68cc1700: 0x67 0x0a 0x00 0x00 0x00 0x00 0x00 0x00
(gdb)
```

Now, if we pass the key by reference to pgstat_entry_ref_hash_insert as is
patched, we can see the padding is in fact cleared.

```
(gdb) x/24xb d
0x7ffe1bf6c640: 0x01 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x7ffe1bf6c648: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffe1bf6c650: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
```

This looks like a compiler bug, we tested multiple ways to workaround:

1/ pg_noinline pgstat_get_entry_ref_cached
2/ making volatile the PgStat_HashKey key in the
pgstat_get_entry_ref_cached parameter
3/ Passing the key by reference instead of by value
4/ set SH_SCOPE to "external" rather than "static inline" in pgstat_shmem.c

it seems, at least for this case, the best option is to pass the key
by reference, like
in the attached patch.

FWIW, quickly looking at other areas that pass keys around, we can
also otherhash
keys being passed by value here:
```
spcachekey_hash();
spcachekey_equal():
```

but does not look problematic, as only the string field of the struct is hashed.

--
Sami Imseih
Amazon Web Services (AWS)

Attachments:

v1-0001-Fix-PgStat_HashKey-padding-issue-when-passed-by-r.patchapplication/octet-stream; name=v1-0001-Fix-PgStat_HashKey-padding-issue-when-passed-by-r.patchDownload
From 44c10d802f29bf49f7317b17d46ab6f9d132b7bd Mon Sep 17 00:00:00 2001
From: Ubuntu <ubuntu@ip-172-31-46-230.ec2.internal>
Date: Thu, 4 Sep 2025 16:00:23 +0000
Subject: [PATCH v1 1/1] Fix PgStat_HashKey padding issue when passed by
 reference

Adding a new OID field to PgStat_HashKey introduced 4 bytes of hole
padding. When the key was passed by value to
pgstat_get_entry_ref_cached(), builds with -O2 or higher optimization
sometimes left the padding uninitialized. Since hash/compare functions
of the key rely on the the full struct contents, inconsistent padding
caused spurious errors such as "entry ref vanished before deletion".

Passing the key by reference ensures padding is preserved and avoids
mismatches under optimization. Other hash key uses were reviewed and do
not appear to be affected.
---
 src/backend/utils/activity/pgstat_shmem.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index 62de3474453..4492f3f9890 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -385,7 +385,7 @@ pgstat_acquire_entry_ref(PgStat_EntryRef *entry_ref,
  * Helper function for pgstat_get_entry_ref().
  */
 static bool
-pgstat_get_entry_ref_cached(PgStat_HashKey key, PgStat_EntryRef **entry_ref_p)
+pgstat_get_entry_ref_cached(PgStat_HashKey *key, PgStat_EntryRef **entry_ref_p)
 {
 	bool		found;
 	PgStat_EntryRefHashEntry *cache_entry;
@@ -396,7 +396,7 @@ pgstat_get_entry_ref_cached(PgStat_HashKey key, PgStat_EntryRef **entry_ref_p)
 	 * out-of-memory errors after incrementing PgStatShared_Common->refcount.
 	 */
 
-	cache_entry = pgstat_entry_ref_hash_insert(pgStatEntryRefHash, key, &found);
+	cache_entry = pgstat_entry_ref_hash_insert(pgStatEntryRefHash, *key, &found);
 
 	if (!found || !cache_entry->entry_ref)
 	{
@@ -485,7 +485,7 @@ pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, uint64 objid, bool create,
 	 * First check the lookup cache hashtable in local memory. If we find a
 	 * match here we can avoid taking locks / causing contention.
 	 */
-	if (pgstat_get_entry_ref_cached(key, &entry_ref))
+	if (pgstat_get_entry_ref_cached(&key, &entry_ref))
 		return entry_ref;
 
 	Assert(entry_ref != NULL);
-- 
2.43.0

#2Sami Imseih
samimseih@gmail.com
In reply to: Sami Imseih (#1)
Re: PgStat_HashKey padding issue when passed by reference

I forgot to CC Bertrand as mentioned above.

--

Sami Imseih
Amazon Web Services (AWS)

#3Andres Freund
andres@anarazel.de
In reply to: Sami Imseih (#1)
Re: PgStat_HashKey padding issue when passed by reference

Hi,

On 2025-09-04 11:14:53 -0500, Sami Imseih wrote:

GDB when setting a breakpoint at pgstat_entry_ref_hash_insert (which
is called inside
pgstat_get_entry_ref_cached) shows that the padding has some unexpected
values, see the 12-15th byte "0x00 0x23 0x21 0x21" which based on the
memset done earlier should be 0.

```
(gdb) x/24xb d
0x7fff68cc16f0: 0x02 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x7fff68cc16f8: 0x00 0x00 0x00 0x00 0x00 0x23 0x21 0x21
0x7fff68cc1700: 0x67 0x0a 0x00 0x00 0x00 0x00 0x00 0x00
(gdb)
```

Now, if we pass the key by reference to pgstat_entry_ref_hash_insert as is
patched, we can see the padding is in fact cleared.

```
(gdb) x/24xb d
0x7ffe1bf6c640: 0x01 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x7ffe1bf6c648: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffe1bf6c650: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
```

This looks like a compiler bug, we tested multiple ways to workaround:

Padding bytes aren't guaranteed to be zeroed, unless you take care to zero
them out with memset or such. That's not a compiler bug.

Greetings,

Andres Freund

#4Sami Imseih
samimseih@gmail.com
In reply to: Andres Freund (#3)
Re: PgStat_HashKey padding issue when passed by reference

This looks like a compiler bug, we tested multiple ways to workaround:

Padding bytes aren't guaranteed to be zeroed, unless you take care to zero
them out with memset or such. That's not a compiler bug.

Perhaps calling this a compiler bug is not appropriate.
However, memset is in fact called when the key is created

```
/* clear padding */
memset(&key, 0, sizeof(struct PgStat_HashKey));
```

but the zeroed out padding bytes are not retained when the
key is passed by value. This is why the proposal is to pass the
key by reference.

--
Sami Imseih
Amazon Web Services (AWS)

#5Ranier Vilela
ranier.vf@gmail.com
In reply to: Sami Imseih (#1)
Re: PgStat_HashKey padding issue when passed by reference

Em qui., 4 de set. de 2025 às 13:15, Sami Imseih <samimseih@gmail.com>
escreveu:

Hi,

I was experimenting with adding a new OID field to PgStat_HashKey:

```
typedef struct PgStat_HashKey
{
PgStat_Kind kind; /* statistics entry kind */
Oid dboid; /* database ID. InvalidOid for shared objects. */
Oid newfield;
uint64 objid; /* object ID (table, function, etc.), or
* identifier. */
} PgStat_HashKey;
```

It's important to observe that hole padding is added with this new
field:

```
(gdb) ptype /o PgStat_HashKey
type = struct PgStat_HashKey {
/* 0 | 4 */ uint32 kind;
/* 4 | 4 */ Oid dboid;
/* 8 | 4 */ Oid newfield;
/* XXX 4-byte hole */
/* 16 | 8 */ uint64 objid;

/* total size (bytes): 24 */
}
```

With "newfield" added, I started seeing the error "entry ref vanished
before deletion" when creating the cluster (or selecting from
pg_stat_database, etc.).

This error occurs when the local reference to a pgstat entry is deleted
and the entry can't be found in the simplehash pgStatEntryRefHash,
based on the key.

```
if (!pgstat_entry_ref_hash_delete(pgStatEntryRefHash, key))
elog(ERROR, "entry ref vanished before deletion");
```

This is surprising because this entry with the key is created earlier
via pgstat_get_entry_ref_cached -> pgstat_entry_ref_hash_insert.

When I brought this up to Bertrand (CC'd), he was not able to reproduce the
ERROR by adding a new field, and we quickly realized that it is related
to the compiler optimization (-O) flags we were using. He was building
with -O0 (no optimization) and I was building with -O2. So something
with optimization was causing the issue.

Starting a problematic cluster with Valgrind:

```
valgrind --leak-check=full --track-origins=yes \
$PGHOME/bin/postgres -D $PGDATA --single -P
```

shows messages like "Use of uninitialised value of size 8":

```
==26625== Use of uninitialised value of size 8
==26625== at 0x61D04F: pgstat_get_entry_ref_cached (pgstat_shmem.c:405)
==26625== by 0x61D04F: pgstat_get_entry_ref (pgstat_shmem.c:488)
==26625== by 0x6177B9: pgstat_fetch_entry (pgstat.c:977)
==26625== by 0x5433B2: rebuild_database_list (autovacuum.c:1002)
```

Further debugging led us to the fact that the key is passed-by-value to

```
pgstat_get_entry_ref_cached(PgStat_HashKey key, PgStat_EntryRef
**entry_ref_p)
```

and in that routine the entry is created:

```
cache_entry = pgstat_entry_ref_hash_insert(pgStatEntryRefHash, key,
&found);
``

The hash for the key is created with fasthash32(key, size, 0) and
compared against another key using memcmp(a, b, sizeof(PgStat_HashKey))
in the "pgstat_hash_hash_key" and "pgstat_cmp_hash_key" routines,
respectively.

With -O2, we observed that (on our testing environment):

pgstat_get_entry_ref_cached() is inlined
the inlined code does not copy the hole padding content when the key
is passed-by-value

So that while the hole initially contains zeroes:

```
/* clear padding */
memset(&key, 0, sizeof(struct PgStat_HashKey));
```

We observed that the zeroes in the hole are not copied to
pgstat_get_entry_ref_cached()
when passed-by-value with -O2.

GDB when setting a breakpoint at pgstat_entry_ref_hash_insert (which
is called inside
pgstat_get_entry_ref_cached) shows that the padding has some unexpected
values, see the 12-15th byte "0x00 0x23 0x21 0x21" which based on the
memset done earlier should be 0.

```
(gdb) x/24xb d
0x7fff68cc16f0: 0x02 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x7fff68cc16f8: 0x00 0x00 0x00 0x00 0x00 0x23 0x21 0x21
0x7fff68cc1700: 0x67 0x0a 0x00 0x00 0x00 0x00 0x00 0x00
(gdb)
```

Now, if we pass the key by reference to pgstat_entry_ref_hash_insert as is
patched, we can see the padding is in fact cleared.

```
(gdb) x/24xb d
0x7ffe1bf6c640: 0x01 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x7ffe1bf6c648: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffe1bf6c650: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
```

This looks like a compiler bug, we tested multiple ways to workaround:

1/ pg_noinline pgstat_get_entry_ref_cached
2/ making volatile the PgStat_HashKey key in the
pgstat_get_entry_ref_cached parameter
3/ Passing the key by reference instead of by value
4/ set SH_SCOPE to "external" rather than "static inline" in pgstat_shmem.c

it seems, at least for this case, the best option is to pass the key
by reference, like
in the attached patch.

+1
Not to mention that it is faster to pass the parameter by reference.

best regards,
Ranier Vilela

#6Sami Imseih
samimseih@gmail.com
In reply to: Ranier Vilela (#5)
Re: PgStat_HashKey padding issue when passed by reference

+1
Not to mention that it is faster to pass the parameter by reference.

yes, there is potentially better performance.

BTW. My mistake. The subject of this thread should be
"PgStat_HashKey padding issue when passed by value"

--
Sami Imseih
Amazon Web Services (AWS)

#7Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#4)
Re: PgStat_HashKey padding issue when passed by reference

On Thu, Sep 04, 2025 at 11:50:15AM -0500, Sami Imseih wrote:

Perhaps calling this a compiler bug is not appropriate.
However, memset is in fact called when the key is created

```
/* clear padding */
memset(&key, 0, sizeof(struct PgStat_HashKey));
```

but the zeroed out padding bytes are not retained when the
key is passed by value. This is why the proposal is to pass the
key by reference.

So your point is that this impacts the hash lookups and the fact that
we rely on passing PgStat_HashKey around due to the internals of how
pgstat_shmem.c is shaped for its dshash.

Did you run a full installcheck under valgrind to have more confidence
that this is the only code path where we care about the padding of the
passed-in values for the hash lookups?

There are a lot of things that use simplehash.h, so one could question
if we should think about that from a higher point of view, and if
there could be some compiler magic that could be used to enforce a
policy (don't think there is any magic for the padding of passed-in
values, just wondering if there is something I don't know about that
could justify a more global policy that can be applied to everything
that uses simplehash.h).

One idea would be, for example, that keys used with simplehash should
never have any padding at all, and we could force a check in the shape
of a static assertion to force a failure when attempting to compile
code that attempts to do so. That would give us a way to check in a
broader way if some code path do that currently, scaling better with
the expectations we could have in the whole tree or even out-of-core
extension code.
--
Michael

#8Michael Paquier
michael@paquier.xyz
In reply to: Michael Paquier (#7)
Re: PgStat_HashKey padding issue when passed by reference

On Sat, Sep 06, 2025 at 10:35:58AM +0900, Michael Paquier wrote:

One idea would be, for example, that keys used with simplehash should
never have any padding at all, and we could force a check in the shape
of a static assertion to force a failure when attempting to compile
code that attempts to do so. That would give us a way to check in a
broader way if some code path do that currently, scaling better with
the expectations we could have in the whole tree or even out-of-core
extension code.

Doing some research here, I have noticed this one:
https://en.cppreference.com/w/cpp/types/has_unique_object_representations.html

I was also wondering about some use of pg_attribute_packed() here, or
perhaps enforce a check based on offsetof() and the structure size,
but I doubt that any of that would be really portable across the
buildfarm.

Another idea would be to make sure that the sizeof() of the structure
matches with the sum of the sizeof() for the individual fields in it.
That's cumbersome to rely on, still simpler. Perhaps we could do
something among these lines for pgstat_shmem.c, or just document that
the structure should never have any padding.
--
Michael

#9Andres Freund
andres@anarazel.de
In reply to: Michael Paquier (#8)
Re: PgStat_HashKey padding issue when passed by reference

Hi,

On 2025-09-08 10:25:13 +0900, Michael Paquier wrote:

On Sat, Sep 06, 2025 at 10:35:58AM +0900, Michael Paquier wrote:

One idea would be, for example, that keys used with simplehash should
never have any padding at all, and we could force a check in the shape
of a static assertion to force a failure when attempting to compile
code that attempts to do so. That would give us a way to check in a
broader way if some code path do that currently, scaling better with
the expectations we could have in the whole tree or even out-of-core
extension code.

Doing some research here, I have noticed this one:
https://en.cppreference.com/w/cpp/types/has_unique_object_representations.html

I was also wondering about some use of pg_attribute_packed() here, or
perhaps enforce a check based on offsetof() and the structure size,
but I doubt that any of that would be really portable across the
buildfarm.

Another idea would be to make sure that the sizeof() of the structure
matches with the sum of the sizeof() for the individual fields in it.
That's cumbersome to rely on, still simpler. Perhaps we could do
something among these lines for pgstat_shmem.c, or just document that
the structure should never have any padding.

I'd just add a comment mentioning that any padding bytes should be avoided.

Greetings,

Andres

#10Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#8)
1 attachment(s)
Re: PgStat_HashKey padding issue when passed by reference

Did you run a full installcheck under valgrind to have more confidence
that this is the only code path where we care about the padding of the
passed-in values for the hash lookups?

I did and could not reproduce "Use of uninitialised value..." on HEAD.

I will mention that it's not a simple reproducible exercise, at least
I could not repro with a simple C program that compiled with -O2.

Another idea would be to make sure that the sizeof() of the structure
matches with the sum of the sizeof() for the individual fields in it.
That's cumbersome to rely on, still simpler. Perhaps we could do
something among these lines for pgstat_shmem.c, or just document that
the structure should never have any padding.

I'd just add a comment mentioning that any padding bytes should be avoided.

or instead of avoiding padding, we continue to do what we do which
is zeroing out the key when creating, but to make sure we pass it by
reference so the hash_hash/hash_compare functions are operating on the same
memor.I think that is all we really need. in v2 I added a comment
to clarify why pass-by-reference is needed.

Thoughts?

--
Sami

Attachments:

v2-0001-Fix-PgStat_HashKey-padding-issue-when-passed-by-v.patchapplication/octet-stream; name=v2-0001-Fix-PgStat_HashKey-padding-issue-when-passed-by-v.patchDownload
From 020b9a770ceedce2e3769a6474e6b9ff76333046 Mon Sep 17 00:00:00 2001
From: Ubuntu <ubuntu@ip-172-31-46-230.ec2.internal>
Date: Thu, 4 Sep 2025 16:00:23 +0000
Subject: [PATCH v2 1/1] Fix PgStat_HashKey padding issue when passed by value

Adding a new OID field to PgStat_HashKey introduced 4 bytes of hole
padding. When the key was passed by value to
pgstat_get_entry_ref_cached(), builds with -O2 or higher optimization
sometimes left the padding uninitialized. Since hash/compare functions
of the key rely on the the full struct contents, inconsistent padding
caused spurious errors such as "entry ref vanished before deletion".

Passing the key by reference ensures padding is preserved and avoids
mismatches under optimization. Other hash key uses were reviewed and do
not appear to be affected.
---
 src/backend/utils/activity/pgstat_shmem.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index 9dc3212f7dd..2824b092cda 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -395,9 +395,13 @@ pgstat_acquire_entry_ref(PgStat_EntryRef *entry_ref,
 
 /*
  * Helper function for pgstat_get_entry_ref().
+ *
+ * Use pass-by-reference for PgStat_HashKey to preserve any padding bytes
+ * previously zeroed by the caller. Passing by value could leave these
+ * bytes uninitialized, breaking key comparisons in pgstat_cmp_hash_key.
  */
 static bool
-pgstat_get_entry_ref_cached(PgStat_HashKey key, PgStat_EntryRef **entry_ref_p)
+pgstat_get_entry_ref_cached(PgStat_HashKey *key, PgStat_EntryRef **entry_ref_p)
 {
 	bool		found;
 	PgStat_EntryRefHashEntry *cache_entry;
@@ -408,7 +412,7 @@ pgstat_get_entry_ref_cached(PgStat_HashKey key, PgStat_EntryRef **entry_ref_p)
 	 * out-of-memory errors after incrementing PgStatShared_Common->refcount.
 	 */
 
-	cache_entry = pgstat_entry_ref_hash_insert(pgStatEntryRefHash, key, &found);
+	cache_entry = pgstat_entry_ref_hash_insert(pgStatEntryRefHash, *key, &found);
 
 	if (!found || !cache_entry->entry_ref)
 	{
@@ -497,7 +501,7 @@ pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, uint64 objid, bool create,
 	 * First check the lookup cache hashtable in local memory. If we find a
 	 * match here we can avoid taking locks / causing contention.
 	 */
-	if (pgstat_get_entry_ref_cached(key, &entry_ref))
+	if (pgstat_get_entry_ref_cached(&key, &entry_ref))
 		return entry_ref;
 
 	Assert(entry_ref != NULL);
-- 
2.43.0

#11Michael Paquier
michael@paquier.xyz
In reply to: Andres Freund (#9)
1 attachment(s)
Re: PgStat_HashKey padding issue when passed by reference

On Mon, Sep 08, 2025 at 12:08:12PM -0400, Andres Freund wrote:

On 2025-09-08 10:25:13 +0900, Michael Paquier wrote:

Another idea would be to make sure that the sizeof() of the structure
matches with the sum of the sizeof() for the individual fields in it.
That's cumbersome to rely on, still simpler. Perhaps we could do
something among these lines for pgstat_shmem.c, or just document that
the structure should never have any padding.

I'd just add a comment mentioning that any padding bytes should be avoided.

Agreed on this part.

I am wondering also about the addition of a static assertion as well,
as it seems that this thread and the opinions on it point to such an
addition having value, and requiring valgrind to detect that is
annoying, especially if people propose more patches in the future that
may affect the way we pass the hash key values in this area of the
code. An idea is attached.
--
Michael

Attachments:

pgstat-hashkey-padding.patchtext/x-diff; charset=us-asciiDownload
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index 6cf00008f633..d5869299fa86 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -57,6 +57,15 @@ typedef struct PgStat_HashKey
 								 * identifier. */
 } PgStat_HashKey;
 
+/*
+ * PgStat_HashKey should not have any padding.  Checking that the structure
+ * size matches with the sum of each field is a check simple enough to
+ * enforce this policy.
+ */
+StaticAssertDecl((sizeof(PgStat_Kind) + sizeof(uint64) + sizeof(Oid)) ==
+				 sizeof(PgStat_HashKey),
+				 "PgStat_HashKey should have no padding");
+
 /*
  * Shared statistics hash entry. Doesn't itself contain any stats, but points
  * to them (with ->body). That allows the stats entries themselves to be of
#12Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#11)
Re: PgStat_HashKey padding issue when passed by reference

I'd just add a comment mentioning that any padding bytes should be avoided.

Agreed on this part.

I am wondering also about the addition of a static assertion as well,
as it seems that this thread and the opinions on it point to such an
addition having value, and requiring valgrind to detect that is
annoying, especially if people propose more patches in the future that
may affect the way we pass the hash key values in this area of the
code. An idea is attached.

hmm, so if we decide to add a member that has a type that requires
padding, the assert will fail? I am not sure I like this very much, since
we lose flexibility on the struct member types that can be used. See
the examples below on top of pgstat-hashkey-padding.patch

The following will fail the assert since padding is needed for the
new Oid member.

```
index d5869299fa8..4cdd41fda3a 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -53,6 +53,7 @@ typedef struct PgStat_HashKey
 {
        PgStat_Kind kind;                       /* statistics entry kind */
        Oid                     dboid;                  /* database
ID. InvalidOid for shared objects. */
+       Oid                 field1;
        uint64          objid;                  /* object ID (table,
function, etc.), or
                                                                 *
identifier. */
 } PgStat_HashKey;
@@ -62,7 +63,7 @@ typedef struct PgStat_HashKey
  * size matches with the sum of each field is a check simple enough to
  * enforce this policy.
  */
-StaticAssertDecl((sizeof(PgStat_Kind) + sizeof(uint64) + sizeof(Oid)) ==
+StaticAssertDecl((sizeof(PgStat_Kind) + sizeof(uint64) + sizeof(Oid)
+ sizeof(Oid)) ==
                                 sizeof(PgStat_HashKey),
                                 "PgStat_HashKey should have no padding");
```

This will not fail the assert, since no padding is needed for the new member.

```
diff --git a/src/include/utils/pgstat_internal.h
b/src/include/utils/pgstat_internal.h
index d5869299fa8..5732c89219d 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -53,6 +53,7 @@ typedef struct PgStat_HashKey
 {
        PgStat_Kind kind;                       /* statistics entry kind */
        Oid                     dboid;                  /* database
ID. InvalidOid for shared objects. */
+       uint64          field1;
        uint64          objid;                  /* object ID (table,
function, etc.), or
                                                                 *
identifier. */
 } PgStat_HashKey;
@@ -62,7 +63,7 @@ typedef struct PgStat_HashKey
  * size matches with the sum of each field is a check simple enough to
  * enforce this policy.
  */
-StaticAssertDecl((sizeof(PgStat_Kind) + sizeof(uint64) + sizeof(Oid)) ==
+StaticAssertDecl((sizeof(PgStat_Kind) + sizeof(uint64) + sizeof(Oid)
+ sizeof(uint64)) ==
                                 sizeof(PgStat_HashKey),
                                 "PgStat_HashKey should have no padding");
```

--
Sami

#13Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#12)
Re: PgStat_HashKey padding issue when passed by reference

On Mon, Sep 08, 2025 at 09:20:14PM -0500, Sami Imseih wrote:

The following will fail the assert since padding is needed for the
new Oid member.

@@ -53,6 +53,7 @@ typedef struct PgStat_HashKey
{
PgStat_Kind kind; /* statistics entry kind */
Oid dboid; /* database
ID. InvalidOid for shared objects. */
+ Oid field1;
uint64 objid; /* object ID (table,
function, etc.), or

This will not fail the assert, since no padding is needed for the new member.

@@ -53,6 +53,7 @@ typedef struct PgStat_HashKey
{
PgStat_Kind kind; /* statistics entry kind */
Oid dboid; /* database
ID. InvalidOid for shared objects. */
+ uint64 field1;
uint64 objid; /* object ID (table,
function, etc.), or

Exactly. Hence my proposal of static assertion is doing exactly the
job I want it to do :)
--
Michael

#14Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#13)
Re: PgStat_HashKey padding issue when passed by reference

Exactly. Hence my proposal of static assertion is doing exactly the
job I want it to do :)

But my concern is the flexibility of this approach. If someone is to add an
OID field next, they will not be able to as that will be introducing
padding.
On the other hand, passing the key by reference and documenting the reason
in
pgstat_shmem.c will not lose this flexibility.

--
Sami

Show quoted text
#15Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#14)
1 attachment(s)
Re: PgStat_HashKey padding issue when passed by reference

On Mon, Sep 08, 2025 at 09:36:52PM -0500, Sami Imseih wrote:

But my concern is the flexibility of this approach. If someone is to add an
OID field next, they will not be able to as that will be introducing
padding. On the other hand, passing the key by reference and
documenting the reason in pgstat_shmem.c will not lose this
flexibility.

I don't mind discarding the static assertion idea, but at the end what
counts for me here is that I don't want to sacrifice future changes in
the pgstats code that would always require passing around the hash key
by reference. So I would just do like attached, documenting at the
top of PgStat_HashKey that we should not have padding in it, removing
three memset(0) calls that expected it.
--
Michael

Attachments:

0001-Document-no-padding-rule-for-PgStat_HashKey.patchtext/x-diff; charset=us-asciiDownload
From 104ab93d761746366d6e71e84472f3a3264e7a5b Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 11 Sep 2025 11:50:18 +0900
Subject: [PATCH] Document no-padding rule for PgStat_HashKey

This removes a couple of memset(0) calls, as we don't want padding in
it.
---
 src/include/utils/pgstat_internal.h       |  6 +++++-
 src/backend/utils/activity/pgstat.c       |  5 +----
 src/backend/utils/activity/pgstat_shmem.c | 10 ++--------
 3 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index 6cf00008f633..b62747a3ba05 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -48,7 +48,11 @@
  * PgStatShared_Common as the first element.
  */
 
-/* struct for shared statistics hash entry key. */
+/*
+ * Struct for shared statistics hash entry key.
+ *
+ * NB: We assume that this struct contains no padding.
+ */
 typedef struct PgStat_HashKey
 {
 	PgStat_Kind kind;			/* statistics entry kind */
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index f8e91484e36b..73c2ced3f4e2 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -932,7 +932,7 @@ pgstat_clear_snapshot(void)
 void *
 pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
 {
-	PgStat_HashKey key;
+	PgStat_HashKey key = {0};
 	PgStat_EntryRef *entry_ref;
 	void	   *stats_data;
 	const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
@@ -943,9 +943,6 @@ pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
 
 	pgstat_prep_snapshot();
 
-	/* clear padding */
-	memset(&key, 0, sizeof(struct PgStat_HashKey));
-
 	key.kind = kind;
 	key.dboid = dboid;
 	key.objid = objid;
diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index 9dc3212f7dd0..ca36fd247f64 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -456,14 +456,11 @@ PgStat_EntryRef *
 pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, uint64 objid, bool create,
 					 bool *created_entry)
 {
-	PgStat_HashKey key;
+	PgStat_HashKey key = {0};
 	PgStatShared_HashEntry *shhashent;
 	PgStatShared_Common *shheader = NULL;
 	PgStat_EntryRef *entry_ref;
 
-	/* clear padding */
-	memset(&key, 0, sizeof(struct PgStat_HashKey));
-
 	key.kind = kind;
 	key.dboid = dboid;
 	key.objid = objid;
@@ -988,13 +985,10 @@ pgstat_drop_database_and_contents(Oid dboid)
 bool
 pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
 {
-	PgStat_HashKey key;
+	PgStat_HashKey key = {0};
 	PgStatShared_HashEntry *shent;
 	bool		freed = true;
 
-	/* clear padding */
-	memset(&key, 0, sizeof(struct PgStat_HashKey));
-
 	key.kind = kind;
 	key.dboid = dboid;
 	key.objid = objid;
-- 
2.51.0

#16Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#15)
Re: PgStat_HashKey padding issue when passed by reference

On Mon, Sep 08, 2025 at 09:36:52PM -0500, Sami Imseih wrote:

But my concern is the flexibility of this approach. If someone is to add an
OID field next, they will not be able to as that will be introducing
padding. On the other hand, passing the key by reference and
documenting the reason in pgstat_shmem.c will not lose this
flexibility.

I don't mind discarding the static assertion idea, but at the end what
counts for me here is that I don't want to sacrifice future changes in
the pgstats code that would always require passing around the hash key
by reference.

I don't see how this improves the situation, but will just make it more
difficult to add a new field that requires padding in the future.

If we are documenting either way, I rather that we just document the need
to pass a key by reference, which is the pattern used in other areas
( see pgss_store and entry_alloc in pg_stat_statements.c )

Others may have a different opinion.

--
Sami

#17Ranier Vilela
ranier.vf@gmail.com
In reply to: Michael Paquier (#15)
Re: PgStat_HashKey padding issue when passed by reference

Em qua., 10 de set. de 2025 às 23:53, Michael Paquier <michael@paquier.xyz>
escreveu:

On Mon, Sep 08, 2025 at 09:36:52PM -0500, Sami Imseih wrote:

But my concern is the flexibility of this approach. If someone is to add

an

OID field next, they will not be able to as that will be introducing
padding. On the other hand, passing the key by reference and
documenting the reason in pgstat_shmem.c will not lose this
flexibility.

I don't mind discarding the static assertion idea, but at the end what
counts for me here is that I don't want to sacrifice future changes in
the pgstats code that would always require passing around the hash key
by reference.

So I would just do like attached, documenting at the
top of PgStat_HashKey that we should not have padding in it, removing
three memset(0) calls that expected it.

Currently no compiler guarantees that static initialization will fill
possible holes,
something that *memset* guarantees.
I think this change is unsafe.

best regards,
Ranier Vilela

#18Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#16)
Re: PgStat_HashKey padding issue when passed by reference

On Thu, Sep 11, 2025 at 10:21:45AM -0500, Sami Imseih wrote:

I don't see how this improves the situation, but will just make it more
difficult to add a new field that requires padding in the future.

If we are documenting either way, I rather that we just document the need
to pass a key by reference, which is the pattern used in other areas
( see pgss_store and entry_alloc in pg_stat_statements.c )

Others may have a different opinion.

Yeah, I do care about the size of the hash key. So if someone goes on
and proposes the addition of a new field while we already have 8 bytes
for the object ID, that can itself be the hash of something else
because we area already set up for life in terms of value friction, we
will have an interesting debate. Adding padding is not something I'd
be OK with, even if the hash key compaction could be enforced with a
compiler attribute.

And FWIW, I'm not much a fan of the expectations documented at the top
of pgssHashKey with its padding bytes, neither am I convinced that it
is a good idea to spread that more than necessary and bloat the size
of the hash key. That's just my opinion, other opinions may differ of
course, and I'm OK to be outvoted.
--
Michael

#19Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#18)
Re: PgStat_HashKey padding issue when passed by reference

I don't see how this improves the situation, but will just make it more
difficult to add a new field that requires padding in the future.

If we are documenting either way, I rather that we just document the need
to pass a key by reference, which is the pattern used in other areas
( see pgss_store and entry_alloc in pg_stat_statements.c )

Others may have a different opinion.

Yeah, I do care about the size of the hash key. So if someone goes on
and proposes the addition of a new field while we already have 8 bytes
for the object ID, that can itself be the hash of something else
because we area already set up for life in terms of value friction, we
will have an interesting debate.

Just to confirm, you are saying we are unlikely to ever add a new field
to the key. Is that correct?

--
Sami Imseih
Amazon Web Services (AWS)

#20Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#19)
Re: PgStat_HashKey padding issue when passed by reference

On Mon, Sep 15, 2025 at 04:47:27PM -0500, Sami Imseih wrote:

Just to confirm, you are saying we are unlikely to ever add a new field
to the key. Is that correct?

I would rather avoid that, yes.
--
Michael

#21Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#20)
Re: PgStat_HashKey padding issue when passed by reference

On Mon, Sep 15, 2025 at 04:47:27PM -0500, Sami Imseih wrote:

Just to confirm, you are saying we are unlikely to ever add a new field
to the key. Is that correct?

I would rather avoid that, yes.

7d85d87f4d5c35 added code to clear the padding bytes with memset
in anticipation that the key could be changed in the future, in a way
that padding will be introduced. So, if we are changing thoughts on
this, we should add additional comments next to
```
+ * NB: We assume that this struct contains no padding.
```
to enforce that the hash stored in objid should be used to
support additional fields, rather than adding a field directly
into the key. Will help future patch reviews/designs.

--
Sami

#22Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#21)
Re: PgStat_HashKey padding issue when passed by reference

On Tue, Sep 16, 2025 at 02:38:20PM -0500, Sami Imseih wrote:

7d85d87f4d5c35 added code to clear the padding bytes with memset
in anticipation that the key could be changed in the future, in a way
that padding will be introduced.

Yep. The argument raised on this thread with the requirement of the
key being passed by reference has made me change my mind, because I
did not thing that valgrind would complain with that. So yes, I'm
backpedalling a bit. Sorry for the confusion.

So, if we are changing thoughts on
this, we should add additional comments next to
```
+ * NB: We assume that this struct contains no padding.
```
to enforce that the hash stored in objid should be used to
support additional fields, rather than adding a field directly
into the key.

Hmm. Do you have a specific suggestion for enhancement? I can
think about something like this wording:
"NB: We assume that this struct contains no padding. The 8 bytes
allocated for the object ID are good enough to ensure the uniqueness
of the hash key, hence the addition of new fields is not recommended."

More suggestions or a better sentence are of course welcome.

Will help future patch reviews/designs.

Cool, thanks.
--
Michael

#23Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#22)
Re: PgStat_HashKey padding issue when passed by reference

More suggestions or a better sentence are of course welcome.

"NB: We assume that this struct contains no padding. The 8 bytes
allocated for the object ID are good enough to ensure the uniqueness
of the hash key, hence the addition of new fields is not recommended."

That sounds correct. However, I see the no padding and the objid as separate
points. One could add a new field that does not introduce padding. So, I added
"Also, " for clarity.

"NB: We assume that this struct contains no padding. Also, 8 bytes
allocated for the object ID are good enough to ensure the uniqueness
of the hash key, hence the addition of new fields is not recommended."

Also, what about we also add the assert as done earlier in this thread [0]/messages/by-id/aL9zo5X0MsSxO2pM@paquier.xyz
to ensure that the struct indeed does not have padding?

+/*
+ * PgStat_HashKey should not have any padding. Checking that the structure
+ * size matches with the sum of each field is a check simple enough to
+ * enforce this policy.
+ */
+StaticAssertDecl((sizeof(PgStat_Kind) + sizeof(uint64) + sizeof(Oid)) ==
+ sizeof(PgStat_HashKey),
+ "PgStat_HashKey should have no padding");
+

[0]: /messages/by-id/aL9zo5X0MsSxO2pM@paquier.xyz

--
Sami

#24Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#23)
1 attachment(s)
Re: PgStat_HashKey padding issue when passed by reference

On Wed, Sep 17, 2025 at 07:04:36PM -0500, Sami Imseih wrote:

"NB: We assume that this struct contains no padding. Also, 8 bytes
allocated for the object ID are good enough to ensure the uniqueness
of the hash key, hence the addition of new fields is not recommended."

Works for me.

Also, what about we also add the assert as done earlier in this thread [0]
to ensure that the struct indeed does not have padding?

I still want to add it, but it also seemed like you were not much a
fan of it, so I did not really want to push forward with something
that was not loved. :D

Addressing your points, attached is an updated patch labelled v2.
--
Michael

Attachments:

v2-0001-Document-no-padding-rule-for-PgStat_HashKey.patchtext/x-diff; charset=us-asciiDownload
From 86f6080503a5e986e7daf771d5d7970f36cc2fe6 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 18 Sep 2025 09:48:44 +0900
Subject: [PATCH v2] Document no-padding rule for PgStat_HashKey

This removes a couple of memset(0) calls, as we don't want padding in
it.  While on it, add a cheap assertion checking that no padding is
introduced in the structure, by checking that the size of PgStat_HashKey
matches with the sum of the field sizes.
---
 src/include/utils/pgstat_internal.h       | 17 ++++++++++++++++-
 src/backend/utils/activity/pgstat.c       |  5 +----
 src/backend/utils/activity/pgstat_shmem.c | 10 ++--------
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index 6cf00008f633..bf75ebcef31c 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -48,7 +48,13 @@
  * PgStatShared_Common as the first element.
  */
 
-/* struct for shared statistics hash entry key. */
+/*
+ * Struct for shared statistics hash entry key.
+ *
+ * NB: We assume that this struct contains no padding.  Also, 8 bytes
+ * allocated for the object ID are good enough to ensure the uniqueness
+ * of the hash key, hence the addition of new fields is not recommended.
+ */
 typedef struct PgStat_HashKey
 {
 	PgStat_Kind kind;			/* statistics entry kind */
@@ -57,6 +63,15 @@ typedef struct PgStat_HashKey
 								 * identifier. */
 } PgStat_HashKey;
 
+/*
+ * PgStat_HashKey should not have any padding.  Checking that the structure
+ * size matches with the sum of each field is a check simple enough to
+ * enforce this policy.
+ */
+StaticAssertDecl((sizeof(PgStat_Kind) + sizeof(uint64) + sizeof(Oid)) ==
+				 sizeof(PgStat_HashKey),
+				 "PgStat_HashKey should have no padding");
+
 /*
  * Shared statistics hash entry. Doesn't itself contain any stats, but points
  * to them (with ->body). That allows the stats entries themselves to be of
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index f8e91484e36b..73c2ced3f4e2 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -932,7 +932,7 @@ pgstat_clear_snapshot(void)
 void *
 pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
 {
-	PgStat_HashKey key;
+	PgStat_HashKey key = {0};
 	PgStat_EntryRef *entry_ref;
 	void	   *stats_data;
 	const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
@@ -943,9 +943,6 @@ pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
 
 	pgstat_prep_snapshot();
 
-	/* clear padding */
-	memset(&key, 0, sizeof(struct PgStat_HashKey));
-
 	key.kind = kind;
 	key.dboid = dboid;
 	key.objid = objid;
diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index 9dc3212f7dd0..ca36fd247f64 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -456,14 +456,11 @@ PgStat_EntryRef *
 pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, uint64 objid, bool create,
 					 bool *created_entry)
 {
-	PgStat_HashKey key;
+	PgStat_HashKey key = {0};
 	PgStatShared_HashEntry *shhashent;
 	PgStatShared_Common *shheader = NULL;
 	PgStat_EntryRef *entry_ref;
 
-	/* clear padding */
-	memset(&key, 0, sizeof(struct PgStat_HashKey));
-
 	key.kind = kind;
 	key.dboid = dboid;
 	key.objid = objid;
@@ -988,13 +985,10 @@ pgstat_drop_database_and_contents(Oid dboid)
 bool
 pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
 {
-	PgStat_HashKey key;
+	PgStat_HashKey key = {0};
 	PgStatShared_HashEntry *shent;
 	bool		freed = true;
 
-	/* clear padding */
-	memset(&key, 0, sizeof(struct PgStat_HashKey));
-
 	key.kind = kind;
 	key.dboid = dboid;
 	key.objid = objid;
-- 
2.51.0

#25Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#24)
Re: PgStat_HashKey padding issue when passed by reference

I still want to add it, but it also seemed like you were not much a
fan of it, so I did not really want to push forward with something
that was not loved. :D

Addressing your points, attached is an updated patch labelled v2.

I was not a fan of it, when my idea was to allow flexibility in adding
more fields to the key. However, I am now convinced objid should be
good enough.

v2 looks good to me. Not sure if there are edge cases in which
the assert will succeed even with padding (I can't think of any way
that will be possible), so for now what you have seems good enough.

--
Sami

#26Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#25)
Re: PgStat_HashKey padding issue when passed by reference

On Thu, Sep 18, 2025 at 11:52:05AM -0500, Sami Imseih wrote:

v2 looks good to me. Not sure if there are edge cases in which
the assert will succeed even with padding (I can't think of any way
that will be possible), so for now what you have seems good enough.

Okay, I've applied that on HEAD, then. I didn't see an urge in
backpatching it. If there is an ask to do so, I could always do so
later.
--
Michael

#27Sami Imseih
samimseih@gmail.com
In reply to: Michael Paquier (#26)
Re: PgStat_HashKey padding issue when passed by reference

On Thu, Sep 18, 2025 at 11:52:05AM -0500, Sami Imseih wrote:

v2 looks good to me. Not sure if there are edge cases in which
the assert will succeed even with padding (I can't think of any way
that will be possible), so for now what you have seems good enough.

Okay, I've applied that on HEAD, then. I didn't see an urge in
backpatching it. If there is an ask to do so, I could always do so
later.
--
Michael

Thank you! I update the CF entry [0]https://commitfest.postgresql.org/patch/6033/ as committed.

[0]: https://commitfest.postgresql.org/patch/6033/

--
Sami

#28Michael Paquier
michael@paquier.xyz
In reply to: Sami Imseih (#27)
Re: PgStat_HashKey padding issue when passed by reference

On Fri, Sep 19, 2025 at 08:52:24PM -0500, Sami Imseih wrote:

Thank you! I update the CF entry [0] as committed.

[0] https://commitfest.postgresql.org/patch/6033/

Oops, missed this part. Thanks.
--
Michael

#29Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Sami Imseih (#25)
Re: PgStat_HashKey padding issue when passed by reference

Hi,

On Thu, Sep 18, 2025 at 11:52:05AM -0500, Sami Imseih wrote:

I still want to add it, but it also seemed like you were not much a
fan of it, so I did not really want to push forward with something
that was not loved. :D

Addressing your points, attached is an updated patch labelled v2.

I was not a fan of it, when my idea was to allow flexibility in adding
more fields to the key. However, I am now convinced objid should be
good enough.

+ * NB: We assume that this struct contains no padding.  Also, 8 bytes
+ * allocated for the object ID are good enough to ensure the uniqueness
+ * of the hash key, hence the addition of new fields is not recommended.

yeah that would also work for [1]/messages/by-id/ZlGYokUIlERemvpB@ip-10-97-1-34.eu-west-3.compute.internal, where the objoid could then store a spcOid
and a relNumber (so that all the RelFileLocator fields would be stored) means:

dboid (linked to RelFileLocator's dbOid)
objoid (linked to RelFileLocator's spcOid and to the RelFileLocator's relNumber)

[1]: /messages/by-id/ZlGYokUIlERemvpB@ip-10-97-1-34.eu-west-3.compute.internal

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com