0001-Fix-subscriber-invalid-memory-access-on-DDL.patch

application/x-patch

Filename: 0001-Fix-subscriber-invalid-memory-access-on-DDL.patch
Type: application/x-patch
Part: 0
Message: Re: segmentation fault when cassert enabled

Patch

Format: format-patch
Series: patch 0001
Subject: Fix subscriber invalid memory access on DDL
File+
src/backend/replication/logical/relation.c 39 14
From 9bec5e5250c5af034096ed9ab966c2c237518976 Mon Sep 17 00:00:00 2001
From: Jehan-Guillaume de Rorthais <jgdr@dalibo.com>, vignesh.c <vignesh21@gmail.com>
Date: Fri, 13 Dec 2019 11:59:13 +0530
Subject: [PATCH] Fix subscriber invalid memory access on DDL

Before this patch, the attrmap structure mapping the local fields
to remote ones for a subscribed relation was rebuild before handling
pending invalidation messages and potential relcache updates. This
was leading to an invalid memory access by overflowing the attrmap
when building the related tuple slot received from the provider.
---
 src/backend/replication/logical/relation.c | 53 ++++++++++++++++++++++--------
 1 file changed, 39 insertions(+), 14 deletions(-)

diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index b386f84..9009ebc 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -220,6 +220,8 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 {
 	LogicalRepRelMapEntry *entry;
 	bool		found;
+	Oid			relid = InvalidOid;
+	LogicalRepRelation	*remoterel;
 
 	if (LogicalRepRelMap == NULL)
 		logicalrep_relmap_init();
@@ -232,20 +234,24 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 		elog(ERROR, "no relation map entry for remote relation ID %u",
 			 remoteid);
 
-	/* Need to update the local cache? */
-	if (!OidIsValid(entry->localreloid))
-	{
-		Oid			relid;
-		int			i;
-		int			found;
-		Bitmapset  *idkey;
-		TupleDesc	desc;
-		LogicalRepRelation *remoterel;
-		MemoryContext oldctx;
+	remoterel = &entry->remoterel;
 
-		remoterel = &entry->remoterel;
+	/*
+	 * entry->localreloid is set to InvalidOid when the local relation is
+	 * either unknown or invalidated.
+	 * Moreover, when opening and locking a relation, pending invalidation
+	 * messages are processed.
+	 * Because of that, we first need to open the local relation, then rebuild
+	 * the mapping of local attribute if the relation is invalidated.
+	 */
 
-		/* Try to find and lock the relation by name. */
+	/*
+	 * Unknown or invalidated local relation. First look for its oid and open
+	 * it. We will build the mapping of local attributes after.
+	 */
+	if (!OidIsValid(entry->localreloid))
+	{
+		/* Try to find the relation by name */
 		relid = RangeVarGetRelid(makeRangeVar(remoterel->nspname,
 											  remoterel->relname, -1),
 								 lockmode, true);
@@ -256,6 +262,27 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 							remoterel->nspname, remoterel->relname)));
 		entry->localrel = table_open(relid, NoLock);
 
+	}
+	else
+	{
+		relid = entry->localreloid;
+		entry->localrel = table_open(entry->localreloid, lockmode);
+	}
+
+	/*
+	 * Pending invalidation messages might have been processed while grabbing
+	 * the lock during table_open, applying some DDL operations that are then
+	 * reflected in the relcache.
+	 * Because of that, we need to rebuild the mapping of local attribute after
+	 * the relation is opened.
+	 */
+	if (!OidIsValid(entry->localreloid)) {
+		int			found;
+		Bitmapset  *idkey;
+		TupleDesc	desc;
+		MemoryContext oldctx;
+		int			i;
+
 		/* Check for supported relkind. */
 		CheckSubscriptionRelkind(entry->localrel->rd_rel->relkind,
 								 remoterel->nspname, remoterel->relname);
@@ -350,8 +377,6 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 
 		entry->localreloid = relid;
 	}
-	else
-		entry->localrel = table_open(entry->localreloid, lockmode);
 
 	if (entry->state != SUBREL_STATE_READY)
 		entry->state = GetSubscriptionRelState(MySubscription->oid,
-- 
1.8.3.1