Skip to content

Memory leak fixes (pt.9)

Patrick Steinhardt git 3 versions – In review

Get series with b4
b4 am [email protected]

Versions newest first · linked by author and title

  1. v3 Latest22 patches 3 repliesIn review
  2. v222 patches 18 repliesSuperseded
  3. v121 patches 11 repliesSuperseded

Patches in v3 No applies recorded yet

#Subject and filesSizeRepliesApplied
1/22builtin/ls-remote: plug leaking server optionsbuiltin/ls-remote.c+1 -00 replies
2/22t/helper: fix leaks in "reach" test toolt/helper/test-reach.c t/t6600-test-reach.sh+11 -00 replies
3/22grep: fix leak in `grep_splice_or()`grep.c+1 -00 replies
4/22builtin/grep: fix leak with `--max-count=0`builtin/grep.c t/t7810-grep.sh+11 -30 replies
5/22revision: fix leaking bloom filtersrevision.c t/t4216-log-bloom.sh+6 -00 replies
6/22diff-lib: fix leaking diffopts in `do_diff_cache()`diff-lib.c t/t7610-mergetool.sh+2 -00 replies
7/22pretty: clear signature checkpretty.c t/t4202-log.sh t/t7031-verify-tag-signed-ssh.sh +2 more+5 -00 replies
8/22upload-pack: fix leaking URI protocolst/t5702-protocol-v2.sh upload-pack.c+2 -00 replies
9/22builtin/commit: fix leaking change data contentsbuiltin/commit.c t/t7500-commit-template-squash-signoff.sh+9 -10 replies
10/22trailer: fix leaking trailer valuestrailer.c+8 -20 replies
11/22trailer: fix leaking strbufs when formatting trailerst/t7513-interpret-trailers.sh trailer.c+8 -50 replies
12/22builtin/commit: fix leaking cleanup configbuiltin/commit.c t/t7502-commit-porcelain.sh+13 -50 replies
13/22transport-helper: fix leaking import/export markst/t5801-remote-helpers.sh transport-helper.c+3 -00 replies
14/22builtin/tag: fix leaking key ID on failure to signbuiltin/tag.c t/t7004-tag.sh+2 -10 replies
15/22combine-diff: fix leaking lost linescombine-diff.c t/t4038-diff-combined.sh+4 -20 replies
16/22dir: release untracked cache datadir.c+8 -00 replies
17/22sparse-index: correctly free EWAH contentssparse-index.c+5 -20 replies
18/22t/helper: stop re-initialization of `the_repository`t/helper/test-read-cache.c t/t7519-status-fsmonitor.sh+1 -20 replies
19/22t/helper: fix leaking buffer in "dump-untracked-cache"t/helper/test-dump-untracked-cache.c+2 -00 replies
20/22dir: fix leak when parsing "status.showUntrackedFiles"dir.c t/t7063-status-untracked-cache.sh+3 -20 replies
21/22builtin/merge: release output buffer after performing mergebuiltin/merge.c t/t6424-merge-unrelated-index-changes.sh+2 -00 replies
22/22list-objects-filter-options: work around reported leak on errorlist-objects-filter-options.c t/t6112-rev-list-filters-objects.sh+8 -100 replies

Reviews trailers per patch

No Reviewed-by, Acked-by or Tested-by trailers for v3 yet.

Read the v3 thread

Cover letter [PATCH v3 00/22] Memory leak fixes (pt.9)

Hi,

this is the third revision of my 9th series of memory leak fixes. Changes compared to v2:

- Remove an unnecessary cast.

- Fix a duplicate newline.

- Polish a couple of commit messages.

Thanks!

Patrick

Patrick Steinhardt (22):
builtin/ls-remote: plug leaking server options t/helper: fix leaks in "reach" test tool
grep: fix leak in grep_splice_or()
builtin/grep: fix leak with --max-count=0
revision: fix leaking bloom filters
diff-lib: fix leaking diffopts in do_diff_cache()
pretty: clear signature check
upload-pack: fix leaking URI protocols builtin/commit: fix leaking change data contents
trailer: fix leaking trailer values
trailer: fix leaking strbufs when formatting trailers builtin/commit: fix leaking cleanup config
transport-helper: fix leaking import/export marks builtin/tag: fix leaking key ID on failure to sign
combine-diff: fix leaking lost lines
dir: release untracked cache data
sparse-index: correctly free EWAH contents
t/helper: stop re-initialization of the_repository t/helper: fix leaking buffer in "dump-untracked-cache"
dir: fix leak when parsing "status.showUntrackedFiles" builtin/merge: release output buffer after performing merge list-objects-filter-options: work around reported leak on error

 builtin/commit.c                          | 26 +++++++++++++++++------
 builtin/grep.c                            | 13 +++++++++---
 builtin/ls-remote.c                       |  1 +
 builtin/merge.c                           |  1 +
 builtin/tag.c                             |  2 +-
 combine-diff.c                            |  5 +++--
 diff-lib.c                                |  1 +
 dir.c                                     | 12 +++++++++--
 grep.c                                    |  1 +
 list-objects-filter-options.c             | 17 ++++++---------
 pretty.c                                  |  1 +
 revision.c                                |  5 +++++
 sparse-index.c                            |  7 ++++--
 t/helper/test-dump-untracked-cache.c      |  2 ++
 t/helper/test-reach.c                     | 10 +++++++++
 t/helper/test-read-cache.c                |  2 --
 t/t4038-diff-combined.sh                  |  1 +
 t/t4202-log.sh                            |  1 +
 t/t4216-log-bloom.sh                      |  1 +
 t/t5702-protocol-v2.sh                    |  1 +
 t/t5801-remote-helpers.sh                 |  1 +
 t/t6112-rev-list-filters-objects.sh       |  1 +
 t/t6424-merge-unrelated-index-changes.sh  |  1 +
 t/t6600-test-reach.sh                     |  1 +
 t/t7004-tag.sh                            |  1 +
 t/t7031-verify-tag-signed-ssh.sh          |  1 +
 t/t7063-status-untracked-cache.sh         |  1 +
 t/t7500-commit-template-squash-signoff.sh |  1 +
 t/t7502-commit-porcelain.sh               |  1 +
 t/t7510-signed-commit.sh                  |  1 +
 t/t7513-interpret-trailers.sh             |  1 +
 t/t7519-status-fsmonitor.sh               |  1 +
 t/t7528-signed-commit-ssh.sh              |  1 +
 t/t7610-mergetool.sh                      |  1 +
 t/t7810-grep.sh                           |  1 +
 trailer.c                                 | 22 +++++++++++++------
 transport-helper.c                        |  2 ++
 upload-pack.c                             |  1 +
 38 files changed, 115 insertions(+), 35 deletions(-)

Range-diff against v2:
1: 89b66411354 ! 1: fbb9e68e2f2 builtin/ls-remote: plug leaking server options
@@ Metadata
## Commit message ##
builtin/ls-remote: plug leaking server options

- The server options populated via OPT_STRING_LIST() is never cleared,
- causing a memory leak. Plug it.
+ The list of server options populated via OPT_STRING_LIST() is never
+ cleared, causing a memory leak. Plug it.

This leak is exposed by t5702, but plugging it alone does not make the whole test suite pass.

 2:  1c42e194b20 =  2:  17136f4bdb3 t/helper: fix leaks in "reach" test tool
 3:  cb4eee37b40 !  3:  74b21470194 grep: fix leak in `grep_splice_or()`

@@ Commit message
grep: fix leak in grep_splice_or()

In grep_splice_or() we search for the next TRUE node in our tree of
- grep exrpessions and replace it with the given new expression. But we
+ grep expressions and replace it with the given new expression. But we
don't free the old node, which causes a memory leak. Plug it.

This leak is exposed by t7810, but plugging it alone isn't sufficient to

 4:  6b2c8842ef5 =  4:  d716f93169a builtin/grep: fix leak with `--max-count=0`
 5:  7527b31a28f =  5:  aeb8a19d28d revision: fix leaking bloom filters
 6:  60af98cb2c7 !  6:  24d9d9b1358 diff-lib: fix leaking diffopts in `do_diff_cache()`

@@ Commit message
In do_diff_cache() we initialize a new rev_info and then overwrite its diffopt with a user-provided set of options. This can leak memory because repo_init_revisions() may end up allocating memory for the
- diffopt itself depending on the configuration. And as that field is
- overwritten we won't ever free that.
+ diffopt itself depending on the configuration. And since that field is
+ overwritten we won't ever free it.

Plug the memory leak by releasing the diffopts before we overwrite them.

7: 5d5f6867f91 ! 7: 58ebef7e757 pretty: clear signature check
@@ Metadata
## Commit message ##
pretty: clear signature check

- The signature check in of the formatting context is never getting
- released. Fix this to plug the resulting memory leak.
+ The signature check in the formatting context is never getting released.
+ Fix this to plug the resulting memory leak.

 8:  0d503e40194 =  8:  c5813079d44 upload-pack: fix leaking URI protocols
 9:  9f967dfe5d5 =  9:  f66fa4e0e25 builtin/commit: fix leaking change data contents
10:  e3ffd59123f ! 10:  dac63bae39e trailer: fix leaking trailer values
    @@ trailer.c: static char *apply_command(struct conf_info *conf, const char *arg)
     +		char *arg;
     +
      		if (arg_tok->value && arg_tok->value[0]) {
    --			arg = arg_tok->value;
    -+			arg = (char *)arg_tok->value;
    + 			arg = arg_tok->value;
      		} else {
    - 			if (in_tok && in_tok->value)
    +@@ trailer.c: static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg
      				arg = xstrdup(in_tok->value);
      			else
      				arg = xstrdup("");

11: 5b851453bce ! 11: 82269e5d5be trailer: fix leaking strbufs when formatting trailers
@@ Metadata
## Commit message ##
trailer: fix leaking strbufs when formatting trailers

- We are populating, but never releasing two string buffers in
- format_trailers(), causing a memory leak. Plug this leak by lifting
- those buffers outside of the loop and releasing them on function return.
- This fixes the memory leaks, but also optimizes the loop as we don't
- have to reallocate the buffers on every single iteration.
+ When formatting trailer lines we iterate through each of the trailers
+ and munge their respective token/value pairs according to the trailer
+ options. When formatting a trailer that has its item->token pointer
+ set we perform the munging in two local buffers. In the case where we
+ figure out that the value is empty and trim_empty is set we just skip
+ over the trailer item. But the buffers are local to the loop and we
+ don't release their contents, leading to a memory leak.
+
+ Plug this leak by lifting the buffers outside of the loop and releasing
+ them on function return. This fixes the memory leaks, but also optimizes
+ the loop as we don't have to reallocate the buffers on every single
+ iteration.

@@ trailer.c: void format_trailers(const struct process_trailer_options *opts,
size_t origlen = out->len;
struct list_head *pos;
struct trailer_item *item;
-
-+
+@@ trailer.c: void format_trailers(const struct process_trailer_options *opts,
list_for_each(pos, trailers) {
item = list_entry(pos, struct trailer_item, list);
if (item->token) {

12:  60c3f6146f3 = 12:  a627e03702e builtin/commit: fix leaking cleanup config
13:  ea81cd8db86 = 13:  40e0c2a2cac transport-helper: fix leaking import/export marks
14:  b700ab9079f = 14:  ffa5d9eae7e builtin/tag: fix leaking key ID on failure to sign
15:  76bbcb3fe30 ! 15:  70dd0cb6933 combine-diff: fix leaking lost lines

@@ Commit message
The cnt variable tracks the number of lines in a patch diff. It can happen though that there are no newlines, in which case we'd still end up allocating our array of slines. In fact, we always allocate it with
- cnt + 2 entries. But when we loop through the array to clear it at the
- end of this function we only loop until lno < cnt, and thus we may not
- end up releasing whatever the two extra slines contain.
+ cnt + 2 entries: one extra entry for the deletion hunk at the end, and
+ another entry that we don't seem to ever populate at all but acts as a
+ kind of sentinel value.

- Plug this memory leak.
+ When we loop through the array to clear it at the end of this function
+ we only loop until lno < cnt, and thus we may not end up releasing
+ whatever the two extra slines contain. While that shouldn't matter for
+ the sentinel value, it does matter for the extra deletion hunk sline.
+ Regardless of that, plug this memory leak by releasing both extra
+ entries, which makes the logic a bit easier to reason about.
+
+ While at it, fix the formatting of a local comment, which incidentally
+ also provides the necessary context for why we overallocate the sline
+ array.

## combine-diff.c ##
+@@ combine-diff.c: static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
+ result_file.ptr = result;
+ result_file.size = result_size;
+
+- /* Even p_lno[cnt+1] is valid -- that is for the end line number
++ /*
++ * Even p_lno[cnt+1] is valid -- that is for the end line number
+ * for deletion hunk at the end.
+ */
+ CALLOC_ARRAY(sline[0].p_lno, st_mult(st_add(cnt, 2), num_parent));
@@ combine-diff.c: static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
}
free(result);

16:  d6b96a4012d = 16:  b248f266a91 dir: release untracked cache data
17:  3aa6bac5079 = 17:  76e9a6d5792 sparse-index: correctly free EWAH contents
18:  132fe750906 = 18:  70f16486d77 t/helper: stop re-initialization of `the_repository`
19:  b8b702eeb28 = 19:  f056d31ca50 t/helper: fix leaking buffer in "dump-untracked-cache"
20:  ad309ac1b37 = 20:  714c9286e7a dir: fix leak when parsing "status.showUntrackedFiles"
21:  5e243f9ee53 ! 21:  0ff65c1213b builtin/merge: release outbut buffer after performing merge

@@ Metadata
Author: Patrick Steinhardt <[email protected]>

## Commit message ##
- builtin/merge: release outbut buffer after performing merge
+ builtin/merge: release output buffer after performing merge

The obuf member of struct merge_options is used to buffer output in some cases. In order to not discard its allocated memory we only release
22: b75376e3725 = 22: d9e122bb5db list-objects-filter-options: work around reported leak on error

Signature · 1 line
2.47.0.229.g8f8d6eee53.dirty