Skip to content

Commit 62ec3e1

Browse files
michaelpqMaxim Orlov
and
Maxim Orlov
committed
Fix possible double-release of spinlock in procsignal.c
9d9b9d4 has added spinlocks to protect the fields in ProcSignal flags, introducing a code path in ProcSignalInit() where a spinlock could be released twice if the pss_pid field of a ProcSignalSlot is found as already set. Multiple spinlock releases have no effect with most spinlock implementations, but this could cause the code to run into issues when the spinlock is acquired concurrently by a different process. This sanity check on pss_pid generates a LOG that can be delayed until after the spinlock is released as, like older versions up to v17, the code expects the initialization of the ProcSignalSlot to happen even if pss_pid is found incorrect. The code is changed so as the old pss_pid is read while holding the slot's spinlock, with the LOG from the sanity check generated after releasing the spinlock, preventing the double release. Author: Maksim Melnikov <m.melnikov@postgrespro.ru> Co-authored-by: Maxim Orlov <orlovmg@gmail.com> Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru> Discussion: https://postgr.es/m/dca47527-2d8b-4e3b-b5a0-e2deb73371a4@postgrespro.ru
1 parent 15df9d7 commit 62ec3e1

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

src/backend/storage/ipc/procsignal.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,21 +167,18 @@ ProcSignalInit(bool cancel_key_valid, int32 cancel_key)
167167
{
168168
ProcSignalSlot *slot;
169169
uint64 barrier_generation;
170+
uint32 old_pss_pid;
170171

171172
if (MyProcNumber < 0)
172173
elog(ERROR, "MyProcNumber not set");
173174
if (MyProcNumber >= NumProcSignalSlots)
174175
elog(ERROR, "unexpected MyProcNumber %d in ProcSignalInit (max %d)", MyProcNumber, NumProcSignalSlots);
175176
slot = &ProcSignal->psh_slot[MyProcNumber];
176177

177-
/* sanity check */
178178
SpinLockAcquire(&slot->pss_mutex);
179-
if (pg_atomic_read_u32(&slot->pss_pid) != 0)
180-
{
181-
SpinLockRelease(&slot->pss_mutex);
182-
elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty",
183-
MyProcPid, MyProcNumber);
184-
}
179+
180+
/* Value used for sanity check below */
181+
old_pss_pid = pg_atomic_read_u32(&slot->pss_pid);
185182

186183
/* Clear out any leftover signal reasons */
187184
MemSet(slot->pss_signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
@@ -208,6 +205,11 @@ ProcSignalInit(bool cancel_key_valid, int32 cancel_key)
208205

209206
SpinLockRelease(&slot->pss_mutex);
210207

208+
/* Spinlock is released, do the check */
209+
if (old_pss_pid != 0)
210+
elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty",
211+
MyProcPid, MyProcNumber);
212+
211213
/* Remember slot location for CheckProcSignal */
212214
MyProcSignalSlot = slot;
213215

0 commit comments

Comments
 (0)