Commit 058a050e authored by Magnus Hagander's avatar Magnus Hagander

Fix memory and file descriptor leaks in pg_receivexlog/pg_basebackup

When the internal loop mode was added, freeing memory and closing
filedescriptors before returning became important, and a few cases
in the code missed that.

Fujii Masao
parent 84a42560
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
#define STREAMING_HEADER_SIZE (1+sizeof(WalDataMessageHeader)) #define STREAMING_HEADER_SIZE (1+sizeof(WalDataMessageHeader))
#define STREAMING_KEEPALIVE_SIZE (1+sizeof(PrimaryKeepaliveMessage)) #define STREAMING_KEEPALIVE_SIZE (1+sizeof(PrimaryKeepaliveMessage))
/* fd for currently open WAL file */
static int walfile = -1;
/* /*
* Open a new WAL file in the specified directory. Store the name * Open a new WAL file in the specified directory. Store the name
* (not including the full directory) in namebuf. Assumes there is * (not including the full directory) in namebuf. Assumes there is
...@@ -96,6 +100,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu ...@@ -96,6 +100,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu
{ {
fprintf(stderr, _("%s: could not pad WAL segment %s: %s\n"), fprintf(stderr, _("%s: could not pad WAL segment %s: %s\n"),
progname, fn, strerror(errno)); progname, fn, strerror(errno));
free(zerobuf);
close(f); close(f);
unlink(fn); unlink(fn);
return -1; return -1;
...@@ -120,7 +125,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu ...@@ -120,7 +125,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu
* completed writing the whole segment. * completed writing the whole segment.
*/ */
static bool static bool
close_walfile(int walfile, char *basedir, char *walname, bool segment_complete) close_walfile(char *basedir, char *walname, bool segment_complete)
{ {
off_t currpos = lseek(walfile, 0, SEEK_CUR); off_t currpos = lseek(walfile, 0, SEEK_CUR);
...@@ -142,8 +147,10 @@ close_walfile(int walfile, char *basedir, char *walname, bool segment_complete) ...@@ -142,8 +147,10 @@ close_walfile(int walfile, char *basedir, char *walname, bool segment_complete)
{ {
fprintf(stderr, _("%s: could not close file %s: %s\n"), fprintf(stderr, _("%s: could not close file %s: %s\n"),
progname, walname, strerror(errno)); progname, walname, strerror(errno));
walfile = -1;
return false; return false;
} }
walfile = -1;
/* /*
* Rename the .partial file only if we've completed writing the whole * Rename the .partial file only if we've completed writing the whole
...@@ -270,7 +277,6 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -270,7 +277,6 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
char current_walfile_name[MAXPGPATH]; char current_walfile_name[MAXPGPATH];
PGresult *res; PGresult *res;
char *copybuf = NULL; char *copybuf = NULL;
int walfile = -1;
int64 last_status = -1; int64 last_status = -1;
XLogRecPtr blockpos = InvalidXLogRecPtr; XLogRecPtr blockpos = InvalidXLogRecPtr;
...@@ -315,6 +321,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -315,6 +321,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: could not start replication: %s\n"), fprintf(stderr, _("%s: could not start replication: %s\n"),
progname, PQresultErrorMessage(res)); progname, PQresultErrorMessage(res));
PQclear(res);
return false; return false;
} }
PQclear(res); PQclear(res);
...@@ -341,9 +348,9 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -341,9 +348,9 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
*/ */
if (stream_stop && stream_stop(blockpos, timeline, false)) if (stream_stop && stream_stop(blockpos, timeline, false))
{ {
if (walfile != -1) if (walfile != -1 && !close_walfile(basedir, current_walfile_name, rename_partial))
/* Potential error message is written by close_walfile */ /* Potential error message is written by close_walfile */
return close_walfile(walfile, basedir, current_walfile_name, rename_partial); goto error;
return true; return true;
} }
...@@ -370,7 +377,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -370,7 +377,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: could not send feedback packet: %s"), fprintf(stderr, _("%s: could not send feedback packet: %s"),
progname, PQerrorMessage(conn)); progname, PQerrorMessage(conn));
return false; goto error;
} }
last_status = now; last_status = now;
...@@ -421,14 +428,14 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -421,14 +428,14 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: select() failed: %s\n"), fprintf(stderr, _("%s: select() failed: %s\n"),
progname, strerror(errno)); progname, strerror(errno));
return false; goto error;
} }
/* Else there is actually data on the socket */ /* Else there is actually data on the socket */
if (PQconsumeInput(conn) == 0) if (PQconsumeInput(conn) == 0)
{ {
fprintf(stderr, _("%s: could not receive data from WAL stream: %s\n"), fprintf(stderr, _("%s: could not receive data from WAL stream: %s\n"),
progname, PQerrorMessage(conn)); progname, PQerrorMessage(conn));
return false; goto error;
} }
continue; continue;
} }
...@@ -439,7 +446,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -439,7 +446,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: could not read copy data: %s\n"), fprintf(stderr, _("%s: could not read copy data: %s\n"),
progname, PQerrorMessage(conn)); progname, PQerrorMessage(conn));
return false; goto error;
} }
if (copybuf[0] == 'k') if (copybuf[0] == 'k')
{ {
...@@ -451,7 +458,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -451,7 +458,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: keepalive message is incorrect size: %d\n"), fprintf(stderr, _("%s: keepalive message is incorrect size: %d\n"),
progname, r); progname, r);
return false; goto error;
} }
continue; continue;
} }
...@@ -459,13 +466,13 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -459,13 +466,13 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: unrecognized streaming header: \"%c\"\n"), fprintf(stderr, _("%s: unrecognized streaming header: \"%c\"\n"),
progname, copybuf[0]); progname, copybuf[0]);
return false; goto error;
} }
if (r < STREAMING_HEADER_SIZE + 1) if (r < STREAMING_HEADER_SIZE + 1)
{ {
fprintf(stderr, _("%s: streaming header too small: %d\n"), fprintf(stderr, _("%s: streaming header too small: %d\n"),
progname, r); progname, r);
return false; goto error;
} }
/* Extract WAL location for this block */ /* Extract WAL location for this block */
...@@ -483,7 +490,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -483,7 +490,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: received xlog record for offset %u with no file open\n"), fprintf(stderr, _("%s: received xlog record for offset %u with no file open\n"),
progname, xlogoff); progname, xlogoff);
return false; goto error;
} }
} }
else else
...@@ -494,7 +501,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -494,7 +501,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: got WAL data offset %08x, expected %08x\n"), fprintf(stderr, _("%s: got WAL data offset %08x, expected %08x\n"),
progname, xlogoff, (int) lseek(walfile, 0, SEEK_CUR)); progname, xlogoff, (int) lseek(walfile, 0, SEEK_CUR));
return false; goto error;
} }
} }
...@@ -520,7 +527,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -520,7 +527,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
basedir, current_walfile_name); basedir, current_walfile_name);
if (walfile == -1) if (walfile == -1)
/* Error logged by open_walfile */ /* Error logged by open_walfile */
return false; goto error;
} }
if (write(walfile, if (write(walfile,
...@@ -532,7 +539,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -532,7 +539,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
bytes_to_write, bytes_to_write,
current_walfile_name, current_walfile_name,
strerror(errno)); strerror(errno));
return false; goto error;
} }
/* Write was successful, advance our position */ /* Write was successful, advance our position */
...@@ -544,11 +551,10 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -544,11 +551,10 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
/* Did we reach the end of a WAL segment? */ /* Did we reach the end of a WAL segment? */
if (blockpos % XLOG_SEG_SIZE == 0) if (blockpos % XLOG_SEG_SIZE == 0)
{ {
if (!close_walfile(walfile, basedir, current_walfile_name, false)) if (!close_walfile(basedir, current_walfile_name, false))
/* Error message written in close_walfile() */ /* Error message written in close_walfile() */
return false; goto error;
walfile = -1;
xlogoff = 0; xlogoff = 0;
if (stream_stop != NULL) if (stream_stop != NULL)
...@@ -577,8 +583,22 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi ...@@ -577,8 +583,22 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
{ {
fprintf(stderr, _("%s: unexpected termination of replication stream: %s\n"), fprintf(stderr, _("%s: unexpected termination of replication stream: %s\n"),
progname, PQresultErrorMessage(res)); progname, PQresultErrorMessage(res));
return false; goto error;
} }
PQclear(res); PQclear(res);
if (copybuf != NULL)
PQfreemem(copybuf);
if (walfile != -1 && close(walfile) != 0)
fprintf(stderr, _("%s: could not close file %s: %s\n"),
progname, current_walfile_name, strerror(errno));
return true; return true;
error:
if (copybuf != NULL)
PQfreemem(copybuf);
if (walfile != -1 && close(walfile) != 0)
fprintf(stderr, _("%s: could not close file %s: %s\n"),
progname, current_walfile_name, strerror(errno));
return false;
} }
...@@ -143,6 +143,17 @@ GetConnection(void) ...@@ -143,6 +143,17 @@ GetConnection(void)
tmpconn = PQconnectdbParams(keywords, values, true); tmpconn = PQconnectdbParams(keywords, values, true);
/*
* If there is too little memory even to allocate the PGconn object
* and PQconnectdbParams returns NULL, we call exit(1) directly.
*/
if (!tmpconn)
{
fprintf(stderr, _("%s: could not connect to server\n"),
progname);
exit(1);
}
if (PQstatus(tmpconn) == CONNECTION_BAD && if (PQstatus(tmpconn) == CONNECTION_BAD &&
PQconnectionNeedsPassword(tmpconn) && PQconnectionNeedsPassword(tmpconn) &&
dbgetpassword != -1) dbgetpassword != -1)
...@@ -154,8 +165,11 @@ GetConnection(void) ...@@ -154,8 +165,11 @@ GetConnection(void)
if (PQstatus(tmpconn) != CONNECTION_OK) if (PQstatus(tmpconn) != CONNECTION_OK)
{ {
fprintf(stderr, _("%s: could not connect to server: %s"), fprintf(stderr, _("%s: could not connect to server: %s\n"),
progname, PQerrorMessage(tmpconn)); progname, PQerrorMessage(tmpconn));
PQfinish(tmpconn);
free(values);
free(keywords);
return NULL; return NULL;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment