From d18e72af178a25cef1d4095de6eb13684e8c987f Mon Sep 17 00:00:00 2001
From: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Date: Tue, 25 Jun 2024 15:54:55 +0200
Subject: Fix possible overflow of pg_stat DSA's refcnt

During backend initialisation, pgStat DSA is attached using
dsa_attach_in_place with a NULL segment. The NULL segment means that
there's no callback to release the DSA when the process exits.

pgstat_detach_shmem only calls dsa_detach which, as mentioned in the
function's comment, doesn't include releasing and thus doesn't decrement
the reference count of pgStat DSA.

Thus, every time a backend is created (new connection or new parallel
worker), pgStat DSA's refcnt is increased and never decreased. It will
eventually overflow and eventually reach 0, triggering the "could not
attach to dynamic shared area" error on all newly created backends. When
this state is reached, the only way to recover is to restart the
instance to reset the counter.

This patch fixes the issue by releasing pgStat DSA with
dsa_release_in_place during pgStat shutdown to decrement refcnt.
---
 src/backend/utils/activity/pgstat_shmem.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index fb79c5e771..51008e9998 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -246,6 +246,13 @@ pgstat_detach_shmem(void)
 	pgStatLocal.shared_hash = NULL;
 
 	dsa_detach(pgStatLocal.dsa);
+
+	/*
+	 * Detach doesn't decrement dsa's refcnt and since no segment was provided
+	 * when attaching to the dsa, no cleanup callbacks are registered. We need
+	 * to manually release dsa to correctly decrement dsa's refcnt
+	 */
+	dsa_release_in_place(pgStatLocal.shmem->raw_dsa_area);
 	pgStatLocal.dsa = NULL;
 }
 
-- 
2.39.3 (Apple Git-146)

