On Tue, Jul 31, 2018 at 7:15 AM Phillip Wood <phillip.wood@xxxxxxxxxxxx> wrote: > The calling code treated NULL as a valid return value, so fix this by > returning and integer and passing in a parameter to receive the author. It might be difficult for future readers (those who didn't follow the discussion) to understand how/why NULL is not sufficient to signal an error. Perhaps incorporating the explanation from your email[1] which discussed that the author name, email, and/or date might change unexpectedly would be sufficient. This excerpt from [1] might be a good starting point: ... the caller does not treat NULL as an error, so this will change the date and potentially the author of the commit ... [which] does corrupt the author data compared to its expected value. [1]: https://public-inbox.org/git/c80cf729-1bbe-10f5-6837-b074d371b91c@xxxxxxxxxxxx/ > Signed-off-by: Phillip Wood <phillip.wood@xxxxxxxxxxxxx> > --- > diff --git a/sequencer.c b/sequencer.c > @@ -701,57 +701,58 @@ static char *get_author(const char *message) > -static const char *read_author_ident(struct strbuf *buf) > +static int read_author_ident(char **author) So, the caller is now responsible for freeing the string placed in 'author'. Okay. > { > - if (strbuf_read_file(buf, rebase_path_author_script(), 256) <= 0) > - return NULL; > + if (strbuf_read_file(&buf, rebase_path_author_script(), 256) <= 0) > + return -1; I think you need to strbuf_release(&buf) in this error path since strbuf_read_file() doesn't guarantee that the strbuf hasn't been partially populated when it returns an error. (That is, this is leaking.) > /* dequote values and construct ident line in-place */ Ugh, this comment should have been adjusted in my series. A minor matter, though, which can be tweaked later. > /* validate date since fmt_ident() will die() on bad value */ > if (parse_date(val[2], &out)){ > - warning(_("invalid date format '%s' in '%s'"), > + error(_("invalid date format '%s' in '%s'"), > val[2], rebase_path_author_script()); > strbuf_release(&out); > - return NULL; > + strbuf_release(&buf); > + return -1; You were careful to print the error, which references a value from 'buf', before destroying 'buf'. Good. (A simplifying alternative would have been to not print the actual value and instead say generally that "the date" was bad. Not a big deal.) > } > - strbuf_swap(buf, &out); > - strbuf_release(&out); > - return buf->buf; > + *author = strbuf_detach(&out, NULL); And, 'author' is only assigned when 0 is returned, so the caller only has to free(author) upon success. Fine. > + strbuf_release(&buf); > + return 0; > } > > static const char staged_changes_advice[] = > @@ -794,12 +795,14 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, > - struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT; > - const char *author = is_rebase_i(opts) ? > - read_author_ident(&script) : NULL; > + struct strbuf msg = STRBUF_INIT; > + char *author = NULL; > struct object_id root_commit, *cache_tree_oid; > int res = 0; > > + if (is_rebase_i(opts) && read_author_ident(&author)) > + return -1; Logic looks correct, and it's nice to see that you went with 'return -1' rather than die(), especially since the caller of run_git_commit() is already able to handle -1.