git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 20/29] sequencer: fix leaking string buffer in `commit_staged_changes()`

From
Patrick Steinhardt <ps@pks.im>
Date
Jun 11, 2024, 09:20 UTC
Message-ID
<144eb23617f679034581ec7ffefde8a803499d3b.1718095906.git.ps@pks.im>
In-Reply-To
<cover.1718095906.git.ps@pks.im>

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 <ps@pks.im>
---
 sequencer.c | 111 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 73 insertions(+), 38 deletions(-)
diff --git a/sequencer.c b/sequencer.c
index 475646671a..c581061b6d 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -5146,33 +5146,47 @@ static int commit_staged_changes(struct repository *r,
 	struct replay_ctx *ctx = opts->ctx;
 	unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
 	unsigned int final_fixup = 0, is_clean;
+	struct strbuf rev = STRBUF_INIT;
+	int ret;
 
-	if (has_unstaged_changes(r, 1))
-		return error(_("cannot rebase: You have unstaged changes."));
+	if (has_unstaged_changes(r, 1)) {
+		ret = error(_("cannot rebase: You have unstaged changes."));
+		goto out;
+	}
 
 	is_clean = !has_uncommitted_changes(r, 0);
 
 	if (!is_clean && !file_exists(rebase_path_message())) {
 		const char *gpg_opt = gpg_sign_opt_quoted(opts);
-
-		return error(_(staged_changes_advice), gpg_opt, gpg_opt);
+		ret = error(_(staged_changes_advice), gpg_opt, gpg_opt);
+		goto out;
 	}
+
 	if (file_exists(rebase_path_amend())) {
-		struct strbuf rev = STRBUF_INIT;
 		struct object_id head, to_amend;
 
-		if (repo_get_oid(r, "HEAD", &head))
-			return error(_("cannot amend non-existing commit"));
-		if (!read_oneliner(&rev, rebase_path_amend(), 0))
-			return error(_("invalid file: '%s'"), rebase_path_amend());
-		if (get_oid_hex(rev.buf, &to_amend))
-			return error(_("invalid contents: '%s'"),
-				rebase_path_amend());
-		if (!is_clean && !oideq(&head, &to_amend))
-			return error(_("\nYou have uncommitted changes in your "
-				       "working tree. Please, commit them\n"
-				       "first and then run 'git rebase "
-				       "--continue' again."));
+		if (repo_get_oid(r, "HEAD", &head)) {
+			ret = error(_("cannot amend non-existing commit"));
+			goto out;
+		}
+
+		if (!read_oneliner(&rev, rebase_path_amend(), 0)) {
+			ret = error(_("invalid file: '%s'"), rebase_path_amend());
+			goto out;
+		}
+
+		if (get_oid_hex(rev.buf, &to_amend)) {
+			ret = error(_("invalid contents: '%s'"),
+				    rebase_path_amend());
+			goto out;
+		}
+		if (!is_clean && !oideq(&head, &to_amend)) {
+			ret = error(_("\nYou have uncommitted changes in your "
+				      "working tree. Please, commit them\n"
+				      "first and then run 'git rebase "
+				      "--continue' again."));
+			goto out;
+		}
 		/*
 		 * When skipping a failed fixup/squash, we need to edit the
 		 * commit message, the current fixup list and count, and if it
@@ -5204,9 +5218,11 @@ static int commit_staged_changes(struct repository *r,
 				len--;
 			strbuf_setlen(&ctx->current_fixups, len);
 			if (write_message(p, len, rebase_path_current_fixups(),
-					  0) < 0)
-				return error(_("could not write file: '%s'"),
-					     rebase_path_current_fixups());
+					  0) < 0) {
+				ret = error(_("could not write file: '%s'"),
+					    rebase_path_current_fixups());
+				goto out;
+			}
 
 			/*
 			 * If a fixup/squash in a fixup/squash chain failed, the
@@ -5236,35 +5252,38 @@ static int commit_staged_changes(struct repository *r,
 				 * We need to update the squash message to skip
 				 * the latest commit message.
 				 */
-				int res = 0;
 				struct commit *commit;
 				const char *msg;
 				const char *path = rebase_path_squash_msg();
 				const char *encoding = get_commit_output_encoding();
 
-				if (parse_head(r, &commit))
-					return error(_("could not parse HEAD"));
+				if (parse_head(r, &commit)) {
+					ret = error(_("could not parse HEAD"));
+					goto out;
+				}
 
 				p = repo_logmsg_reencode(r, commit, NULL, encoding);
 				if (!p)  {
-					res = error(_("could not parse commit %s"),
+					ret = error(_("could not parse commit %s"),
 						    oid_to_hex(&commit->object.oid));
 					goto unuse_commit_buffer;
 				}
 				find_commit_subject(p, &msg);
 				if (write_message(msg, strlen(msg), path, 0)) {
-					res = error(_("could not write file: "
+					ret = error(_("could not write file: "
 						       "'%s'"), path);
 					goto unuse_commit_buffer;
 				}
+
+				ret = 0;
+
 			unuse_commit_buffer:
 				repo_unuse_commit_buffer(r, commit, p);
-				if (res)
-					return res;
+				if (ret)
+					goto out;
 			}
 		}
 
-		strbuf_release(&rev);
 		flags |= AMEND_MSG;
 	}
 
@@ -5272,18 +5291,29 @@ static int commit_staged_changes(struct repository *r,
 		if (refs_ref_exists(get_main_ref_store(r),
 				    "CHERRY_PICK_HEAD") &&
 		    refs_delete_ref(get_main_ref_store(r), "",
-				    "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF))
-			return error(_("could not remove CHERRY_PICK_HEAD"));
-		if (unlink(git_path_merge_msg(r)) && errno != ENOENT)
-			return error_errno(_("could not remove '%s'"),
-					   git_path_merge_msg(r));
-		if (!final_fixup)
-			return 0;
+				    "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF)) {
+			ret = error(_("could not remove CHERRY_PICK_HEAD"));
+			goto out;
+		}
+
+		if (unlink(git_path_merge_msg(r)) && errno != ENOENT) {
+			ret = error_errno(_("could not remove '%s'"),
+					  git_path_merge_msg(r));
+			goto out;
+		}
+
+		if (!final_fixup) {
+			ret = 0;
+			goto out;
+		}
 	}
 
 	if (run_git_commit(final_fixup ? NULL : rebase_path_message(),
-			   opts, flags))
-		return error(_("could not commit staged changes."));
+			   opts, flags)) {
+		ret = error(_("could not commit staged changes."));
+		goto out;
+	}
+
 	unlink(rebase_path_amend());
 	unlink(git_path_merge_head(r));
 	refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
@@ -5301,7 +5331,12 @@ static int commit_staged_changes(struct repository *r,
 		strbuf_reset(&ctx->current_fixups);
 		ctx->current_fixup_count = 0;
 	}
-	return 0;
+
+	ret = 0;
+
+out:
+	strbuf_release(&rev);
+	return ret;
 }
 
 int sequencer_continue(struct repository *r, struct replay_opts *opts)
-- 
2.45.2.436.gcd77e87115.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 63 of 74 in “Memory leak fixes (pt.2)”
  1. 00/29 Memory leak fixes (pt.2)Patrick Steinhardt, Jun 3, 2024
  2. 01/29 revision: fix memory leak when reversing revisionsPatrick Steinhardt, Jun 3, 2024
  3. 02/29 parse-options: fix leaks for users of OPT_FILENAMEPatrick Steinhardt, Jun 3, 2024
  4. Karthik NayakJun 6, 2024
  5. 03/29 notes-utils: free note trees when releasing copied notesPatrick Steinhardt, Jun 3, 2024
  6. Karthik NayakJun 6, 2024
  7. 04/29 bundle: plug leaks in `create_bundle()`Patrick Steinhardt, Jun 3, 2024
  8. 05/29 biultin/rev-parse: fix memory leaks in `--parseopt` modePatrick Steinhardt, Jun 3, 2024
  9. 06/29 merge-recursive: fix leaging rename conflict infoPatrick Steinhardt, Jun 3, 2024
  10. Karthik NayakJun 6, 2024
  11. 07/29 revision: fix leaking display notesPatrick Steinhardt, Jun 3, 2024
  12. 08/29 notes: fix memory leak when pruning notesPatrick Steinhardt, Jun 3, 2024
  13. 09/29 builtin/rev-list: fix leaking bitmap index when calculating disk usagePatrick Steinhardt, Jun 3, 2024
  14. 10/29 object-name: free leaking object contextsPatrick Steinhardt, Jun 3, 2024
  15. 11/29 builtin/difftool: plug memory leaks in `run_dir_diff()`Patrick Steinhardt, Jun 3, 2024
  16. 12/29 builtin/merge-recursive: fix leaking object ID basesPatrick Steinhardt, Jun 3, 2024
  17. 13/29 merge-recursive: fix memory leak when finalizing mergePatrick Steinhardt, Jun 3, 2024
  18. Karthik NayakJun 6, 2024
  19. Phillip WoodJun 6, 2024
  20. Karthik NayakJun 12, 2024
  21. 14/29 builtin/log: fix leaking commit list in git-cherry(1)Patrick Steinhardt, Jun 3, 2024
  22. 15/29 revision: free diff optionsPatrick Steinhardt, Jun 3, 2024
  23. 16/29 builtin/stash: fix leak in `show_stash()`Patrick Steinhardt, Jun 3, 2024
  24. 17/29 rerere: fix various trivial leaksPatrick Steinhardt, Jun 3, 2024
  25. 18/29 config: fix leaking "core.notesref" variablePatrick Steinhardt, Jun 3, 2024
  26. 19/29 commit: fix leaking parents when calling `commit_tree_extended()`Patrick Steinhardt, Jun 3, 2024
  27. 20/29 sequencer: fix leaking string buffer in `commit_staged_changes()`Patrick Steinhardt, Jun 3, 2024
  28. Phillip WoodJun 3, 2024
  29. Patrick SteinhardtJun 4, 2024
  30. Patrick SteinhardtJun 4, 2024
  31. Phillip WoodJun 4, 2024
  32. 21/29 apply: fix leaking string in `match_fragment()`Patrick Steinhardt, Jun 3, 2024
  33. 22/29 builtin/clone: plug leaking HEAD ref in `wanted_peer_refs()`Patrick Steinhardt, Jun 3, 2024
  34. 23/29 sequencer: fix memory leaks in `make_script_with_merges()`Patrick Steinhardt, Jun 3, 2024
  35. 24/29 builtin/merge: fix leaking `struct cmdnames` in `get_strategy()`Patrick Steinhardt, Jun 3, 2024
  36. 25/29 merge: fix leaking merge basesPatrick Steinhardt, Jun 3, 2024
  37. 26/29 line-range: plug leaking find functionsPatrick Steinhardt, Jun 3, 2024
  38. 27/29 blame: fix leaking data for blame scoreboardsPatrick Steinhardt, Jun 3, 2024
  39. 28/29 builtin/blame: fix leaking prefixed pathsPatrick Steinhardt, Jun 3, 2024
  40. 29/29 builtin/blame: fix leaking ignore revs filesPatrick Steinhardt, Jun 3, 2024
  41. Karthik NayakJun 6, 2024
  42. Patrick SteinhardtJun 7, 2024
  43. 00/29 Memory leak fixes (pt.2)Patrick Steinhardt, Jun 11, 2024
  44. 01/29 revision: fix memory leak when reversing revisionsPatrick Steinhardt, Jun 11, 2024
  45. 02/29 parse-options: fix leaks for users of OPT_FILENAMEPatrick Steinhardt, Jun 11, 2024
  46. 03/29 notes-utils: free note trees when releasing copied notesPatrick Steinhardt, Jun 11, 2024
  47. 04/29 bundle: plug leaks in `create_bundle()`Patrick Steinhardt, Jun 11, 2024
  48. 05/29 biultin/rev-parse: fix memory leaks in `--parseopt` modePatrick Steinhardt, Jun 11, 2024
  49. 06/29 merge-recursive: fix leaking rename conflict infoPatrick Steinhardt, Jun 11, 2024
  50. 07/29 revision: fix leaking display notesPatrick Steinhardt, Jun 11, 2024
  51. 08/29 notes: fix memory leak when pruning notesPatrick Steinhardt, Jun 11, 2024
  52. 09/29 builtin/rev-list: fix leaking bitmap index when calculating disk usagePatrick Steinhardt, Jun 11, 2024
  53. 10/29 object-name: free leaking object contextsPatrick Steinhardt, Jun 11, 2024
  54. 11/29 builtin/difftool: plug memory leaks in `run_dir_diff()`Patrick Steinhardt, Jun 11, 2024
  55. 12/29 builtin/merge-recursive: fix leaking object ID basesPatrick Steinhardt, Jun 11, 2024
  56. 13/29 merge-recursive: fix memory leak when finalizing mergePatrick Steinhardt, Jun 11, 2024
  57. 14/29 builtin/log: fix leaking commit list in git-cherry(1)Patrick Steinhardt, Jun 11, 2024
  58. 15/29 revision: free diff optionsPatrick Steinhardt, Jun 11, 2024
  59. 16/29 builtin/stash: fix leak in `show_stash()`Patrick Steinhardt, Jun 11, 2024
  60. 17/29 rerere: fix various trivial leaksPatrick Steinhardt, Jun 11, 2024
  61. 18/29 config: fix leaking "core.notesref" variablePatrick Steinhardt, Jun 11, 2024
  62. 19/29 commit: fix leaking parents when calling `commit_tree_extended()`Patrick Steinhardt, Jun 11, 2024
  63. 20/29 sequencer: fix leaking string buffer in `commit_staged_changes()`Patrick Steinhardt, Jun 11, 2024
  64. 21/29 apply: fix leaking string in `match_fragment()`Patrick Steinhardt, Jun 11, 2024
  65. 22/29 builtin/clone: plug leaking HEAD ref in `wanted_peer_refs()`Patrick Steinhardt, Jun 11, 2024
  66. 23/29 sequencer: fix memory leaks in `make_script_with_merges()`Patrick Steinhardt, Jun 11, 2024
  67. 24/29 builtin/merge: fix leaking `struct cmdnames` in `get_strategy()`Patrick Steinhardt, Jun 11, 2024
  68. 25/29 merge: fix leaking merge basesPatrick Steinhardt, Jun 11, 2024
  69. 26/29 line-range: plug leaking find functionsPatrick Steinhardt, Jun 11, 2024
  70. 27/29 blame: fix leaking data for blame scoreboardsPatrick Steinhardt, Jun 11, 2024
  71. 28/29 builtin/blame: fix leaking prefixed pathsPatrick Steinhardt, Jun 11, 2024
  72. 29/29 builtin/blame: fix leaking ignore revs filesPatrick Steinhardt, Jun 11, 2024
  73. Phillip WoodJun 12, 2024
  74. Karthik NayakJun 12, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.