summaryrefslogtreecommitdiff
path: root/streaming.c
diff options
context:
space:
mode:
authorJeff King <peff@peff.net>2013-03-25 20:21:14 (GMT)
committerJunio C Hamano <gitster@pobox.com>2013-03-27 20:47:02 (GMT)
commit692f0bc7ae0cb818bf3c757d509773d6f2e48c68 (patch)
tree51a874384de2956226f0e78bb61ae231a77fddb3 /streaming.c
parent42e7e2a53492ed1772b7b5d8b328f8d0a66f8b33 (diff)
downloadgit-692f0bc7ae0cb818bf3c757d509773d6f2e48c68.zip
git-692f0bc7ae0cb818bf3c757d509773d6f2e48c68.tar.gz
git-692f0bc7ae0cb818bf3c757d509773d6f2e48c68.tar.bz2
avoid infinite loop in read_istream_loose
The read_istream_loose function loops on inflating a chunk of data from an mmap'd loose object. We end the loop when we run out of space in our output buffer, or if we see a zlib error. We need to treat Z_BUF_ERROR specially, though, as it is not fatal; it is just zlib's way of telling us that we need to either feed it more input or give it more output space. It is perfectly normal for us to hit this when we are at the end of our buffer. However, we may also get Z_BUF_ERROR because we have run out of input. In a well-formed object, this should not happen, because we have fed the whole mmap'd contents to zlib. But if the object is truncated or corrupt, we will loop forever, never giving zlib any more data, but continuing to ask it to inflate. We can fix this by considering it an error when zlib returns Z_BUF_ERROR but we still have output space left (which means it must want more input, which we know is a truncation error). It would not be sufficient to just check whether zlib had consumed all the input at the start of the loop, as it might still want to generate output from what is in its internal state. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'streaming.c')
-rw-r--r--streaming.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/streaming.c b/streaming.c
index f4ab12b..cabcd9d 100644
--- a/streaming.c
+++ b/streaming.c
@@ -309,7 +309,7 @@ static read_method_decl(loose)
st->z_state = z_done;
break;
}
- if (status != Z_OK && status != Z_BUF_ERROR) {
+ if (status != Z_OK && (status != Z_BUF_ERROR || total_read < sz)) {
git_inflate_end(&st->z);
st->z_state = z_error;
return -1;