From: Phillip Wood Date: Mon, 07 Nov 2022 19:35:22 GMT Subject: Re: [PATCH 1/2] sequencer: stop exporting GIT_REFLOG_ACTION Message-ID: <03cd4cdb-5f6b-11b9-1959-d58d5b544565@dunelm.org.uk> In-Reply-To: <221107.86iljqvhzf.gmgdl@evledraar.gmail.com> Hi Ævar On 07/11/2022 16:12, Ævar Arnfjörð Bjarmason wrote: > > On Fri, Nov 04 2022, Phillip Wood via GitGitGadget wrote: > >> From: Phillip Wood > >> +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 We always return the same string, it is only allocated on the first call. opt->reflog_action is freed at the end of the rebase in sequencer_remove_state(). >> __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? Yes but I think it makes sense to call squencer_reflog_action() in case this changes in the future. Note I don't think this is leaking anything. >> [...] >> @@ -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. I'm not sure how, opts->reflog_message will be a copy of opts->reflog_action which is freed at the end of the rebase. I'll have a proper look tomorrow to see if I'm missing something. Best Wishes Phillip