Re: Infinite loop in cascade_filter_fn()
From: Carlos Martín Nieto <hidden>
Date: 2016-06-15 22:52:31
Subsystem:
the rest · Maintainer:
Linus Torvalds
On Wed, Nov 23, 2011 at 06:40:47PM +0100, Henrik Grubbström wrote:
Hi. My git repository walker just got bitten by what seems to be a reasonably new bug in convert.c:cascade_filter_fn() (git 1.7.8.rc3 (gentoo)). How to reproduce: git clone git@github.com:pikelang/Pike.git git checkout -f 0e2080f838c6f0bc7d670ac7549676a353451dca^ git checkout -f 0e2080f838c6f0bc7d670ac7549676a353451dca The first two commands complete as expected, while the last hangs forever. Performing the same with git 1.7.6.4 works as expected. The problematic file seems to be /src/modules/_Crypto/rijndael_ecb_vt.txt which has the attributes: text ident eol=crlf
It looks like you won the lottery. The problem was that the output buffer only has one byte available when we see a LF. We check whether there is enough space (two bytes) to store CRLF in the output buffer, see that there isn't and return. cascade_filter_fn sees that the buffer hasn't been written fully and calls lf_to_crlf_filter_fn with the same output buffer, which we still can't fill, because it's too short. This patch fixes this, but I think it would still break if the LF is at the end of the file. Changing the `if (!input)` to put the LF in the output buffer may or may not be the right soulution. I feel like this should be handled by cascade_filter_fn rather than the actual filter somehow, but Junio's comment (4ae66704 'stream filter: add "no more input" to the filters') suggests otherwise. I'm working on a cleaner patch that takes care of a bit of state, but this is the general idea. cmn
--- 8< ---Subject: [PATCH] convert: don't loop indefintely if at LF-to-CRLF streaming If we find a LF when the output buffer is only has one byte remaining, cascade_filter_fn won't notice that we need more input and won't drain the output buffer. In such a case, store whether we've outputted the CR so we can retake it from there. Signed-off-by: Carlos Martín Nieto <redacted> --- convert.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/convert.c b/convert.c
index 86e9c29..4218f40 100644
--- a/convert.c
+++ b/convert.c@@ -881,6 +881,7 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter, char *output, size_t *osize_p) { size_t count; + static int put_cr = 0; if (!input) return 0; /* we do not keep any states */
@@ -890,10 +891,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter, for (i = o = 0; o < *osize_p && i < count; i++) { char ch = input[i]; if (ch == '\n') { - if (o + 1 < *osize_p) + if (put_cr) { + put_cr = 0; + } else { output[o++] = '\r'; - else - break; + put_cr = 1; + i--; + continue; + } } output[o++] = ch; }
--
1.7.8.rc3.31.g017d1
Attachments
- signature.asc [application/pgp-signature] 490 bytes