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

Re: [PATCHv2 02/10] pkt-line: drop safe_write function

From
Jeff King <peff@peff.net>
Date
Feb 18, 2013, 10:24 UTC
Message-ID
<20130218102430.GM5096@sigill.intra.peff.net>
In-Reply-To
<20130218095644.GA7049@elie.Belkin>
On Mon, Feb 18, 2013 at 01:56:45AM -0800, Jonathan Nieder wrote:
Show 10 quoted lines
> Jeff King wrote:
> 
> > This is just write_or_die by another name.
> >
> > Signed-off-by: Jeff King <peff@peff.net>
> > ---
> > Actually, they are not quite the same. write_or_die will exit(0) when it
> > sees EPIPE.
> 
> That information definitely belongs in the commit message.

Yeah, this one was more RFC; I was hoping for some input on the EPIPE thing, so I could know _what_ to put in the commit message. Is it safe, and if so, why? And if not, we should drop the patch.

Show 6 quoted lines
> If the connection to send-pack is lost and stdout becomes a broken
> pipe and I am updating enough refs to overflow the pipe buffer,
> receive-pack will die with SIGPIPE.  So unless the sadistic caller has
> set the inherited SIGPIPE action to SIG_IGN (for example by wrapping
> git with an uncautious Python wrapper that uses subprocess.Popen), the
> change to EPIPE handling is not a behavior change.

Yeah, but I don't want to count on always catching SIGPIPE. There's the inherited signal handler thing, but there's also the fact that we may end up ignoring SIGPIPE from backend programs like upload-pack and receive-pack; they check their writes anyway, and we have already run into issues with getting SIGPIPE when we don't necessarily expect or care about it.

The nice thing about write_or_die is that it still _exits_ on EPIPE. It's just that it doesn't print an error (which is really not a big deal) and exit with a 0 return code. I really wonder if we should just change the latter. For programs which are creating copious output (e.g., "git log"), the return value is not important anyway. For backend programs, an unexpected EPIPE from something like write_or_die should probably involve a non-successful return code.

> Arguably it would be more friendly to stay alive to run the
> post-receive and post-update hooks, though, given that a ref update
> has occurred.  Maybe transport commands like this one should always
> set the disposition of SIGPIPE to SIG_IGN.

Yeah, I've suggested that in the past. And I do think it's sane, because if you took a ref update, you almost certainly want to run the post-receive, even if the client is no longer around (e.g., if it is going to email out the changeset).

Show 15 quoted lines
> [...]
> > --- a/builtin/send-pack.c
> > +++ b/builtin/send-pack.c
> > @@ -79,7 +79,7 @@ static void print_helper_status(struct ref *ref)
> >  		}
> >  		strbuf_addch(&buf, '\n');
> >  
> > -		safe_write(1, buf.buf, buf.len);
> > +		write_or_die(1, buf.buf, buf.len);
> 
> A signal will kill send-pack before write_or_die has a chance to
> intervene so this change is a no-op unless the caller is sadistic
> (as in the [1] case).  In the signal(SIGPIPE, SIG_IGN) case, it might
> be a regression, since "git push" should not declare success when its
> connection to receive-pack closes early.

But that isn't going to receive-pack, is it? Send-pack's stdout is really just going to the user (or wherever). So it would have an effect more for:

  (git push && echo >&2 OK) | grep -m1 foo

which might print "OK" even if we failed. That's quite contrived, but it is at least a measurable change. And anyway...

Show 5 quoted lines
> In that case, if triggerable this looks like a bad change: if
> upload-pack has gone missing, the fetch should not be considered a
> success.
> [...]
> Etc.  I'm stopping here.
Yeah, there are definitely some bad ones.
Show 5 quoted lines
> I'm thinking before a patch like this we should make the following
> change:
> 
>  1. at startup, set the signal action of SIGPIPE to SIG_DFL, to make
>     the behavior a little more predictable.

I'm lukewarm on that, just because we may want to ignore SIGPIPE ourselves at some point.

Show 7 quoted lines
> Perhaps the following as well:
> 
>  2. in write_or_die(), when encountering EPIPE, set the signal action
>     of SIGPIPE to SIG_DFL and raise(SIGPIPE), ensuring the exit status
>     reflects the broken pipe.  If the parent process is unnecessarily
>     noisy about that, that's a bug in the parent process (hopefully
>     uncommon).

I like this. My suggestion would be to just exit(1) instead of exit(0). But really, raising SIGPIPE makes the most sense, because it communicates to the parent what happened (and the shell will wisely not print a message, but careful parents like "git fetch" and "git push" will check it properly and notice that the child did not succeed).

> Or alternatively:
> 
>  2b. never set SIGPIPE to SIG_IGN except in short blocks of code that
>      do not call write_or_die()
Yuck. :)
> What do you think?

I really like option 2. That exit(0) when we see SIGPIPE bugs me. Because we _are_ dying due to our write failing, and I think the only reason to exit(0) was to avoid unnecessary complaints from parents. But raising SIGPIPE seems like the best of both worlds to me.

-Peff
Previous: Jonathan NiederNext: Jeff King
Message 17 of 50 in “make smart-http more robust against bogus server input”
  1. 0/3 make smart-http more robust against bogus server inputJeff King, Feb 16, 2013
  2. 1/3 pkt-line: teach packet_get_line a no-op modeJeff King, Feb 16, 2013
  3. Jonathan NiederFeb 17, 2013
  4. 2/3 remote-curl: verify smart-http metadata linesJeff King, Feb 16, 2013
  5. Jonathan NiederFeb 17, 2013
  6. Jeff KingFeb 17, 2013
  7. Jonathan NiederFeb 18, 2013
  8. Jeff KingFeb 18, 2013
  9. 3/3 remote-curl: sanity check ref advertisement from serverJeff King, Feb 16, 2013
  10. Jonathan NiederFeb 17, 2013
  11. Jeff KingFeb 17, 2013
  12. Jonathan NiederFeb 18, 2013
  13. 0/10 pkt-line and remote-curl cleanups serverJeff King, Feb 18, 2013
  14. 01/10 pkt-line: move a misplaced commentJeff King, Feb 18, 2013
  15. 02/10 pkt-line: drop safe_write functionJeff King, Feb 18, 2013
  16. Jonathan NiederFeb 18, 2013
  17. Jeff KingFeb 18, 2013
  18. 03/10 pkt-line: clean up "gentle" reading functionJeff King, Feb 18, 2013
  19. Jonathan NiederFeb 18, 2013
  20. Jeff KingFeb 18, 2013
  21. 04/10 pkt-line: change error message for oversized packetJeff King, Feb 18, 2013
  22. Junio C HamanoFeb 18, 2013
  23. Jeff KingFeb 18, 2013
  24. Junio C HamanoFeb 18, 2013
  25. Jeff KingFeb 18, 2013
  26. Jeff KingFeb 20, 2013
  27. Junio C HamanoFeb 20, 2013
  28. Jonathan NiederFeb 18, 2013
  29. Jeff KingFeb 18, 2013
  30. 05/10 pkt-line: rename s/packet_read_line/packet_read/Jeff King, Feb 18, 2013
  31. Jonathan NiederFeb 18, 2013
  32. Jeff KingFeb 18, 2013
  33. Jonathan NiederFeb 18, 2013
  34. 06/10 pkt-line: share buffer/descriptor reading implementationJeff King, Feb 18, 2013
  35. Jonathan NiederFeb 18, 2013
  36. Jeff KingFeb 18, 2013
  37. Jonathan NiederFeb 18, 2013
  38. 07/10 teach get_remote_heads to read from a memory bufferJeff King, Feb 18, 2013
  39. 08/10 remote-curl: pass buffer straight to get_remote_headsJeff King, Feb 18, 2013
  40. Jonathan NiederFeb 18, 2013
  41. Junio C HamanoFeb 18, 2013
  42. Jeff KingFeb 18, 2013
  43. Junio C HamanoFeb 18, 2013
  44. Jeff KingFeb 18, 2013
  45. Shawn PearceFeb 20, 2013
  46. 09/10 remote-curl: move ref-parsing code up in fileJeff King, Feb 18, 2013
  47. 10/10 remote-curl: always parse incoming refsJeff King, Feb 18, 2013
  48. Jonathan NiederFeb 18, 2013
  49. Shawn PearceFeb 20, 2013
  50. Shawn PearceFeb 20, 2013

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.