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@xxxxxxxxxx: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 <cmn@xxxxxxxx> --- 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
Attachment:
signature.asc
Description: Digital signature