diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2018-02-23 21:35:19 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2018-02-23 21:35:19 +0000 |
commit | 5dd8c40e5ee7a6f5e3acca5d38042a17760e0cde (patch) | |
tree | 14c7e96eaed3e14a3eef79313a4c7ca322639695 /read.c | |
parent | 9117e414d80f2ae174b6fdc21fd5e1376a10e30e (diff) | |
download | mandoc-5dd8c40e5ee7a6f5e3acca5d38042a17760e0cde.tar.gz mandoc-5dd8c40e5ee7a6f5e3acca5d38042a17760e0cde.tar.zst mandoc-5dd8c40e5ee7a6f5e3acca5d38042a17760e0cde.zip |
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 <vehk at vehk dot de> who also
provided an incomplete patch, part of which i'm using in this commit.
Diffstat (limited to 'read.c')
-rw-r--r-- | read.c | 39 |
1 files changed, 32 insertions, 7 deletions
@@ -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 <kristaps@bsd.lv> * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> @@ -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 |