From fbaf30392aca794a667e21616138a544c264d17c Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Mon, 5 Mar 2018 09:44:49 +1300
Subject: [PATCH] Fix detach race condition in shm_mq.c.

Commit 34db06ef9a1d7f36391c64293bf1e0ce44a33915 adopted a lock-free design
for shm_mq.c, but it introduced a race condition that could lose messages.
When shm_mq_receive_bytes() detects that the other end has detached, it must
make sure that it has seen the final version of mq_bytes_written, or it might
miss a message sent before detaching.  Repair by reading the values in the
correct order.

Thomas Munro
Discussion: https://postgr.es/m/CAEepm%3D2myZ4qxpt1a%3DC%2BwEv3o188K13K3UvD-44FK0SdAzHy%2Bw%40mail.gmail.com
---
 src/backend/storage/ipc/shm_mq.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index 40df8e1251e..3e7ee758d3b 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -1020,6 +1020,15 @@ shm_mq_receive_bytes(shm_mq_handle *mqh, Size bytes_needed, bool nowait,
 	{
 		Size		offset;
 		uint64		read;
+		bool		detached;
+
+		/*
+		 * Read the detached flag first and then insert a read barrier, to
+		 * make sure that we read the final version of mq_bytes_written that
+		 * was written before the flag was raised.
+		 */
+		detached = mq->mq_detached;
+		pg_read_barrier();
 
 		/* Get bytes written, so we can compute what's available to read. */
 		written = pg_atomic_read_u64(&mq->mq_bytes_written);
@@ -1057,7 +1066,7 @@ shm_mq_receive_bytes(shm_mq_handle *mqh, Size bytes_needed, bool nowait,
 		 * receiving a message stored in the buffer even after the sender has
 		 * detached.
 		 */
-		if (mq->mq_detached)
+		if (detached)
 			return SHM_MQ_DETACHED;
 
 		/*
-- 
2.16.2

