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

[PATCH v2 6/6] revisions API: don't leak memory on argv elements that need free()-ing

From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Date
Jul 29, 2022, 08:31 UTC
Message-ID
<patch-v2-6.6-3c57e126554-20220729T082919Z-avarab@gmail.com>
In-Reply-To
<cover-v2-0.6-00000000000-20220729T082919Z-avarab@gmail.com>

Add a "free_removed_argv_elements" member to "struct setup_revision_opt", and use it to fix several memory leaks, e.g. the one with a "XXX" comment added in 8a534b61241 (bisect: use argv_array API, 2011-09-13).

We have various memory leaks in APIs that take and munge "const char **argv", e.g. parse_options(). Sometimes these APIs are given the "argv" we get to the "main" function, in which case we don't leak memory, but other times we're giving it the "v" member of a "struct strvec" we created.

There's several potential ways to fix those sort of leaks, we could add a "nodup" mode to "struct strvec", which would work for the cases where we push constant strings to it. But that wouldn't work as soon as we used strvec_pushf(), or otherwise needed to duplicate or create a string for that "struct strvec".

Let's instead make it the responsibility of the revisions API. If it's going to clobber elements of argv it can also free() them, which it will now do if instructed to do so via "free_removed_argv_elements".

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 bisect.c                    | 6 ++++--
 builtin/submodule--helper.c | 5 ++++-
 remote.c                    | 5 ++++-
 revision.c                  | 2 ++
 revision.h                  | 3 ++-
 t/t2020-checkout-detach.sh  | 1 +
 6 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/bisect.c b/bisect.c
index 6afb98be7a1..38b3891f3a6 100644
--- a/bisect.c
+++ b/bisect.c
@@ -653,6 +653,9 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
 			     const char *bad_format, const char *good_format,
 			     int read_paths)
 {
+	struct setup_revision_opt opt = {
+		.free_removed_argv_elements = 1,
+	};
 	int i;
 
 	repo_init_revisions(r, revs, prefix);
@@ -669,8 +672,7 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
 	if (read_paths)
 		read_bisect_paths(rev_argv);
 
-	setup_revisions(rev_argv->nr, rev_argv->v, revs, NULL);
-	/* XXX leak rev_argv, as "revs" may still be pointing to it */
+	setup_revisions(rev_argv->nr, rev_argv->v, revs, &opt);
 }
 
 static void bisect_common(struct rev_info *revs)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index fac52ade5e1..b63f420ecef 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1104,6 +1104,9 @@ static int compute_summary_module_list(struct object_id *head_oid,
 {
 	struct strvec diff_args = STRVEC_INIT;
 	struct rev_info rev;
+	struct setup_revision_opt opt = {
+		.free_removed_argv_elements = 1,
+	};
 	struct module_cb_list list = MODULE_CB_LIST_INIT;
 	int ret = 0;
 
@@ -1121,7 +1124,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
 	init_revisions(&rev, info->prefix);
 	rev.abbrev = 0;
 	precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
-	setup_revisions(diff_args.nr, diff_args.v, &rev, NULL);
+	setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
 	rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
 	rev.diffopt.format_callback = submodule_summary_callback;
 	rev.diffopt.format_callback_data = &list;
diff --git a/remote.c b/remote.c
index 1ee2b145d07..d66064118cb 100644
--- a/remote.c
+++ b/remote.c
@@ -2169,6 +2169,9 @@ static int stat_branch_pair(const char *branch_name, const char *base,
 	struct object_id oid;
 	struct commit *ours, *theirs;
 	struct rev_info revs;
+	struct setup_revision_opt opt = {
+		.free_removed_argv_elements = 1,
+	};
 	struct strvec argv = STRVEC_INIT;
 
 	/* Cannot stat if what we used to build on no longer exists */
@@ -2203,7 +2206,7 @@ static int stat_branch_pair(const char *branch_name, const char *base,
 	strvec_push(&argv, "--");
 
 	repo_init_revisions(the_repository, &revs, NULL);
-	setup_revisions(argv.nr, argv.v, &revs, NULL);
+	setup_revisions(argv.nr, argv.v, &revs, &opt);
 	if (prepare_revision_walk(&revs))
 		die(_("revision walk setup failed"));
 
diff --git a/revision.c b/revision.c
index 0c6e26cd9c8..35d24e4fd3e 100644
--- a/revision.c
+++ b/revision.c
@@ -2784,6 +2784,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 			const char *arg = argv[i];
 			if (strcmp(arg, "--"))
 				continue;
+			if (opt && opt->free_removed_argv_elements)
+				free((char *)argv[i]);
 			argv[i] = NULL;
 			argc = i;
 			if (argv[i + 1])
diff --git a/revision.h b/revision.h
index e576845cdd1..bb91e7ed914 100644
--- a/revision.h
+++ b/revision.h
@@ -375,7 +375,8 @@ struct setup_revision_opt {
 	const char *def;
 	void (*tweak)(struct rev_info *, struct setup_revision_opt *);
 	unsigned int	assume_dashdash:1,
-			allow_exclude_promisor_objects:1;
+			allow_exclude_promisor_objects:1,
+			free_removed_argv_elements:1;
 	unsigned revarg_opt;
 };
 int setup_revisions(int argc, const char **argv, struct rev_info *revs,
diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh
index bc46713a43e..2eab6474f8d 100755
--- a/t/t2020-checkout-detach.sh
+++ b/t/t2020-checkout-detach.sh
@@ -4,6 +4,7 @@ test_description='checkout into detached HEAD state'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_detached () {
-- 
2.37.1.1196.g8af3636bc64
Previous: Ævar Arnfjörð BjarmasonNext: Jeff King
Message 32 of 52 in “revisions API: fix more memory leaks”
  1. 0/6 revisions API: fix more memory leaksÆvar Arnfjörð Bjarmason, Jul 13, 2022
  2. 1/6 bisect.c: add missing "goto" for release_revisions()Ævar Arnfjörð Bjarmason, Jul 13, 2022
  3. 2/6 test-fast-rebase helper: use release_revisions() (again)Ævar Arnfjörð Bjarmason, Jul 13, 2022
  4. 3/6 log: make the intent of cmd_show()'s "rev.pending" juggling clearerÆvar Arnfjörð Bjarmason, Jul 13, 2022
  5. Jeff KingJul 18, 2022
  6. 4/6 log: fix common "rev.pending" memory leak in "git show"Ævar Arnfjörð Bjarmason, Jul 13, 2022
  7. Jeff KingJul 18, 2022
  8. Ævar Arnfjörð BjarmasonJul 18, 2022
  9. 5/6 bisect.c: partially fix bisect_rev_setup() memory leakÆvar Arnfjörð Bjarmason, Jul 13, 2022
  10. Jeff KingJul 18, 2022
  11. 6/6 revisions API: don't leak memory on argv elements that need free()-ingÆvar Arnfjörð Bjarmason, Jul 13, 2022
  12. Jeff KingJul 18, 2022
  13. Ævar Arnfjörð BjarmasonJul 18, 2022
  14. Jeff KingJul 18, 2022
  15. Ævar Arnfjörð BjarmasonJul 29, 2022
  16. Jeff KingJul 29, 2022
  17. Jeff KingJul 29, 2022
  18. Junio C HamanoJul 29, 2022
  19. Jeff KingJul 29, 2022
  20. Jeff KingJul 18, 2022
  21. 0/6 revisions API: fix more memory leaksÆvar Arnfjörð Bjarmason, Jul 29, 2022
  22. 1/6 bisect.c: add missing "goto" for release_revisions()Ævar Arnfjörð Bjarmason, Jul 29, 2022
  23. 2/6 test-fast-rebase helper: use release_revisions() (again)Ævar Arnfjörð Bjarmason, Jul 29, 2022
  24. Eric SunshineJul 30, 2022
  25. 3/6 log: make the intent of cmd_show()'s "rev.pending" juggling clearerÆvar Arnfjörð Bjarmason, Jul 29, 2022
  26. Junio C HamanoJul 29, 2022
  27. 4/6 log: fix common "rev.pending" memory leak in "git show"Ævar Arnfjörð Bjarmason, Jul 29, 2022
  28. Jeff KingJul 29, 2022
  29. Jeff KingJul 29, 2022
  30. Jeff KingJul 29, 2022
  31. 5/6 bisect.c: partially fix bisect_rev_setup() memory leakÆvar Arnfjörð Bjarmason, Jul 29, 2022
  32. 6/6 revisions API: don't leak memory on argv elements that need free()-ingÆvar Arnfjörð Bjarmason, Jul 29, 2022
  33. Jeff KingJul 29, 2022
  34. Jeff KingJul 29, 2022
  35. 0/6 revisions API: fix more memory leaksÆvar Arnfjörð Bjarmason, Aug 2, 2022
  36. 1/6 bisect.c: add missing "goto" for release_revisions()Ævar Arnfjörð Bjarmason, Aug 2, 2022
  37. Junio C HamanoAug 3, 2022
  38. 2/6 test-fast-rebase helper: use release_revisions() (again)Ævar Arnfjörð Bjarmason, Aug 2, 2022
  39. 3/6 log: fix a memory leak in "git show <revision>..."Ævar Arnfjörð Bjarmason, Aug 2, 2022
  40. Jeff KingAug 3, 2022
  41. Jeff KingAug 3, 2022
  42. Junio C HamanoAug 3, 2022
  43. 5/6 bisect.c: partially fix bisect_rev_setup() memory leakÆvar Arnfjörð Bjarmason, Aug 2, 2022
  44. 4/6 log: refactor "rev.pending" code in cmd_show()Ævar Arnfjörð Bjarmason, Aug 2, 2022
  45. Jeff KingAug 3, 2022
  46. Junio C HamanoAug 3, 2022
  47. Ævar Arnfjörð BjarmasonAug 4, 2022
  48. Junio C HamanoAug 4, 2022
  49. Ævar Arnfjörð BjarmasonAug 5, 2022
  50. 6/6 revisions API: don't leak memory on argv elements that need free()-ingÆvar Arnfjörð Bjarmason, Aug 2, 2022
  51. Junio C HamanoAug 3, 2022
  52. Jeff KingAug 3, 2022

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.