Subject: Re: Bug Report: Multi-line trailers containing empty lines break parsing

From: Junio C Hamano <[email-masked]>
Date: Tue, 16 Feb 2021 11:39:00 -0800

Taylor Blau <[email-masked]> writes:

> Anyway, I'm pretty sure the problem is that
> trailer.c:find_trailer_start() doesn't disambiguate between a blank line
> and one that contains only space characters.

I saw that while reviewing another topic the other day and found it
a bit strange, but kept it as I thought it was deliberate and the
behaviour (i.e. a line with only blanks and a line that is empty are
treated the same) was protected with some tests, but looking at your
patch below, I guess there is no such test.

> When it encounters a blank line, find_trailer_start() assumes that the
> trailers must begin on the line following the one it's looking at. But
> this isn't the case if the line is a non-empty continuation, in which
> the line may be part of a trailer.
>
> Fix this by only considering a blank line which has exactly zero space
> characters before the LF as delimiting the start of trailers.

Hmph...

> +test_expect_success 'handling of empty continuations lines' '
> +	tr _ " " >input <<-\EOF &&
> +	subject
> +
> +	body
> +
> +	trailer: single
> +	multi: one
> +	_two
> +	multi: one
> +	_
> +	_two
> +	_three
> +	EOF
> +	cat >expect <<-\EOF &&
> +	trailer: single
> +	multi: one two
> +	multi: one two three
> +	EOF
> +	git interpret-trailers --parse <input >actual &&
> +	test_cmp expect actual
> +'

A few comments (not pointing out bugs, but just sharing
observations).

 - if the line before "trailer: single" were not an empty line but a
   line with a single SP on it (which is is_blank_line()), would the
   new logic get confused?

 - if the second "multi:" trailer did not have the funny blank line
   before "_two", the expected output would still be "multi:"
   followed by "one two three", iow, the line after the second
   "multi: one" is a total no-op?  If we added many more " \n" lines
   there, they are all absorbed and ignored?  It somehow feels wrong

> diff --git a/trailer.c b/trailer.c
> index 249ed618ed..7ca7200aec 100644
> --- a/trailer.c
> +++ b/trailer.c
> @@ -846,7 +846,7 @@ static size_t find_trailer_start(const char *buf, size_t len)
>  			possible_continuation_lines = 0;
>  			continue;
>  		}
> -		if (is_blank_line(bol)) {
> +		if (is_blank_line(bol) && *bol == '\n') {
>  			if (only_spaces)
>  				continue;
>  			non_trailer_lines += possible_continuation_lines;
> --
> 2.30.0.667.g81c0cbc6fd