diff options
author | Jeff King <peff@peff.net> | 2013-03-25 16:21:14 -0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2013-03-27 13:47:02 -0700 |
commit | 692f0bc7ae0cb818bf3c757d509773d6f2e48c68 (patch) | |
tree | 51a874384de2956226f0e78bb61ae231a77fddb3 /streaming.c | |
parent | 42e7e2a53492ed1772b7b5d8b328f8d0a66f8b33 (diff) | |
download | git-692f0bc7ae0cb818bf3c757d509773d6f2e48c68.tar.gz |
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.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/streaming.c b/streaming.c index f4ab12ba42..cabcd9d157 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; |