Skip to content

Commit bc54ef4

Browse files
committed
Fix error handling in libpqrcv_connect()
When libpqrcv_connect (also known as walrcv_connect()) failed, it leaked the libpq connection. In most paths that's fairly harmless, as the calling process will exit soon after. But e.g. CREATE SUBSCRIPTION could lead to a somewhat longer lived leak. Fix by releasing resources, including the libpq connection, on error. Add a test exercising the error code path. To make it reliable and safe, the test tries to connect to port=-1, which happens to fail during connection establishment, rather than during connection string parsing. Reviewed-by: Noah Misch <noah@leadboat.com> Discussion: https://postgr.es/m/20230121011237.q52apbvlarfv6jm6@awork3.anarazel.de Backpatch: 11-
1 parent 9567686 commit bc54ef4

File tree

3 files changed

+32
-13
lines changed

3 files changed

+32
-13
lines changed

src/backend/replication/libpqwalreceiver/libpqwalreceiver.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,7 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
175175
conn->streamConn = PQconnectStartParams(keys, vals,
176176
/* expand_dbname = */ true);
177177
if (PQstatus(conn->streamConn) == CONNECTION_BAD)
178-
{
179-
*err = pchomp(PQerrorMessage(conn->streamConn));
180-
return NULL;
181-
}
178+
goto bad_connection_errmsg;
182179

183180
/*
184181
* Poll connection until we have OK or FAILED status.
@@ -220,10 +217,7 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
220217
} while (status != PGRES_POLLING_OK && status != PGRES_POLLING_FAILED);
221218

222219
if (PQstatus(conn->streamConn) != CONNECTION_OK)
223-
{
224-
*err = pchomp(PQerrorMessage(conn->streamConn));
225-
return NULL;
226-
}
220+
goto bad_connection_errmsg;
227221

228222
if (logical)
229223
{
@@ -234,16 +228,26 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
234228
if (PQresultStatus(res) != PGRES_TUPLES_OK)
235229
{
236230
PQclear(res);
237-
ereport(ERROR,
238-
(errmsg("could not clear search path: %s",
239-
pchomp(PQerrorMessage(conn->streamConn)))));
231+
*err = psprintf(_("could not clear search path: %s"),
232+
pchomp(PQerrorMessage(conn->streamConn)));
233+
goto bad_connection;
240234
}
241235
PQclear(res);
242236
}
243237

244238
conn->logical = logical;
245239

246240
return conn;
241+
242+
/* error path, using libpq's error message */
243+
bad_connection_errmsg:
244+
*err = pchomp(PQerrorMessage(conn->streamConn));
245+
246+
/* error path, error already set */
247+
bad_connection:
248+
PQfinish(conn->streamConn);
249+
pfree(conn);
250+
return NULL;
247251
}
248252

249253
/*

src/test/regress/expected/subscription.out

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,15 @@ ALTER SUBSCRIPTION regress_testsub4 SET (origin = any);
130130

131131
DROP SUBSCRIPTION regress_testsub3;
132132
DROP SUBSCRIPTION regress_testsub4;
133-
-- fail - invalid connection string
133+
-- fail, connection string does not parse
134+
CREATE SUBSCRIPTION regress_testsub5 CONNECTION 'i_dont_exist=param' PUBLICATION testpub;
135+
ERROR: invalid connection string syntax: invalid connection option "i_dont_exist"
136+
137+
-- fail, connection string parses, but doesn't work (and does so without
138+
-- connecting, so this is reliable and safe)
139+
CREATE SUBSCRIPTION regress_testsub5 CONNECTION 'port=-1' PUBLICATION testpub;
140+
ERROR: could not connect to the publisher: invalid port number: "-1"
141+
-- fail - invalid connection string during ALTER
134142
ALTER SUBSCRIPTION regress_testsub CONNECTION 'foobar';
135143
ERROR: invalid connection string syntax: missing "=" after "foobar" in connection info string
136144

src/test/regress/sql/subscription.sql

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,14 @@ ALTER SUBSCRIPTION regress_testsub4 SET (origin = any);
7777
DROP SUBSCRIPTION regress_testsub3;
7878
DROP SUBSCRIPTION regress_testsub4;
7979

80-
-- fail - invalid connection string
80+
-- fail, connection string does not parse
81+
CREATE SUBSCRIPTION regress_testsub5 CONNECTION 'i_dont_exist=param' PUBLICATION testpub;
82+
83+
-- fail, connection string parses, but doesn't work (and does so without
84+
-- connecting, so this is reliable and safe)
85+
CREATE SUBSCRIPTION regress_testsub5 CONNECTION 'port=-1' PUBLICATION testpub;
86+
87+
-- fail - invalid connection string during ALTER
8188
ALTER SUBSCRIPTION regress_testsub CONNECTION 'foobar';
8289

8390
\dRs+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy