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 <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
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