On Fri, Nov 04 2022, Phillip Wood via GitGitGadget wrote: > From: Phillip Wood <phillip.wood@xxxxxxxxxxxxx> > +static const char *sequencer_reflog_action(struct replay_opts *opts) > +{ > + if (!opts->reflog_action) { > + opts->reflog_action = getenv(GIT_REFLOG_ACTION); > + opts->reflog_action = > + xstrdup(opts->reflog_action ? opts->reflog_action > + : action_name(opts)); > + } > + > + return opts->reflog_action; > +} We always return an xstrdup'd here, so this should be a "char *" return value, not a "const char *"., but > __attribute__((format (printf, 3, 4))) > static const char *reflog_message(struct replay_opts *opts, > const char *sub_action, const char *fmt, ...) > { > va_list ap; > static struct strbuf buf = STRBUF_INIT; > - char *reflog_action = getenv(GIT_REFLOG_ACTION); > > va_start(ap, fmt); > strbuf_reset(&buf); Here we just reset the strbuf... > - strbuf_addstr(&buf, reflog_action ? reflog_action : action_name(opts)); > + strbuf_addstr(&buf, sequencer_reflog_action(opts)); Here we leak the freshly xstrdup'd value, mostly untested, but shouldn't this instead be: diff --git a/sequencer.c b/sequencer.c index e23f6f0b718..58a97e04c67 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3695,10 +3695,11 @@ static const char *reflog_message(struct replay_opts *opts, { va_list ap; static struct strbuf buf = STRBUF_INIT; + char *msg = sequencer_reflog_action(opts); va_start(ap, fmt); strbuf_reset(&buf); - strbuf_addstr(&buf, sequencer_reflog_action(opts)); + strbuf_attach(&buf, msg, strlen(msg), strlen(msg) + 1); if (sub_action) strbuf_addf(&buf, " (%s)", sub_action); if (fmt) { Of course that requires dropping the "const", per the above... > if (sub_action) > strbuf_addf(&buf, " (%s)", sub_action); > if (fmt) { > @@ -4497,7 +4511,7 @@ static int checkout_onto(struct repository *r, struct replay_opts *opts, > RESET_HEAD_RUN_POST_CHECKOUT_HOOK, > .head_msg = reflog_message(opts, "start", "checkout %s", > onto_name), > - .default_reflog_action = "rebase" > + .default_reflog_action = sequencer_reflog_action(opts) Here we'd before hand a fixed string to reset_head(), but now it's xstrdup()'d, but the corresponding free() on that side is missing. But aren't we always just returing "rebase" here still? > [...] > @@ -5116,7 +5121,7 @@ static int single_pick(struct repository *r, > TODO_PICK : TODO_REVERT; > item.commit = cmit; > > - setenv(GIT_REFLOG_ACTION, action_name(opts), 0); > + opts->reflog_message = sequencer_reflog_action(opts); > return do_pick_commit(r, &item, opts, 0, &check_todo); Here you're adding a new memory leak, which you can see if you run e.g. the 1st test of ./t1013-read-tree-submodule.sh before & after this change.