Skip to content

Commit 2f64da0

Browse files
rjustogitster
authored andcommitted
checkout: plug some leaks in git-restore
In git-restore we need to free the pathspec and pathspec_from_file values from the struct checkout_opts. A simple fix could be to free them in cmd_restore, after the call to checkout_main returns, like we are doing [1][2] in the sibling function cmd_checkout. However, we can do even better. We have git-switch and git-restore, both of them spin-offs[3][4] of git-checkout. All three are implemented as thin wrappers around checkout_main. Considering this, it makes a lot of sense to do the cleanup closer to checkout_main. Move the cleanups, including the new_branch_info variable, to checkout_main. As a consequence, mark: t2070, t2071, t2072 and t6418 as leak-free. [1] 9081a42 (checkout: fix "branch info" memory leaks, 2021-11-16) [2] 7ce4088 (parse-options: consistently allocate memory in fix_filename(), 2023-03-04) [3] d787d31 (checkout: split part of it to new command 'switch', 2019-03-29) [4] 46e91b6 (checkout: split part of it to new command 'restore', 2019-04-25) Signed-off-by: Rubén Justo <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3c2a3fd commit 2f64da0

File tree

5 files changed

+25
-30
lines changed

5 files changed

+25
-30
lines changed

builtin/checkout.c

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,10 +1687,11 @@ static char cb_option = 'b';
16871687

16881688
static int checkout_main(int argc, const char **argv, const char *prefix,
16891689
struct checkout_opts *opts, struct option *options,
1690-
const char * const usagestr[],
1691-
struct branch_info *new_branch_info)
1690+
const char * const usagestr[])
16921691
{
16931692
int parseopt_flags = 0;
1693+
struct branch_info new_branch_info = { 0 };
1694+
int ret;
16941695

16951696
opts->overwrite_ignore = 1;
16961697
opts->prefix = prefix;
@@ -1806,7 +1807,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
18061807
opts->track == BRANCH_TRACK_UNSPECIFIED &&
18071808
!opts->new_branch;
18081809
int n = parse_branchname_arg(argc, argv, dwim_ok,
1809-
new_branch_info, opts, &rev);
1810+
&new_branch_info, opts, &rev);
18101811
argv += n;
18111812
argc -= n;
18121813
} else if (!opts->accept_ref && opts->from_treeish) {
@@ -1815,7 +1816,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
18151816
if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))
18161817
die(_("could not resolve %s"), opts->from_treeish);
18171818

1818-
setup_new_branch_info_and_source_tree(new_branch_info,
1819+
setup_new_branch_info_and_source_tree(&new_branch_info,
18191820
opts, &rev,
18201821
opts->from_treeish);
18211822

@@ -1835,7 +1836,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
18351836
* Try to give more helpful suggestion.
18361837
* new_branch && argc > 1 will be caught later.
18371838
*/
1838-
if (opts->new_branch && argc == 1 && !new_branch_info->commit)
1839+
if (opts->new_branch && argc == 1 && !new_branch_info.commit)
18391840
die(_("'%s' is not a commit and a branch '%s' cannot be created from it"),
18401841
argv[0], opts->new_branch);
18411842

@@ -1885,9 +1886,16 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
18851886
}
18861887

18871888
if (opts->patch_mode || opts->pathspec.nr)
1888-
return checkout_paths(opts, new_branch_info);
1889+
ret = checkout_paths(opts, &new_branch_info);
18891890
else
1890-
return checkout_branch(opts, new_branch_info);
1891+
ret = checkout_branch(opts, &new_branch_info);
1892+
1893+
branch_info_release(&new_branch_info);
1894+
clear_pathspec(&opts->pathspec);
1895+
free(opts->pathspec_from_file);
1896+
free(options);
1897+
1898+
return ret;
18911899
}
18921900

18931901
int cmd_checkout(int argc, const char **argv, const char *prefix)
@@ -1905,8 +1913,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
19051913
OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode (default)")),
19061914
OPT_END()
19071915
};
1908-
int ret;
1909-
struct branch_info new_branch_info = { 0 };
19101916

19111917
memset(&opts, 0, sizeof(opts));
19121918
opts.dwim_new_local_branch = 1;
@@ -1936,13 +1942,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
19361942
options = add_common_switch_branch_options(&opts, options);
19371943
options = add_checkout_path_options(&opts, options);
19381944

1939-
ret = checkout_main(argc, argv, prefix, &opts,
1940-
options, checkout_usage, &new_branch_info);
1941-
branch_info_release(&new_branch_info);
1942-
clear_pathspec(&opts.pathspec);
1943-
free(opts.pathspec_from_file);
1944-
FREE_AND_NULL(options);
1945-
return ret;
1945+
return checkout_main(argc, argv, prefix, &opts, options,
1946+
checkout_usage);
19461947
}
19471948

19481949
int cmd_switch(int argc, const char **argv, const char *prefix)
@@ -1960,8 +1961,6 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
19601961
N_("throw away local modifications")),
19611962
OPT_END()
19621963
};
1963-
int ret;
1964-
struct branch_info new_branch_info = { 0 };
19651964

19661965
memset(&opts, 0, sizeof(opts));
19671966
opts.dwim_new_local_branch = 1;
@@ -1980,11 +1979,8 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
19801979

19811980
cb_option = 'c';
19821981

1983-
ret = checkout_main(argc, argv, prefix, &opts,
1984-
options, switch_branch_usage, &new_branch_info);
1985-
branch_info_release(&new_branch_info);
1986-
FREE_AND_NULL(options);
1987-
return ret;
1982+
return checkout_main(argc, argv, prefix, &opts, options,
1983+
switch_branch_usage);
19881984
}
19891985

19901986
int cmd_restore(int argc, const char **argv, const char *prefix)
@@ -2003,8 +1999,6 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
20031999
OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode")),
20042000
OPT_END()
20052001
};
2006-
int ret;
2007-
struct branch_info new_branch_info = { 0 };
20082002

20092003
memset(&opts, 0, sizeof(opts));
20102004
opts.accept_ref = 0;
@@ -2019,9 +2013,6 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
20192013
options = add_common_options(&opts, options);
20202014
options = add_checkout_path_options(&opts, options);
20212015

2022-
ret = checkout_main(argc, argv, prefix, &opts,
2023-
options, restore_usage, &new_branch_info);
2024-
branch_info_release(&new_branch_info);
2025-
FREE_AND_NULL(options);
2026-
return ret;
2016+
return checkout_main(argc, argv, prefix, &opts, options,
2017+
restore_usage);
20272018
}

t/t2070-restore.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ test_description='restore basic functionality'
55
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
66
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
77

8+
TEST_PASSES_SANITIZE_LEAK=true
89
. ./test-lib.sh
910

1011
test_expect_success 'setup' '

t/t2071-restore-patch.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
test_description='git restore --patch'
44

5+
TEST_PASSES_SANITIZE_LEAK=true
56
. ./lib-patch-mode.sh
67

78
test_expect_success PERL 'setup' '

t/t2072-restore-pathspec-file.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
test_description='restore --pathspec-from-file'
44

5+
TEST_PASSES_SANITIZE_LEAK=true
56
. ./test-lib.sh
67

78
test_tick

t/t6418-merge-text-auto.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ test_description='CRLF merge conflict across text=auto change
1515
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
1616
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
1717

18+
TEST_PASSES_SANITIZE_LEAK=true
1819
. ./test-lib.sh
1920

2021
test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b

0 commit comments

Comments
 (0)