aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/read.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2018-02-23 21:35:19 +0000
committerIngo Schwarze <schwarze@openbsd.org>2018-02-23 21:35:19 +0000
commit5dd8c40e5ee7a6f5e3acca5d38042a17760e0cde (patch)
tree14c7e96eaed3e14a3eef79313a4c7ca322639695 /read.c
parent9117e414d80f2ae174b6fdc21fd5e1376a10e30e (diff)
downloadmandoc-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.c39
1 files changed, 32 insertions, 7 deletions
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 <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