Re: [PATCH] clean: use warning_errno() when appropriate

2017-02-13 Thread Junio C Hamano
Jeff King  writes:

> So in that sense doing the errno dance as close to the caller who cares
> is the most _obvious_ thing, even if it isn't the shortest.

Yup.

> It would be nice if there was a way to annotate a function as
> errno-safe, and then transitively compute which other functions were
> errno-safe when they do not call any errno-unsafe function. I don't know
> if any static analyzers allow that kind of custom annotation, though
> (and also I wonder whether the cost/benefit of maintaining those
> annotations would be worth it).

Double yup.


Re: [PATCH] clean: use warning_errno() when appropriate

2017-02-13 Thread Jeff King
On Mon, Feb 13, 2017 at 01:53:33PM -0800, Junio C Hamano wrote:

> Jeff King  writes:
> 
> > IOW, I think this may be a case where we should be optimizing for
> > programmer time (fewer lines of code, and one less thing to worry about
> > in the callers) versus squeezing out every instruction.
> 
> Fair enough.
> 
> Unless we do the save_errno dance in all the helper functions we
> commonly use to safely stash away errno as necessary and tell
> developers that they can depend on it, the code in the patch that
> began this discussion still needs its own saved_errno dance to be
> safe, though.  I do not have a feeling that we are not there yet,
> even after we teach xmalloc() and its family to do so.

Yeah, I certainly agree that is a potential blocker. Even if it is true
today, there's nothing guaranteeing that the quote functions don't grow
a new internal detail that violates.

So in that sense doing the errno dance as close to the caller who cares
is the most _obvious_ thing, even if it isn't the shortest.

It would be nice if there was a way to annotate a function as
errno-safe, and then transitively compute which other functions were
errno-safe when they do not call any errno-unsafe function. I don't know
if any static analyzers allow that kind of custom annotation, though
(and also I wonder whether the cost/benefit of maintaining those
annotations would be worth it).

-Peff


Re: [PATCH] clean: use warning_errno() when appropriate

2017-02-13 Thread Junio C Hamano
Jeff King  writes:

> IOW, I think this may be a case where we should be optimizing for
> programmer time (fewer lines of code, and one less thing to worry about
> in the callers) versus squeezing out every instruction.

Fair enough.

Unless we do the save_errno dance in all the helper functions we
commonly use to safely stash away errno as necessary and tell
developers that they can depend on it, the code in the patch that
began this discussion still needs its own saved_errno dance to be
safe, though.  I do not have a feeling that we are not there yet,
even after we teach xmalloc() and its family to do so.



Re: [PATCH] clean: use warning_errno() when appropriate

2017-02-13 Thread Jeff King
On Mon, Feb 13, 2017 at 12:38:47PM -0800, Junio C Hamano wrote:

> Jeff King  writes:
> 
> > I wonder if xmalloc() should be the one doing the saved_errno trick.
> > After all, it has only two outcomes: we successfully allocated the
> > memory, or we called die().
> 
> I would be lying if I said I did not considered it when I wrote the
> message you are responding to, but I rejected it because that would
> be optimizing for a wrong case, in that most callers of xmalloc()
> and friends do not do so in the error codepath, and we would be
> penalizing them by doing the saved_errno dance unconditionally.

Yes, that also occurred to me. I'm not sure if two integer swaps is
enough to care about when compared to the cost of a malloc(), though.

IOW, I think this may be a case where we should be optimizing for
programmer time (fewer lines of code, and one less thing to worry about
in the callers) versus squeezing out every instruction.

-Peff


Re: [PATCH] clean: use warning_errno() when appropriate

2017-02-13 Thread Junio C Hamano
Jeff King  writes:

> I wonder if xmalloc() should be the one doing the saved_errno trick.
> After all, it has only two outcomes: we successfully allocated the
> memory, or we called die().

I would be lying if I said I did not considered it when I wrote the
message you are responding to, but I rejected it because that would
be optimizing for a wrong case, in that most callers of xmalloc()
and friends do not do so in the error codepath, and we would be
penalizing them by doing the saved_errno dance unconditionally.



Re: [PATCH] clean: use warning_errno() when appropriate

2017-02-13 Thread Jeff King
On Mon, Feb 13, 2017 at 10:34:06AM -0800, Junio C Hamano wrote:

> Nguyễn Thái Ngọc Duy   writes:
> 
> > All these warning() calls are preceded by a system call. Report the
> > actual error to help the user understand why we fail to remove
> > something.
> 
> I think this patch is probably correct in the current code, but I
> say this only after following what quote_path_relative() and
> relative_path() that is called from it.  These warnings are preceded
> by a call to a system library function, but it is not apparent that
> they are immediately preceded without anything else that could have
> failed in between.
> 
> Side note.  There are many calls into strbuf API in these two
> functions.  Any calls to xmalloc() and friends made by strbuf
> functions may see ENOMEM from underlying malloc() and recover by
> releasing cached resources, by which time the original errno is
> unrecoverable.  So the above "probably correct" is not strictly
> true.
> 
> If we care deeply enough that we want to reliably show the errno we
> got from the preceding call to a system library function even after
> whatever comes in between, I think you'd need the usual saved_errno
> trick.  Is that worth it?---I do not offhand have an opinion.

I wonder if xmalloc() should be the one doing the saved_errno trick.
After all, it has only two outcomes: we successfully allocated the
memory, or we called die().

And that would transitively make most of the strbuf calls errno-safe
(except for obvious syscall-related ones like strbuf_read_file). And in
turn that makes quote_path_relative() pretty safe (at least when writing
to a strbuf).

-Peff


Re: [PATCH] clean: use warning_errno() when appropriate

2017-02-13 Thread Junio C Hamano
Nguyễn Thái Ngọc Duy   writes:

> All these warning() calls are preceded by a system call. Report the
> actual error to help the user understand why we fail to remove
> something.

I think this patch is probably correct in the current code, but I
say this only after following what quote_path_relative() and
relative_path() that is called from it.  These warnings are preceded
by a call to a system library function, but it is not apparent that
they are immediately preceded without anything else that could have
failed in between.

Side note.  There are many calls into strbuf API in these two
functions.  Any calls to xmalloc() and friends made by strbuf
functions may see ENOMEM from underlying malloc() and recover by
releasing cached resources, by which time the original errno is
unrecoverable.  So the above "probably correct" is not strictly
true.

If we care deeply enough that we want to reliably show the errno we
got from the preceding call to a system library function even after
whatever comes in between, I think you'd need the usual saved_errno
trick.  Is that worth it?---I do not offhand have an opinion.

> Signed-off-by: Nguyễn Thái Ngọc Duy 
> ---
>  builtin/clean.c | 8 
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/builtin/clean.c b/builtin/clean.c
> index d6bc3aaaea..dc1168747e 100644
> --- a/builtin/clean.c
> +++ b/builtin/clean.c
> @@ -175,7 +175,7 @@ static int remove_dirs(struct strbuf *path, const char 
> *prefix, int force_flag,
>   res = dry_run ? 0 : rmdir(path->buf);
>   if (res) {
>   quote_path_relative(path->buf, prefix, "ed);
> - warning(_(msg_warn_remove_failed), quoted.buf);
> + warning_errno(_(msg_warn_remove_failed), quoted.buf);
>   *dir_gone = 0;
>   }
>   return res;
> @@ -209,7 +209,7 @@ static int remove_dirs(struct strbuf *path, const char 
> *prefix, int force_flag,
>   string_list_append(&dels, quoted.buf);
>   } else {
>   quote_path_relative(path->buf, prefix, "ed);
> - warning(_(msg_warn_remove_failed), quoted.buf);
> + warning_errno(_(msg_warn_remove_failed), 
> quoted.buf);
>   *dir_gone = 0;
>   ret = 1;
>   }
> @@ -231,7 +231,7 @@ static int remove_dirs(struct strbuf *path, const char 
> *prefix, int force_flag,
>   *dir_gone = 1;
>   else {
>   quote_path_relative(path->buf, prefix, "ed);
> - warning(_(msg_warn_remove_failed), quoted.buf);
> + warning_errno(_(msg_warn_remove_failed), quoted.buf);
>   *dir_gone = 0;
>   ret = 1;
>   }
> @@ -982,7 +982,7 @@ int cmd_clean(int argc, const char **argv, const char 
> *prefix)
>   res = dry_run ? 0 : unlink(abs_path.buf);
>   if (res) {
>   qname = quote_path_relative(item->string, NULL, 
> &buf);
> - warning(_(msg_warn_remove_failed), qname);
> + warning_errno(_(msg_warn_remove_failed), qname);
>   errors++;
>   } else if (!quiet) {
>   qname = quote_path_relative(item->string, NULL, 
> &buf);