Hi hackers, While working on a rebase for [0], I noticed some weird behavior on the stats.
The issue is that [0], in conjonction with b14e9ce7d5, does introduce padding in the PgStat_HashKey: (gdb) ptype /o struct PgStat_HashKey /* offset | size */ type = struct PgStat_HashKey { /* 0 | 4 */ uint32 kind; /* 4 | 4 */ Oid dboid; /* 8 | 8 */ uint64 objid; /* 16 | 4 */ RelFileNumber relfile; /* XXX 4-byte padding */ /* total size (bytes): 24 */ } But, the keys are initialized that way: " PgStat_HashKey key = {.kind = kind,.dboid = dboid,.objid = objid,.relfile = refile}; " which could lead to random data in the padding bytes. We are using sizeof(PgStat_HashKey) in pgstat_cmp_hash_key() and we compute the hash hash key in pgstat_hash_hash_key() using the PgStat_HashKey struct size as input: this lead to unexpected results if the keys contain random data in the padding bytes. Even if currently there is no issues, as without [0] there is no padding: (gdb) ptype /o struct PgStat_HashKey /* offset | size */ type = struct PgStat_HashKey { /* 0 | 4 */ uint32 kind; /* 4 | 4 */ Oid dboid; /* 8 | 8 */ uint64 objid; /* total size (bytes): 16 */ } I think that we should ensure to $SUBJECT (to prevent unexpected results should padding be introduced in the future). For example we currently ensure the same for LOCALLOCKTAG localtag in LockHeldByMe() while there is no padding: gdb) ptype /o struct LOCALLOCKTAG /* offset | size */ type = struct LOCALLOCKTAG { /* 0 | 16 */ LOCKTAG lock; /* 16 | 4 */ LOCKMODE mode; /* total size (bytes): 20 */ } So, please find attached a patch to $SUBJECT. [0]: https://www.postgresql.org/message-id/flat/ZlGYokUIlERemvpB%40ip-10-97-1-34.eu-west-3.compute.internal Looking forward to your feedback, Regards, -- Bertrand Drouvot PostgreSQL Contributors Team RDS Open Source Databases Amazon Web Services: https://aws.amazon.com
>From 0a590aad0ff014dff60e5ee73bef2c5d7a659804 Mon Sep 17 00:00:00 2001 From: Bertrand Drouvot <bertranddrouvot...@gmail.com> Date: Sat, 2 Nov 2024 14:21:18 +0000 Subject: [PATCH v1] Clear padding in PgStat_HashKey keys PgStat_HashKey keys are currently initialized in a way that could result in random data in the padding bytes (if there was padding in PgStat_HashKey which is not the case currently). We are using sizeof(PgStat_HashKey) in pgstat_cmp_hash_key() and we compute the hash hash key in pgstat_hash_hash_key() using the PgStat_HashKey struct size as input. So, we have to ensure that no random data can be stored in the padding bytes (if any) of a PgStat_HashKey key. --- src/backend/utils/activity/pgstat.c | 3 +++ src/backend/utils/activity/pgstat_shmem.c | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) 100.0% src/backend/utils/activity/ diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c index be48432cc3..ea8c5691e8 100644 --- a/src/backend/utils/activity/pgstat.c +++ b/src/backend/utils/activity/pgstat.c @@ -938,6 +938,9 @@ 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 a09c6fee05..c1b7ff76b1 100644 --- a/src/backend/utils/activity/pgstat_shmem.c +++ b/src/backend/utils/activity/pgstat_shmem.c @@ -432,11 +432,18 @@ PgStat_EntryRef * pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, uint64 objid, bool create, bool *created_entry) { - PgStat_HashKey key = {.kind = kind,.dboid = dboid,.objid = objid}; + PgStat_HashKey key; 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; + /* * passing in created_entry only makes sense if we possibly could create * entry. @@ -908,10 +915,17 @@ pgstat_drop_database_and_contents(Oid dboid) bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid) { - PgStat_HashKey key = {.kind = kind,.dboid = dboid,.objid = objid}; + PgStat_HashKey key; PgStatShared_HashEntry *shent; bool freed = true; + /* clear padding */ + memset(&key, 0, sizeof(struct PgStat_HashKey)); + + key.kind = kind; + key.dboid = dboid; + key.objid = objid; + /* delete local reference */ if (pgStatEntryRefHash) { -- 2.34.1