From 5dd8c40e5ee7a6f5e3acca5d38042a17760e0cde Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Fri, 23 Feb 2018 21:35:19 +0000 Subject: After opening a file with gzdopen(3), we have to call gzclose(3) or we leak memory internally used by zlib to keep compression state. Bug reported by Wolfgang Mueller who also provided an incomplete patch, part of which i'm using in this commit. --- read.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'read.c') diff --git a/read.c b/read.c index f99451f9..9e230e23 100644 --- a/read.c +++ b/read.c @@ -1,4 +1,4 @@ -/* $Id: read.c,v 1.193 2017/11/10 23:32:40 schwarze Exp $ */ +/* $Id: read.c,v 1.194 2018/02/23 21:35:19 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2017 Ingo Schwarze @@ -556,6 +556,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd, gzFile gz; size_t off; ssize_t ssz; + int gzerrnum, retval; if (fstat(fd, &st) == -1) { mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, @@ -583,9 +584,22 @@ read_whole_file(struct mparse *curp, const char *file, int fd, } if (curp->gzip) { + /* + * Duplicating the file descriptor is required + * because we will have to call gzclose(3) + * to free memory used internally by zlib, + * but that will also close the file descriptor, + * which this function must not do. + */ + if ((fd = dup(fd)) == -1) { + mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, + "dup: %s", strerror(errno)); + return 0; + } if ((gz = gzdopen(fd, "rb")) == NULL) { mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "gzdopen: %s", strerror(errno)); + close(fd); return 0; } } else @@ -598,6 +612,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd, *with_mmap = 0; off = 0; + retval = 0; fb->sz = 0; fb->buf = NULL; for (;;) { @@ -614,19 +629,29 @@ read_whole_file(struct mparse *curp, const char *file, int fd, read(fd, fb->buf + (int)off, fb->sz - off); if (ssz == 0) { fb->sz = off; - return 1; + retval = 1; + break; } if (ssz == -1) { - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, - "read: %s", strerror(errno)); + if (curp->gzip) + (void)gzerror(gz, &gzerrnum); + mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "read: %s", + curp->gzip && gzerrnum != Z_ERRNO ? + zError(gzerrnum) : strerror(errno)); break; } off += (size_t)ssz; } - free(fb->buf); - fb->buf = NULL; - return 0; + if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK) + mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "gzclose: %s", + gzerrnum == Z_ERRNO ? strerror(errno) : + zError(gzerrnum)); + if (retval == 0) { + free(fb->buf); + fb->buf = NULL; + } + return retval; } static void -- cgit v1.2.3