git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v4] Refactor recv_sideband()

From
Junio C Hamano <gitster@pobox.com>
Date
Jun 28, 2016, 21:09 UTC
Message-ID
<xmqqwpl96mvv.fsf@gitster.mtv.corp.google.com>
In-Reply-To
<alpine.LFD.2.20.1606281629280.24439@knanqh.ubzr>
Nicolas Pitre <nico@fluxnic.net> writes:
Show 46 quoted lines
>> There is something else going on.  I cannot quite explain why I am
>> getting this failure from t5401-update-hooks.sh, for example:
>> 
>>     --- expect      2016-06-28 19:46:24.564937075 +0000
>>     +++ actual      2016-06-28 19:46:24.564937075 +0000
>>     @@ -9,3 +9,4 @@
>>      remote: STDERR post-receive
>>      remote: STDOUT post-update
>>      remote: STDERR post-update
>>     +remote: To ./victim.git
>>     not ok 12 - send-pack stderr contains hook messages
>> 
>> ... goes and looks what v2.9.0 produces, which ends like this:
>> 
>>     ...
>>     remote: STDERR post-receive        
>>     remote: STDOUT post-update        
>>     remote: STDERR post-update        
>>     To ./victim.git
>>        e4822ab..2b65bd1  master -> master
>>      ! [remote rejected] tofail -> tofail (hook declined)
>> 
>> The test checks if lines prefixed with "remote: " match the expected
>> output, and the difference is an indication that the new code is
>> showing an extra incomplete-line "remote: " before other parts of
>> the code says "To ./victim.git" to report where the push is going.
>
> Ah...  I think I know what's going on.
>
> The leftover data in the strbuf is normally (when there is no errors) an 
> unterminated line. So instead of doing:
>
> -                       fprintf(stderr, "%s: protocol error: no band designator\n", me);
> +                       strbuf_addf(&outbuf,
> +                                   "\n%s: protocol error: no band designator\n",
> +                                   me);
>
> you could omit the final \n in the format string and:
>
> -       if (outbuf.len > 0)
> -               fprintf(stderr, "%.*s", (int)outbuf.len, outbuf.buf);
> +       if (outbuf.len)
> +               fwrite(outbuf.buf, 1, outbuf.len, stderr);
>         strbuf_release(&outbuf);
>
> and here a \n could be added before writing out the buffer.
Unfortunately, that is not it.

The basic structure of the code (without the "SQUASH" we discussed) looks like this:

	strbuf_addf(&outbuf, "%s", PREFIX);
	while (retval == 0) {
		len = packet_read(in_stream, NULL, NULL, buf, LARGE_PACKET_MAX, 0);
		...
		band = buf[0] & 0xff;
		switch (band) {
		case 3:
			... /* emergency exit */
		case 2:
			while ((brk = strpbrk(b, "\n\r"))) {
				int linelen = brk - b;
				if (linelen > 0) {
					strbuf_addf(&outbuf, "%.*s%s%c",
						    linelen, b, suffix, *brk);
				} else {
					strbuf_addf(&outbuf, "%c", *brk);
				}
				fprintf(stderr, "%.*s", (int)outbuf.len,
					outbuf.buf);
				strbuf_reset(&outbuf);
				strbuf_addf(&outbuf, "%s", PREFIX);
				b = brk + 1;
			}
			if (*b)
				strbuf_addf(&outbuf, "%s", b);
			break;
		...
		}
	}
	if (outbuf.len > 0)
		fprintf(stderr, "%.*s", (int)outbuf.len, outbuf.buf);

Imagine we are reading from band #2 and we find a complete line. We concatenate the payload up to the LF at the end of the line to the PREFIX we prepared outside the loop and emit it, and then we ASSUME that we further have something after strpbrk() and add PREFIX to the buffer, before going to the next line in the payload.

But there may not be anything after the LF. outbuf.len is still counting the PREFIX and we end up showing it, without termination.

This takes us back to what I said in my review of an earlier round, in $gmane/297332, where I said:

    Instead of doing "we assume outbuf already has PREFIX when we add
    contents from buf[]", the code structure would be better if you:
     * make outbuf.buf contain PREFIX at the beginning of this innermost
       loop; lose the reset/addf from here.
     * move strbuf_reset(&outbuf) at the end of the next if (*b) block
       to just before "continue;"
    perhaps?

I think the strbuf_addf(PREFIX) above the loop should be removed, and instead the code should use the PREFIX only when it decides that there is something worth emitting, i.e.

	while (!retval) {
        	len = packet_read();
                ...
                band = buf[0] & 0xff;
                switch (band) {
                case 3:
                	... /* emergency exit */
		case 2:
                	while ((brk = ...)) {
                        	/* we have something to say */
				strbuf_reset(&outbuf);
                                strbuf_addstr(&outbuf, PREFIX);
                                if (linelen)
                                	strbuf_addf(...);
				else
                                	strbuf_addch(*brk);
				fwrite(outbuf.buf, 1, outbuf.len, stderr);
				b = brk + 1;
			}
                        if (*b) {
                        	/* we still have something to say */
				strbuf_reset(&outbuf);
                                strbuf_addstr(&outbuf, PREFIX);
                               	strbuf_addf(...);
			}
                        break;
		...
                }
	}
Previous: Nicolas PitreNext: Nicolas Pitre
Message 41 of 60 in “Refactor recv_sideband()”
  1. Refactor recv_sideband()Lukas Fleischer, Jun 13, 2016
  2. Nicolas PitreJun 13, 2016
  3. Johannes SchindelinJun 14, 2016
  4. Nicolas PitreJun 14, 2016
  5. Johannes SchindelinJun 14, 2016
  6. Nicolas PitreJun 14, 2016
  7. Refactor recv_sideband()Lukas Fleischer, Jun 14, 2016
  8. Lukas FleischerJun 14, 2016
  9. Junio C HamanoJun 14, 2016
  10. Jeff KingJun 15, 2016
  11. Jeff KingJun 24, 2016
  12. Johannes SchindelinJun 24, 2016
  13. Jeff KingJun 24, 2016
  14. Junio C HamanoJun 24, 2016
  15. Lukas FleischerJun 27, 2016
  16. Junio C HamanoJun 27, 2016
  17. Jeff KingJun 27, 2016
  18. Junio C HamanoJun 27, 2016
  19. Lukas FleischerJun 27, 2016
  20. Nicolas PitreJun 27, 2016
  21. Lukas FleischerJun 28, 2016
  22. Junio C HamanoJun 28, 2016
  23. Johannes SchindelinJun 28, 2016
  24. Johannes SchindelinJun 28, 2016
  25. Junio C HamanoJun 28, 2016
  26. Johannes SchindelinJun 28, 2016
  27. Dennis KaarsemakerJun 24, 2016
  28. Refactor recv_sideband()Lukas Fleischer, Jun 22, 2016
  29. Nicolas PitreJun 22, 2016
  30. Nicolas PitreJun 22, 2016
  31. Lukas FleischerJun 23, 2016
  32. Nicolas PitreJun 23, 2016
  33. Refactor recv_sideband()Lukas Fleischer, Jun 28, 2016
  34. Junio C HamanoJun 28, 2016
  35. Junio C HamanoJun 28, 2016
  36. Nicolas PitreJun 28, 2016
  37. Junio C HamanoJun 28, 2016
  38. Nicolas PitreJun 28, 2016
  39. Junio C HamanoJun 28, 2016
  40. Nicolas PitreJun 28, 2016
  41. Junio C HamanoJun 28, 2016
  42. Nicolas PitreJun 28, 2016
  43. Junio C HamanoJun 28, 2016
  44. Junio C HamanoJun 28, 2016
  45. Junio C HamanoJun 29, 2016
  46. Nicolas PitreJun 29, 2016
  47. Nicolas PitreJun 29, 2016
  48. Junio C HamanoJun 29, 2016
  49. Lukas FleischerJun 30, 2016
  50. Junio C HamanoJul 1, 2016
  51. Nicolas PitreJul 5, 2016
  52. Junio C HamanoJul 6, 2016
  53. Nicolas PitreJul 7, 2016
  54. Nicolas PitreJun 14, 2016
  55. Nicolas PitreJun 14, 2016
  56. Junio C HamanoJun 14, 2016
  57. Lukas FleischerJun 14, 2016
  58. Junio C HamanoJun 14, 2016
  59. Nicolas PitreJun 14, 2016
  60. Lukas FleischerJun 19, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.