From e5e477be58ff85c58b36af965ddea63c74926a06 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Wed, 11 Nov 2026 12:36:41 +0900 Subject: [PATCH v1] pg_receivewal: Fix resource leaks and error reporting during cleanup Failures while finalizing LZ4 compression or writing the final compressed data could leak a file descriptor and memory. Without --no-loop, repeated failures across reconnects could accumulate these resources. pg_receivewal skipped closing the file and releasing its associated resources on these failures. Ensure these resources are released while preserving the original error. Also fix a possible use-after-free when reporting a close failure. Backpatch to v15, where LZ4 support was added to pg_receivewal. --- src/bin/pg_basebackup/receivelog.c | 13 ++++++++++--- src/bin/pg_basebackup/walmethods.c | 9 ++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c index 77a2b4458b3..29034c217ab 100644 --- a/src/bin/pg_basebackup/receivelog.c +++ b/src/bin/pg_basebackup/receivelog.c @@ -691,9 +691,16 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream) } error: - if (walfile != NULL && stream->walmethod->ops->close(walfile, CLOSE_NO_RENAME) != 0) - pg_log_error("could not close file \"%s\": %s", - walfile->pathname, GetLastWalMethodError(stream->walmethod)); + if (walfile != NULL) + { + char walfile_name[MAXPGPATH]; + + /* The close method can free walfile even on failure. */ + strlcpy(walfile_name, walfile->pathname, sizeof(walfile_name)); + if (stream->walmethod->ops->close(walfile, CLOSE_NO_RENAME) != 0) + pg_log_error("could not close file \"%s\": %s", + walfile_name, GetLastWalMethodError(stream->walmethod)); + } walfile = NULL; return false; } diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c index 3a6b3b5f45b..90475b299ce 100644 --- a/src/bin/pg_basebackup/walmethods.c +++ b/src/bin/pg_basebackup/walmethods.c @@ -384,7 +384,7 @@ dir_write(Walfile *f, const void *buf, size_t count) static int dir_close(Walfile *f, WalCloseMethod method) { - int r; + int r = -1; DirectoryMethodFile *df = (DirectoryMethodFile *) f; DirectoryMethodData *dir_data = (DirectoryMethodData *) f->wwmethod; char tmppath[MAXPGPATH]; @@ -413,7 +413,8 @@ dir_close(Walfile *f, WalCloseMethod method) if (LZ4F_isError(compressed)) { f->wwmethod->lasterrstring = LZ4F_getErrorName(compressed); - return -1; + (void) close(df->fd); + goto cleanup; } errno = 0; @@ -421,7 +422,8 @@ dir_close(Walfile *f, WalCloseMethod method) { /* If write didn't set errno, assume problem is no disk space */ f->wwmethod->lasterrno = errno ? errno : ENOSPC; - return -1; + (void) close(df->fd); + goto cleanup; } r = close(df->fd); @@ -497,6 +499,7 @@ dir_close(Walfile *f, WalCloseMethod method) f->wwmethod->lasterrno = errno; #ifdef USE_LZ4 +cleanup: pg_free(df->lz4buf); /* supports free on NULL */ LZ4F_freeCompressionContext(df->ctx); -- 2.56.0