Skip to content

Commit 776bdc4

Browse files
committed
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. This is a backpatch of commit 058a050 to the 9.2 branch, which seems to have been neglected (in error, because the bugs it fixes were introduced in commit 16282ae which is present in both master and 9.2). Fujii Masao
1 parent 99dd2a3 commit 776bdc4

File tree

2 files changed

+54
-20
lines changed

2 files changed

+54
-20
lines changed

src/bin/pg_basebackup/receivelog.c

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040

4141
const XLogRecPtr InvalidXLogRecPtr = {0, 0};
4242

43+
/* fd for currently open WAL file */
44+
static int walfile = -1;
45+
46+
4347
/*
4448
* Open a new WAL file in the specified directory. Store the name
4549
* (not including the full directory) in namebuf. Assumes there is
@@ -97,6 +101,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu
97101
{
98102
fprintf(stderr, _("%s: could not pad WAL segment %s: %s\n"),
99103
progname, fn, strerror(errno));
104+
free(zerobuf);
100105
close(f);
101106
unlink(fn);
102107
return -1;
@@ -121,7 +126,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu
121126
* completed writing the whole segment.
122127
*/
123128
static bool
124-
close_walfile(int walfile, char *basedir, char *walname, bool segment_complete)
129+
close_walfile(char *basedir, char *walname, bool segment_complete)
125130
{
126131
off_t currpos = lseek(walfile, 0, SEEK_CUR);
127132

@@ -143,8 +148,10 @@ close_walfile(int walfile, char *basedir, char *walname, bool segment_complete)
143148
{
144149
fprintf(stderr, _("%s: could not close file %s: %s\n"),
145150
progname, walname, strerror(errno));
151+
walfile = -1;
146152
return false;
147153
}
154+
walfile = -1;
148155

149156
/*
150157
* Rename the .partial file only if we've completed writing the whole
@@ -271,7 +278,6 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
271278
char current_walfile_name[MAXPGPATH];
272279
PGresult *res;
273280
char *copybuf = NULL;
274-
int walfile = -1;
275281
int64 last_status = -1;
276282
XLogRecPtr blockpos = InvalidXLogRecPtr;
277283

@@ -315,6 +321,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
315321
{
316322
fprintf(stderr, _("%s: could not start replication: %s\n"),
317323
progname, PQresultErrorMessage(res));
324+
PQclear(res);
318325
return false;
319326
}
320327
PQclear(res);
@@ -341,9 +348,9 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
341348
*/
342349
if (stream_stop && stream_stop(blockpos, timeline, false))
343350
{
344-
if (walfile != -1)
351+
if (walfile != -1 && !close_walfile(basedir, current_walfile_name, rename_partial))
345352
/* Potential error message is written by close_walfile */
346-
return close_walfile(walfile, basedir, current_walfile_name, rename_partial);
353+
goto error;
347354
return true;
348355
}
349356

@@ -370,7 +377,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
370377
{
371378
fprintf(stderr, _("%s: could not send feedback packet: %s"),
372379
progname, PQerrorMessage(conn));
373-
return false;
380+
goto error;
374381
}
375382

376383
last_status = now;
@@ -421,14 +428,14 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
421428
{
422429
fprintf(stderr, _("%s: select() failed: %s\n"),
423430
progname, strerror(errno));
424-
return false;
431+
goto error;
425432
}
426433
/* Else there is actually data on the socket */
427434
if (PQconsumeInput(conn) == 0)
428435
{
429436
fprintf(stderr, _("%s: could not receive data from WAL stream: %s\n"),
430437
progname, PQerrorMessage(conn));
431-
return false;
438+
goto error;
432439
}
433440
continue;
434441
}
@@ -439,7 +446,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
439446
{
440447
fprintf(stderr, _("%s: could not read copy data: %s\n"),
441448
progname, PQerrorMessage(conn));
442-
return false;
449+
goto error;
443450
}
444451
if (copybuf[0] == 'k')
445452
{
@@ -451,21 +458,21 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
451458
{
452459
fprintf(stderr, _("%s: keepalive message is incorrect size: %d\n"),
453460
progname, r);
454-
return false;
461+
goto error;
455462
}
456463
continue;
457464
}
458465
else if (copybuf[0] != 'w')
459466
{
460467
fprintf(stderr, _("%s: unrecognized streaming header: \"%c\"\n"),
461468
progname, copybuf[0]);
462-
return false;
469+
goto error;
463470
}
464471
if (r < STREAMING_HEADER_SIZE + 1)
465472
{
466473
fprintf(stderr, _("%s: streaming header too small: %d\n"),
467474
progname, r);
468-
return false;
475+
goto error;
469476
}
470477

471478
/* Extract WAL location for this block */
@@ -483,7 +490,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
483490
{
484491
fprintf(stderr, _("%s: received xlog record for offset %u with no file open\n"),
485492
progname, xlogoff);
486-
return false;
493+
goto error;
487494
}
488495
}
489496
else
@@ -494,7 +501,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
494501
{
495502
fprintf(stderr, _("%s: got WAL data offset %08x, expected %08x\n"),
496503
progname, xlogoff, (int) lseek(walfile, 0, SEEK_CUR));
497-
return false;
504+
goto error;
498505
}
499506
}
500507

@@ -520,7 +527,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
520527
basedir, current_walfile_name);
521528
if (walfile == -1)
522529
/* Error logged by open_walfile */
523-
return false;
530+
goto error;
524531
}
525532

526533
if (write(walfile,
@@ -532,7 +539,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
532539
bytes_to_write,
533540
current_walfile_name,
534541
strerror(errno));
535-
return false;
542+
goto error;
536543
}
537544

538545
/* Write was successful, advance our position */
@@ -544,11 +551,10 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
544551
/* Did we reach the end of a WAL segment? */
545552
if (blockpos.xrecoff % XLOG_SEG_SIZE == 0)
546553
{
547-
if (!close_walfile(walfile, basedir, current_walfile_name, false))
554+
if (!close_walfile(basedir, current_walfile_name, false))
548555
/* Error message written in close_walfile() */
549-
return false;
556+
goto error;
550557

551-
walfile = -1;
552558
xlogoff = 0;
553559

554560
if (stream_stop != NULL)
@@ -577,8 +583,22 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
577583
{
578584
fprintf(stderr, _("%s: unexpected termination of replication stream: %s\n"),
579585
progname, PQresultErrorMessage(res));
580-
return false;
586+
goto error;
581587
}
582588
PQclear(res);
589+
590+
if (copybuf != NULL)
591+
PQfreemem(copybuf);
592+
if (walfile != -1 && close(walfile) != 0)
593+
fprintf(stderr, _("%s: could not close file %s: %s\n"),
594+
progname, current_walfile_name, strerror(errno));
583595
return true;
596+
597+
error:
598+
if (copybuf != NULL)
599+
PQfreemem(copybuf);
600+
if (walfile != -1 && close(walfile) != 0)
601+
fprintf(stderr, _("%s: could not close file %s: %s\n"),
602+
progname, current_walfile_name, strerror(errno));
603+
return false;
584604
}

src/bin/pg_basebackup/streamutil.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,17 @@ GetConnection(void)
143143

144144
tmpconn = PQconnectdbParams(keywords, values, true);
145145

146+
/*
147+
* If there is too little memory even to allocate the PGconn object
148+
* and PQconnectdbParams returns NULL, we call exit(1) directly.
149+
*/
150+
if (!tmpconn)
151+
{
152+
fprintf(stderr, _("%s: could not connect to server\n"),
153+
progname);
154+
exit(1);
155+
}
156+
146157
if (PQstatus(tmpconn) == CONNECTION_BAD &&
147158
PQconnectionNeedsPassword(tmpconn) &&
148159
dbgetpassword != -1)
@@ -154,8 +165,11 @@ GetConnection(void)
154165

155166
if (PQstatus(tmpconn) != CONNECTION_OK)
156167
{
157-
fprintf(stderr, _("%s: could not connect to server: %s"),
168+
fprintf(stderr, _("%s: could not connect to server: %s\n"),
158169
progname, PQerrorMessage(tmpconn));
170+
PQfinish(tmpconn);
171+
free(values);
172+
free(keywords);
159173
return NULL;
160174
}
161175

0 commit comments

Comments
 (0)