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

Re: [PATCH 03/14] copy_fd: pass error message back through a strbuf

From
Jeff King <peff@peff.net>
Date
Dec 3, 2014, 21:00 UTC
Message-ID
<20141203210031.GA6631@peff.net>
In-Reply-To
<xmqqzjb4h823.fsf@gitster.dls.corp.google.com>
On Wed, Dec 03, 2014 at 11:01:08AM -0800, Junio C Hamano wrote:
Show 16 quoted lines
> Jonathan Nieder <jrnieder@gmail.com> writes:
> 
> > -extern int copy_fd(int ifd, int ofd);
> > +extern int copy_fd(int ifd, int ofd, struct strbuf *err);
> 
> It is not limited to this single function, but what contract do we
> envision this "error messages are given back to the caller via
> strbuf" convention should give between the callers and the callee?
> 
> For example, is it a bug in the callee to touch "err" when there is
> no error to report?  Another example is if we should allow the
> callers to pass NULL there when they do not care about the nature of
> the error (e.g. "git cmd -q").
> 
> There may be other rules we want to enforce consistently across
> functions that adopt this convention.

It seems like we are really re-designing the error-handling chain here. Maybe it is worth taking a step back and thinking about our overall strategy.

Why do we dislike errno? Because it is global state, and it is easy for it to get stomped by unrelated operations. Another reason is that it carries no parameters. You see "ENOENT", but you do not have any context (e.g., which file).

What's good about errno? It is machine-readable (i.e., callers can check for ENOENT, as opposed to text in a strbuf). It does not require any allocation. Besides making it slightly more robust, it removes any responsibility for resource cleanup from the caller. It's globalness is also convenient; you do not need to add an extra parameter to each function to handle errors.

So what are some alternatives?

Passing back "-errno" instead of "-1" helps with the stomping issue (and without adding extra parameters). It also retains machine-readability (which I'll call just readability from now on). But it doesn't help with context, or better messaging.

Your solution adds a strbuf. That helps with context and stomping, but loses readability and adds allocation.

If we changed the strbuf to a fixed-size buffer, that would help the allocation issue. Some messages might be truncated, but it seems unlikely in practice. It still loses readability, though.

What about a struct that has an errno-like value _and_ a fixed-size buffer? I'm thinking something like:

  struct error {
	int code;
	char msg[1024];
  };
  /* caller who wants to print the message; no need to free message */
  struct error err;
  if (copy_fd(from, to, &err))
	return error("%s", err.msg);
  /* caller who does not; they can pass NULL */
  if (copy_fd(from, to, NULL))
	return -1;
  /* or they can use it to grab the errno value */
  struct error err;
  if (copy_fd(from, to, &err)) {
	if (err.code == EPIPE)
		exit(141);
	return -1;
  }
  /* function which generates error */
  void read_foo(const char *fn, struct error *err)
  {
	if (open(fn, O_RDONLY))
		return mkerror(err, errno, "unable to open %s", fn);
	... do other stuff ...
	return 0;
  }
  /* helper function for generating errors */
  int mkerror(struct error *err, int code, const char *fmt, ...)
  {
	va_list ap;
	int len;
	if (!err)
		return;
	err->code = code;
	va_start(ap, fmt);
	len = vsnprintf(err->msg, sizeof(err->msg), fmt, ap);
	va_end(ap);
	if (code)
		snprintf(err->msg + len, sizeof(err->msg) - len,
			 ": %s", strerror(code));
	return -1;
  }
You can also take the machine-readable thing a step further, like:
  struct error {
	int code;
	char param1[1024];
	char param2[1024];
	/* 2 parameters should be big enough for anyone, right? */
  }

and then generate the message on the fly when printing. This gives the callers more information. But it also means defining a constant for "code" for every error message, which is annoying. Libraries often do this, but I do not think we need to go that far here.

-Peff
Previous: Jonathan NiederNext: Jonathan Nieder
Message 21 of 83 in “copy.c: make copy_fd preserve meaningful errno”
  1. copy.c: make copy_fd preserve meaningful errnoStefan Beller, Nov 17, 2014
  2. Junio C HamanoNov 17, 2014
  3. Stefan BellerNov 17, 2014
  4. Jonathan NiederNov 17, 2014
  5. Stefan BellerNov 18, 2014
  6. Jonathan NiederNov 18, 2014
  7. Stefan BellerNov 18, 2014
  8. 0/14 Re: copy.c: make copy_fd preserve meaningful errnoJonathan Nieder, Dec 3, 2014
  9. 01/14 strbuf: introduce strbuf_prefixf()Jonathan Nieder, Dec 3, 2014
  10. Eric SunshineDec 3, 2014
  11. Jonathan NiederDec 3, 2014
  12. Junio C HamanoDec 3, 2014
  13. Jonathan NiederDec 3, 2014
  14. Jonathan NiederDec 3, 2014
  15. Junio C HamanoDec 3, 2014
  16. 02/14 add_to_alternates_file: respect GIT_OBJECT_DIRECTORYJonathan Nieder, Dec 3, 2014
  17. Junio C HamanoDec 3, 2014
  18. 03/14 copy_fd: pass error message back through a strbufJonathan Nieder, Dec 3, 2014
  19. Junio C HamanoDec 3, 2014
  20. Jonathan NiederDec 3, 2014
  21. Jeff KingDec 3, 2014
  22. Jonathan NiederDec 3, 2014
  23. Jeff KingDec 4, 2014
  24. Stefan BellerDec 4, 2014
  25. Jeff KingDec 4, 2014
  26. Michael HaggertyDec 10, 2014
  27. Junio C HamanoDec 10, 2014
  28. Jeff KingDec 10, 2014
  29. doc: document error handling functions and conventions (Re: [PATCH 03/14] copy_fd: pass error message back through a strbuf)Jonathan Nieder, Dec 4, 2014
  30. Junio C HamanoDec 4, 2014
  31. Jonathan NiederDec 4, 2014
  32. Jonathan NiederDec 4, 2014
  33. Jeff KingDec 4, 2014
  34. Junio C HamanoDec 4, 2014
  35. Jeff KingDec 5, 2014
  36. Junio C HamanoDec 5, 2014
  37. Jeff KingDec 7, 2014
  38. Junio C HamanoDec 9, 2014
  39. Jeff KingDec 9, 2014
  40. Junio C HamanoFeb 12, 2015
  41. Michael HaggertyFeb 17, 2015
  42. Junio C HamanoFeb 17, 2015
  43. Jeff KingFeb 17, 2015
  44. Junio C HamanoFeb 17, 2015
  45. Junio C HamanoDec 3, 2014
  46. Jonathan NiederDec 3, 2014
  47. Junio C HamanoDec 3, 2014
  48. Jonathan NiederDec 3, 2014
  49. Stefan BellerDec 3, 2014
  50. 04/14 hold_lock_file_for_append: pass error message back through a strbufJonathan Nieder, Dec 3, 2014
  51. Torsten BögershausenDec 3, 2014
  52. Jonathan NiederDec 3, 2014
  53. 05/14 lock_packed_refs: pass error message back through a strbufJonathan Nieder, Dec 3, 2014
  54. 06/14 lockfile: introduce flag for locks outside .gitJonathan Nieder, Dec 3, 2014
  55. Junio C HamanoDec 3, 2014
  56. Jonathan NiederDec 3, 2014
  57. Junio C HamanoDec 3, 2014
  58. Jonathan NiederDec 3, 2014
  59. Junio C HamanoDec 3, 2014
  60. Jonathan NiederDec 3, 2014
  61. Junio C HamanoDec 3, 2014
  62. Jeff KingDec 3, 2014
  63. Junio C HamanoDec 4, 2014
  64. Jonathan NiederDec 4, 2014
  65. 07/14 fast-import: use message from lockfile API when writing marks failsJonathan Nieder, Dec 3, 2014
  66. 08/14 credentials: use message from lockfile API when locking ~/.git-credentials failsJonathan Nieder, Dec 3, 2014
  67. 09/14 config: use message from lockfile API when locking config file failsJonathan Nieder, Dec 3, 2014
  68. Junio C HamanoDec 3, 2014
  69. Jonathan NiederDec 3, 2014
  70. 10/14 rerere: error out on autoupdate failureJonathan Nieder, Dec 3, 2014
  71. 11/14 hold_locked_index: pass error message back through a strbufJonathan Nieder, Dec 3, 2014
  72. 12/14 hold_lock_file_for_update: pass error message back through a strbufJonathan Nieder, Dec 3, 2014
  73. Jonathan NiederDec 3, 2014
  74. 13/14 lockfile: remove unused function 'unable_to_lock_die'Jonathan Nieder, Dec 3, 2014
  75. 14/14 lockfile: make 'unable_to_lock_message' privateJonathan Nieder, Dec 3, 2014
  76. Stefan BellerDec 3, 2014
  77. Junio C HamanoNov 18, 2014
  78. Junio C HamanoNov 18, 2014
  79. Michael HaggertyNov 21, 2014
  80. Michael HaggertyNov 21, 2014
  81. Junio C HamanoNov 21, 2014
  82. Jeff KingNov 21, 2014
  83. Junio C HamanoNov 21, 2014

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.