Re: [PATCH v2] t5411: consistent result for proc-receive broken test

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Nov 09, 2020 at 12:59:24PM -0800, Junio C Hamano wrote:

> > @@ -1196,11 +1197,12 @@ static int run_proc_receive_hook(struct command *commands,
> >  		packet_flush(proc.in);
> >  	}
> >  
> > +	close(proc.in);
> > +
> >  	/* Read result from proc-receive */
> >  	code = read_proc_receive_report(&reader, commands, &errmsg);
> >  
> >  cleanup:
> > -	close(proc.in);
> >  	close(proc.out);
> >  	if (use_sideband)
> >  		finish_async(&muxer);
> 
> OK, without us closing our end, the hook cannot even tell that it
> read to the end of our input.

That doesn't seem right. It should be expecting our flush packet,
shouldn't it? And if it sees an EOF before the flush packet, that would
be an error from the hook's perspective.

This part of the patch seems like a red herring to me.

> > @@ -52,8 +53,10 @@ static void proc_receive_verison(struct packet_reader *reader) {
> >  		}
> >  	}
> >  
> > -	if (server_version != 1 || die_version)
> > +	if (server_version != 1)
> >  		die("bad protocol version: %d", server_version);
> > +	if (die_version)
> > +		die("die with the --die-version option");
> 
> If any of these trigger, wouldn't we end up dying without consuming
> what receive-pack said?

Yeah, I think they would have the same race that the commit message
describes (proc-receive hook writes to stderr and dies, receive-pack
gets an error writing to now-closed hook pipe and never relays the
stderr).

But it seems like fixing this in the hook is the wrong place. The hook
has failed and has nothing else to say. Adding a pump-the-stdin-to-eof
loop to every die() is a lot of effort. Not to mention that the hook
could fail for reasons outside its usual flow control (e.g., segfault,
oom, etc, and receive-pack should be able to handle that gracefully,
even if the hook doesn't appear to behave.

I.e., I think the bug is in receive-pack's run_proc_receive_hook(). It
cleverly ignores SIGPIPE exactly to avoid dying during the write phase,
but then it proceeds to call packet_write_fmt(), etc, that will die on
any error (going to extra effort to emulate sigpipe, no less!). So we
die and take our sideband muxer with us.

So instead of this hunk:

> > @@ -79,9 +82,15 @@ static void proc_receive_read_commands(struct packet_reader *reader,
> >  		    *p++ != ' ' ||
> >  		    parse_oid_hex(p, &new_oid, &p) ||
> >  		    *p++ != ' ' ||
> > -		    die_readline)
> > +		    die_readline) {
> > +			char *bad_line = xstrdup(reader->line);
> > +			while (packet_reader_read(reader) != PACKET_READ_EOF)
> > +				; /* do nothing */
> > +			if (die_readline)
> > +				die("die with the --die-readline option");
> >  			die("protocol error: expected 'old new ref', got '%s'",
> > -			    reader->line);
> > +			    bad_line);
> > +		}
> 
> This part is different from the previous one in that it slurps all
> the input before dying evein in die_readline case.

I think the patch really ought to be in receive-pack, converting
packet_write_fmt() and packet_flush() into their "gently" forms.

And when we see a write error, close our pipe to the hook, set errmsg to
"hook failed to run" or similar, and then jump to the "cleanup" label,
where we'll wait on our sideband muxer to finish (which in turn will
wait pump any remaining data out of the hook's stderr).

Optionally we can pump the hook stdout to see if it gave us a better
message, but I think if write() failed, then all bets are off. The hook
broke protocol; a well-behaved hook that wanted to pass along a specific
per-ref message to the user would actually read all the input and then
report on each ref).

-Peff



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux