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

[PATCH v2 15/29] revision: free diff options

From
Patrick Steinhardt <ps@pks.im>
Date
Jun 11, 2024, 09:20 UTC
Message-ID
<99f4f3d3412a40eb6ada67ae48c7369cb57762cc.1718095906.git.ps@pks.im>
In-Reply-To
<cover.1718095906.git.ps@pks.im>
There is a todo comment in `release_revisions()` that mentions that we
need to free the diff options, which was added via 54c8a7c379 (revisions
API: add a TODO for diff_free(&revs->diffopt), 2022-04-14). Releasing
the diff options wasn't quite feasible at that time because some call
sites rely on its contents to remain even after the revisions have been
released.

In fact, there really only are a couple of callsites that misbehave here:

  - `cmd_shortlog()` releases the revisions, but continues to access its
    file pointer.
  - `do_diff_cache()` creates a shallow copy of `struct diff_options`,
    but does not set the `no_free` member. Consequently, we end up
    releasing resources of the caller-provided diff options.
  - `diff_free()` and friends do not play nice when being called
    multiple times as they don't unset data structures that they have
    just released.

Fix all of those cases and enable the call to `diff_free()`, which plugs a bunch of memory leaks.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/shortlog.c                        | 5 +----
 diff-lib.c                                | 2 ++
 diff.c                                    | 8 ++++++--
 revision.c                                | 2 +-
 t/t4208-log-magic-pathspec.sh             | 1 +
 t/t6000-rev-list-misc.sh                  | 1 +
 t/t6001-rev-list-graft.sh                 | 1 +
 t/t6013-rev-list-reverse-parents.sh       | 1 +
 t/t6017-rev-list-stdin.sh                 | 1 +
 t/t9500-gitweb-standalone-no-errors.sh    | 1 +
 t/t9502-gitweb-standalone-parse-output.sh | 1 +
 11 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index d4daf31e22..5bde7c68c2 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -460,11 +460,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 	else
 		get_from_rev(&rev, &log);
 
-	release_revisions(&rev);
-
 	shortlog_output(&log);
-	if (log.file != stdout)
-		fclose(log.file);
+	release_revisions(&rev);
 	return 0;
 }
 
diff --git a/diff-lib.c b/diff-lib.c
index 5a5a50c5a1..1cbf03bf39 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -662,9 +662,11 @@ int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt)
 	repo_init_revisions(opt->repo, &revs, NULL);
 	copy_pathspec(&revs.prune_data, &opt->pathspec);
 	revs.diffopt = *opt;
+	revs.diffopt.no_free = 1;
 
 	if (diff_cache(&revs, tree_oid, NULL, 1))
 		exit(128);
+
 	release_revisions(&revs);
 	return 0;
 }
diff --git a/diff.c b/diff.c
index e70301df76..53e2f5a42e 100644
--- a/diff.c
+++ b/diff.c
@@ -6649,8 +6649,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
 
 static void diff_free_file(struct diff_options *options)
 {
-	if (options->close_file)
+	if (options->close_file && options->file) {
 		fclose(options->file);
+		options->file = NULL;
+	}
 }
 
 static void diff_free_ignore_regex(struct diff_options *options)
@@ -6661,7 +6663,9 @@ static void diff_free_ignore_regex(struct diff_options *options)
 		regfree(options->ignore_regex[i]);
 		free(options->ignore_regex[i]);
 	}
-	free(options->ignore_regex);
+
+	FREE_AND_NULL(options->ignore_regex);
+	options->ignore_regex_nr = 0;
 }
 
 void diff_free(struct diff_options *options)
diff --git a/revision.c b/revision.c
index 82c0aadb42..99c75c939d 100644
--- a/revision.c
+++ b/revision.c
@@ -3191,7 +3191,7 @@ void release_revisions(struct rev_info *revs)
 	release_revisions_mailmap(revs->mailmap);
 	free_grep_patterns(&revs->grep_filter);
 	graph_clear(revs->graph);
-	/* TODO (need to handle "no_free"): diff_free(&revs->diffopt) */
+	diff_free(&revs->diffopt);
 	diff_free(&revs->pruning);
 	reflog_walk_info_release(revs->reflog_info);
 	release_revisions_topo_walk_info(revs->topo_walk_info);
diff --git a/t/t4208-log-magic-pathspec.sh b/t/t4208-log-magic-pathspec.sh
index 806b2809d4..2a46eb6bed 100755
--- a/t/t4208-log-magic-pathspec.sh
+++ b/t/t4208-log-magic-pathspec.sh
@@ -5,6 +5,7 @@ test_description='magic pathspec tests using git-log'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh
index 6289a2e8b0..f6d17ee902 100755
--- a/t/t6000-rev-list-misc.sh
+++ b/t/t6000-rev-list-misc.sh
@@ -5,6 +5,7 @@ test_description='miscellaneous rev-list tests'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh
index 73a2465aa0..3553bbbfe7 100755
--- a/t/t6001-rev-list-graft.sh
+++ b/t/t6001-rev-list-graft.sh
@@ -5,6 +5,7 @@ test_description='Revision traversal vs grafts and path limiter'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 39793cbbd6..4128269c1d 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -5,6 +5,7 @@ test_description='--reverse combines with --parents'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
diff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh
index 4821b90e74..a0a40fe55c 100755
--- a/t/t6017-rev-list-stdin.sh
+++ b/t/t6017-rev-list-stdin.sh
@@ -8,6 +8,7 @@ test_description='log family learns --stdin'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check () {
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 7679780fb8..ccfa415384 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -13,6 +13,7 @@ or warnings to log.'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-gitweb.sh
 
 # ----------------------------------------------------------------------
diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh
index 81d5625557..b41ea19331 100755
--- a/t/t9502-gitweb-standalone-parse-output.sh
+++ b/t/t9502-gitweb-standalone-parse-output.sh
@@ -13,6 +13,7 @@ in the HTTP header or the actual script output.'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-gitweb.sh
 
 # ----------------------------------------------------------------------
-- 
2.45.2.436.gcd77e87115.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 58 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.