Skip to content

Commit 1e5c160

Browse files
pks-tgitster
authored andcommitted
sequencer: fix leaking string buffer in commit_staged_changes()
We're leaking the `rev` string buffer in various call paths. Refactor the function to have a common exit path so that we can release its memory reliably. This fixes a subset of tests failing with the memory sanitizer in t3404. But as there are more failures, we cannot yet mark the whole test suite as passing. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 63c9bd3 commit 1e5c160

File tree

1 file changed

+73
-38
lines changed

1 file changed

+73
-38
lines changed

sequencer.c

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5146,33 +5146,47 @@ static int commit_staged_changes(struct repository *r,
51465146
struct replay_ctx *ctx = opts->ctx;
51475147
unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
51485148
unsigned int final_fixup = 0, is_clean;
5149+
struct strbuf rev = STRBUF_INIT;
5150+
int ret;
51495151

5150-
if (has_unstaged_changes(r, 1))
5151-
return error(_("cannot rebase: You have unstaged changes."));
5152+
if (has_unstaged_changes(r, 1)) {
5153+
ret = error(_("cannot rebase: You have unstaged changes."));
5154+
goto out;
5155+
}
51525156

51535157
is_clean = !has_uncommitted_changes(r, 0);
51545158

51555159
if (!is_clean && !file_exists(rebase_path_message())) {
51565160
const char *gpg_opt = gpg_sign_opt_quoted(opts);
5157-
5158-
return error(_(staged_changes_advice), gpg_opt, gpg_opt);
5161+
ret = error(_(staged_changes_advice), gpg_opt, gpg_opt);
5162+
goto out;
51595163
}
5164+
51605165
if (file_exists(rebase_path_amend())) {
5161-
struct strbuf rev = STRBUF_INIT;
51625166
struct object_id head, to_amend;
51635167

5164-
if (repo_get_oid(r, "HEAD", &head))
5165-
return error(_("cannot amend non-existing commit"));
5166-
if (!read_oneliner(&rev, rebase_path_amend(), 0))
5167-
return error(_("invalid file: '%s'"), rebase_path_amend());
5168-
if (get_oid_hex(rev.buf, &to_amend))
5169-
return error(_("invalid contents: '%s'"),
5170-
rebase_path_amend());
5171-
if (!is_clean && !oideq(&head, &to_amend))
5172-
return error(_("\nYou have uncommitted changes in your "
5173-
"working tree. Please, commit them\n"
5174-
"first and then run 'git rebase "
5175-
"--continue' again."));
5168+
if (repo_get_oid(r, "HEAD", &head)) {
5169+
ret = error(_("cannot amend non-existing commit"));
5170+
goto out;
5171+
}
5172+
5173+
if (!read_oneliner(&rev, rebase_path_amend(), 0)) {
5174+
ret = error(_("invalid file: '%s'"), rebase_path_amend());
5175+
goto out;
5176+
}
5177+
5178+
if (get_oid_hex(rev.buf, &to_amend)) {
5179+
ret = error(_("invalid contents: '%s'"),
5180+
rebase_path_amend());
5181+
goto out;
5182+
}
5183+
if (!is_clean && !oideq(&head, &to_amend)) {
5184+
ret = error(_("\nYou have uncommitted changes in your "
5185+
"working tree. Please, commit them\n"
5186+
"first and then run 'git rebase "
5187+
"--continue' again."));
5188+
goto out;
5189+
}
51765190
/*
51775191
* When skipping a failed fixup/squash, we need to edit the
51785192
* commit message, the current fixup list and count, and if it
@@ -5204,9 +5218,11 @@ static int commit_staged_changes(struct repository *r,
52045218
len--;
52055219
strbuf_setlen(&ctx->current_fixups, len);
52065220
if (write_message(p, len, rebase_path_current_fixups(),
5207-
0) < 0)
5208-
return error(_("could not write file: '%s'"),
5209-
rebase_path_current_fixups());
5221+
0) < 0) {
5222+
ret = error(_("could not write file: '%s'"),
5223+
rebase_path_current_fixups());
5224+
goto out;
5225+
}
52105226

52115227
/*
52125228
* If a fixup/squash in a fixup/squash chain failed, the
@@ -5236,54 +5252,68 @@ static int commit_staged_changes(struct repository *r,
52365252
* We need to update the squash message to skip
52375253
* the latest commit message.
52385254
*/
5239-
int res = 0;
52405255
struct commit *commit;
52415256
const char *msg;
52425257
const char *path = rebase_path_squash_msg();
52435258
const char *encoding = get_commit_output_encoding();
52445259

5245-
if (parse_head(r, &commit))
5246-
return error(_("could not parse HEAD"));
5260+
if (parse_head(r, &commit)) {
5261+
ret = error(_("could not parse HEAD"));
5262+
goto out;
5263+
}
52475264

52485265
p = repo_logmsg_reencode(r, commit, NULL, encoding);
52495266
if (!p) {
5250-
res = error(_("could not parse commit %s"),
5267+
ret = error(_("could not parse commit %s"),
52515268
oid_to_hex(&commit->object.oid));
52525269
goto unuse_commit_buffer;
52535270
}
52545271
find_commit_subject(p, &msg);
52555272
if (write_message(msg, strlen(msg), path, 0)) {
5256-
res = error(_("could not write file: "
5273+
ret = error(_("could not write file: "
52575274
"'%s'"), path);
52585275
goto unuse_commit_buffer;
52595276
}
5277+
5278+
ret = 0;
5279+
52605280
unuse_commit_buffer:
52615281
repo_unuse_commit_buffer(r, commit, p);
5262-
if (res)
5263-
return res;
5282+
if (ret)
5283+
goto out;
52645284
}
52655285
}
52665286

5267-
strbuf_release(&rev);
52685287
flags |= AMEND_MSG;
52695288
}
52705289

52715290
if (is_clean) {
52725291
if (refs_ref_exists(get_main_ref_store(r),
52735292
"CHERRY_PICK_HEAD") &&
52745293
refs_delete_ref(get_main_ref_store(r), "",
5275-
"CHERRY_PICK_HEAD", NULL, REF_NO_DEREF))
5276-
return error(_("could not remove CHERRY_PICK_HEAD"));
5277-
if (unlink(git_path_merge_msg(r)) && errno != ENOENT)
5278-
return error_errno(_("could not remove '%s'"),
5279-
git_path_merge_msg(r));
5280-
if (!final_fixup)
5281-
return 0;
5294+
"CHERRY_PICK_HEAD", NULL, REF_NO_DEREF)) {
5295+
ret = error(_("could not remove CHERRY_PICK_HEAD"));
5296+
goto out;
5297+
}
5298+
5299+
if (unlink(git_path_merge_msg(r)) && errno != ENOENT) {
5300+
ret = error_errno(_("could not remove '%s'"),
5301+
git_path_merge_msg(r));
5302+
goto out;
5303+
}
5304+
5305+
if (!final_fixup) {
5306+
ret = 0;
5307+
goto out;
5308+
}
52825309
}
52835310

52845311
if (run_git_commit(final_fixup ? NULL : rebase_path_message(),
5285-
opts, flags))
5286-
return error(_("could not commit staged changes."));
5312+
opts, flags)) {
5313+
ret = error(_("could not commit staged changes."));
5314+
goto out;
5315+
}
5316+
52875317
unlink(rebase_path_amend());
52885318
unlink(git_path_merge_head(r));
52895319
refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
@@ -5301,7 +5331,12 @@ static int commit_staged_changes(struct repository *r,
53015331
strbuf_reset(&ctx->current_fixups);
53025332
ctx->current_fixup_count = 0;
53035333
}
5304-
return 0;
5334+
5335+
ret = 0;
5336+
5337+
out:
5338+
strbuf_release(&rev);
5339+
return ret;
53055340
}
53065341

53075342
int sequencer_continue(struct repository *r, struct replay_opts *opts)

0 commit comments

Comments
 (0)