Re: Infinite loop in cascade_filter_fn()
- From
Carlos Martín Nieto <cmn@elego.de>
- Date
- Nov 25, 2011, 15:38 UTC
- Message-ID
- <20111125153829.GB10417@beez.lab.cmartin.tk>
- In-Reply-To
- <Pine.GSO.4.63.1111231801580.5099@shipon.roxen.com>
On Wed, Nov 23, 2011 at 06:40:47PM +0100, Henrik Grubbström wrote:
Show 20 quoted lines
> 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 <cmn@elego.de> --- 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