parse-options: fix leaks for users of OPT_FILENAME

The `OPT_FILENAME()` option will, if set, put an allocated string into the user-provided variable. Consequently, that variable thus needs to be free'd by the caller of `parse_options()`. Some callsites don't though and thus leak memory. Fix those. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jun 11, 2024 at 11:19 UTC 14da26230a7644a2f9dfbc3f43d9d7ab6e0074e9
21 files changed +41 -11
apply.c
+1
@@ -135,6 +135,7 @@ void clear_apply_state(struct apply_state *state)
135 strset_clear(&state->removed_symlinks);
136 strset_clear(&state->kept_symlinks);
137 strbuf_release(&state->root);
138 + FREE_AND_NULL(state->fake_ancestor);
139
140 /* &state->fn_table is cleared at the end of apply_patch() */
141 }
apply.h
+1 -1
@@ -59,7 +59,7 @@ struct apply_state {
59 struct repository *repo;
60 const char *index_file;
61 enum apply_verbosity apply_verbosity;
62 - const char *fake_ancestor;
62 + char *fake_ancestor;
63 const char *patch_input_file;
64 int line_termination;
65 struct strbuf root;
builtin/archive.c
+5 -2
@@ -92,6 +92,7 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
92 N_("path to the remote git-upload-archive command")),
93 OPT_END()
94 };
95 + int ret;
96
97 argc = parse_options(argc, argv, prefix, local_opts, NULL,
98 PARSE_OPT_KEEP_ALL);
@@ -106,6 +107,8 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
107
108 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
109
109 - UNLEAK(output);
110 - return write_archive(argc, argv, prefix, the_repository, output, 0);
110 + ret = write_archive(argc, argv, prefix, the_repository, output, 0);
111 +
112 + free(output);
113 + return ret;
114 }
builtin/commit.c
+5 -2
@@ -106,7 +106,8 @@ static enum {
106 COMMIT_PARTIAL
107 } commit_style;
108
109 -static const char *logfile, *force_author;
109 +static const char *force_author;
110 +static char *logfile;
111 static char *template_file;
112 /*
113 * The _message variables are commit names from which to take
@@ -1309,7 +1310,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
1310 !!use_message, "-C",
1311 !!logfile, "-F");
1312 if (use_message || edit_message || logfile ||fixup_message || have_option_m)
1312 - template_file = NULL;
1313 + FREE_AND_NULL(template_file);
1314 if (edit_message)
1315 use_message = edit_message;
1316 if (amend && !use_message && !fixup_message)
@@ -1892,5 +1893,7 @@ cleanup:
1893 strbuf_release(&author_ident);
1894 strbuf_release(&err);
1895 strbuf_release(&sb);
1896 + free(logfile);
1897 + free(template_file);
1898 return ret;
1899 }
builtin/fmt-merge-msg.c
+3 -1
@@ -11,7 +11,7 @@ static const char * const fmt_merge_msg_usage[] = {
11
12 int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
13 {
14 - const char *inpath = NULL;
14 + char *inpath = NULL;
15 const char *message = NULL;
16 char *into_name = NULL;
17 int shortlog_len = -1;
@@ -66,5 +66,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
66 if (ret)
67 return ret;
68 write_in_full(STDOUT_FILENO, output.buf, output.len);
69 +
70 + free(inpath);
71 return 0;
72 }
builtin/log.c
+3 -1
@@ -2021,7 +2021,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
2021 const char *rfc = NULL;
2022 int creation_factor = -1;
2023 const char *signature = git_version_string;
2024 - const char *signature_file_arg = NULL;
2024 + char *signature_file_arg = NULL;
2025 struct keep_callback_data keep_callback_data = {
2026 .cfg = &cfg,
2027 .revs = &rev,
@@ -2559,6 +2559,8 @@ done:
2559 strbuf_release(&rdiff1);
2560 strbuf_release(&rdiff2);
2561 strbuf_release(&rdiff_title);
2562 + free(description_file);
2563 + free(signature_file_arg);
2564 free(to_free);
2565 free(rev.message_id);
2566 if (rev.ref_message_ids)
builtin/multi-pack-index.c
+9 -4
@@ -50,7 +50,7 @@ static char const * const builtin_multi_pack_index_usage[] = {
50 static struct opts_multi_pack_index {
51 char *object_dir;
52 const char *preferred_pack;
53 - const char *refs_snapshot;
53 + char *refs_snapshot;
54 unsigned long batch_size;
55 unsigned flags;
56 int stdin_packs;
@@ -135,6 +135,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
135 N_("refs snapshot for selecting bitmap commits")),
136 OPT_END(),
137 };
138 + int ret;
139
140 opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
141
@@ -157,7 +158,6 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
158
159 if (opts.stdin_packs) {
160 struct string_list packs = STRING_LIST_INIT_DUP;
160 - int ret;
161
162 read_packs_from_stdin(&packs);
163
@@ -166,12 +166,17 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
166 opts.refs_snapshot, opts.flags);
167
168 string_list_clear(&packs, 0);
169 + free(opts.refs_snapshot);
170
171 return ret;
172
173 }
173 - return write_midx_file(opts.object_dir, opts.preferred_pack,
174 - opts.refs_snapshot, opts.flags);
174 +
175 + ret = write_midx_file(opts.object_dir, opts.preferred_pack,
176 + opts.refs_snapshot, opts.flags);
177 +
178 + free(opts.refs_snapshot);
179 + return ret;
180 }
181
182 static int cmd_multi_pack_index_verify(int argc, const char **argv,
builtin/sparse-checkout.c
+1
@@ -1011,6 +1011,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
1011
1012 ret = check_rules(&pl, check_rules_opts.null_termination);
1013 clear_pattern_list(&pl);
1014 + free(check_rules_opts.rules_file);
1015 return ret;
1016 }
1017
t/helper/test-parse-options.c
+1
@@ -207,6 +207,7 @@ int cmd__parse_options(int argc, const char **argv)
207 expect.strdup_strings = 1;
208 string_list_clear(&expect, 0);
209 string_list_clear(&list, 0);
210 + free(file);
211
212 return ret;
213 }
t/t1512-rev-parse-disambiguation.sh
+1
@@ -23,6 +23,7 @@ one tagged as v1.0.0. They all have one regular file each.
23 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
24 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
25
26 +TEST_PASSES_SANITIZE_LEAK=true
27 . ./test-lib.sh
28
29 test_cmp_failed_rev_parse () {
t/t2500-untracked-overwriting.sh
+1
@@ -2,6 +2,7 @@
2
3 test_description='Test handling of overwriting untracked files'
4
5 +TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7
8 test_setup_reset () {
t/t3406-rebase-message.sh
+1
@@ -5,6 +5,7 @@ test_description='messages from rebase operation'
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 +TEST_PASSES_SANITIZE_LEAK=true
9 . ./test-lib.sh
10
11 test_expect_success 'setup' '
t/t3407-rebase-abort.sh
+1
@@ -5,6 +5,7 @@ test_description='git rebase --abort tests'
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 +TEST_PASSES_SANITIZE_LEAK=true
9 . ./test-lib.sh
10
11 test_expect_success setup '
t/t3428-rebase-signoff.sh
+1
@@ -5,6 +5,7 @@ test_description='git rebase --signoff
5 This test runs git rebase --signoff and make sure that it works.
6 '
7
8 +TEST_PASSES_SANITIZE_LEAK=true
9 . ./test-lib.sh
10 . "$TEST_DIRECTORY"/lib-rebase.sh
11
t/t4131-apply-fake-ancestor.sh
+1
@@ -5,6 +5,7 @@
5
6 test_description='git apply --build-fake-ancestor handling.'
7
8 +TEST_PASSES_SANITIZE_LEAK=true
9 . ./test-lib.sh
10
11 test_expect_success 'setup' '
t/t4151-am-abort.sh
+1
@@ -2,6 +2,7 @@
2
3 test_description='am --abort'
4
5 +TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7
8 test_expect_success setup '
t/t4253-am-keep-cr-dos.sh
+1
@@ -9,6 +9,7 @@ test_description='git-am mbox with dos line ending.
9 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
10 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
11
12 +TEST_PASSES_SANITIZE_LEAK=true
13 . ./test-lib.sh
14
15 # Three patches which will be added as files with dos line ending.
t/t4255-am-submodule.sh
+1
@@ -2,6 +2,7 @@
2
3 test_description='git am handling submodules'
4
5 +TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7 . "$TEST_DIRECTORY"/lib-submodule-update.sh
8
t/t5407-post-rewrite-hook.sh
+1
@@ -7,6 +7,7 @@ test_description='Test the post-rewrite hook.'
7 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
8 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
9
10 +TEST_PASSES_SANITIZE_LEAK=true
11 . ./test-lib.sh
12
13 test_expect_success 'setup' '
t/t6427-diff3-conflict-markers.sh
+1
@@ -5,6 +5,7 @@ test_description='recursive merge diff3 style conflict markers'
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 +TEST_PASSES_SANITIZE_LEAK=true
9 . ./test-lib.sh
10
11 # Setup:
t/t7512-status-help.sh
+1
@@ -10,6 +10,7 @@ test_description='git status advice'
10 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
11 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
12
13 +TEST_PASSES_SANITIZE_LEAK=true
14 . ./test-lib.sh
15
16 . "$TEST_DIRECTORY"/lib-rebase.sh