1
0
mirror of https://github.com/git/git.git synced 2024-11-08 15:19:28 +01:00

builtin/merge: fix leaking struct cmdnames in get_strategy()

In "builtin/merge.c" we use the helper infrastructure to figure out what
merge strategies there are. We never free contents of the `cmdnames`
structures though and thus leak their memory.

Fix this by exposing the already existing `clean_cmdnames()` function to
release their memory. As this name isn't quite idiomatic, rename it to
`cmdnames_release()` while at it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt 2024-06-11 11:21:06 +02:00 committed by Junio C Hamano
parent 6e95f4ee03
commit 77241a6b5e
4 changed files with 16 additions and 9 deletions

@ -164,7 +164,7 @@ static struct strategy *get_strategy(const char *name)
{ {
int i; int i;
struct strategy *ret; struct strategy *ret;
static struct cmdnames main_cmds, other_cmds; static struct cmdnames main_cmds = {0}, other_cmds = {0};
static int loaded; static int loaded;
char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM"); char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
@ -182,10 +182,9 @@ static struct strategy *get_strategy(const char *name)
return &all_strategy[i]; return &all_strategy[i];
if (!loaded) { if (!loaded) {
struct cmdnames not_strategies; struct cmdnames not_strategies = {0};
loaded = 1; loaded = 1;
memset(&not_strategies, 0, sizeof(struct cmdnames));
load_command_list("git-merge-", &main_cmds, &other_cmds); load_command_list("git-merge-", &main_cmds, &other_cmds);
for (i = 0; i < main_cmds.cnt; i++) { for (i = 0; i < main_cmds.cnt; i++) {
int j, found = 0; int j, found = 0;
@ -197,6 +196,8 @@ static struct strategy *get_strategy(const char *name)
add_cmdname(&not_strategies, ent->name, ent->len); add_cmdname(&not_strategies, ent->name, ent->len);
} }
exclude_cmds(&main_cmds, &not_strategies); exclude_cmds(&main_cmds, &not_strategies);
cmdnames_release(&not_strategies);
} }
if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) { if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) {
fprintf(stderr, _("Could not find merge strategy '%s'.\n"), name); fprintf(stderr, _("Could not find merge strategy '%s'.\n"), name);
@ -216,6 +217,9 @@ static struct strategy *get_strategy(const char *name)
CALLOC_ARRAY(ret, 1); CALLOC_ARRAY(ret, 1);
ret->name = xstrdup(name); ret->name = xstrdup(name);
ret->attr = NO_TRIVIAL; ret->attr = NO_TRIVIAL;
cmdnames_release(&main_cmds);
cmdnames_release(&other_cmds);
return ret; return ret;
} }

12
help.c

@ -157,7 +157,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len)
cmds->names[cmds->cnt++] = ent; cmds->names[cmds->cnt++] = ent;
} }
static void clean_cmdnames(struct cmdnames *cmds) void cmdnames_release(struct cmdnames *cmds)
{ {
int i; int i;
for (i = 0; i < cmds->cnt; ++i) for (i = 0; i < cmds->cnt; ++i)
@ -359,8 +359,8 @@ void list_all_main_cmds(struct string_list *list)
for (i = 0; i < main_cmds.cnt; i++) for (i = 0; i < main_cmds.cnt; i++)
string_list_append(list, main_cmds.names[i]->name); string_list_append(list, main_cmds.names[i]->name);
clean_cmdnames(&main_cmds); cmdnames_release(&main_cmds);
clean_cmdnames(&other_cmds); cmdnames_release(&other_cmds);
} }
void list_all_other_cmds(struct string_list *list) void list_all_other_cmds(struct string_list *list)
@ -375,8 +375,8 @@ void list_all_other_cmds(struct string_list *list)
for (i = 0; i < other_cmds.cnt; i++) for (i = 0; i < other_cmds.cnt; i++)
string_list_append(list, other_cmds.names[i]->name); string_list_append(list, other_cmds.names[i]->name);
clean_cmdnames(&main_cmds); cmdnames_release(&main_cmds);
clean_cmdnames(&other_cmds); cmdnames_release(&other_cmds);
} }
void list_cmds_by_category(struct string_list *list, void list_cmds_by_category(struct string_list *list,
@ -689,7 +689,7 @@ const char *help_unknown_cmd(const char *cmd)
if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) { if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {
const char *assumed = main_cmds.names[0]->name; const char *assumed = main_cmds.names[0]->name;
main_cmds.names[0] = NULL; main_cmds.names[0] = NULL;
clean_cmdnames(&main_cmds); cmdnames_release(&main_cmds);
fprintf_ln(stderr, fprintf_ln(stderr,
_("WARNING: You called a Git command named '%s', " _("WARNING: You called a Git command named '%s', "
"which does not exist."), "which does not exist."),

2
help.h

@ -13,6 +13,8 @@ struct cmdnames {
} **names; } **names;
}; };
void cmdnames_release(struct cmdnames *cmds);
static inline void mput_char(char c, unsigned int num) static inline void mput_char(char c, unsigned int num)
{ {
while (num--) while (num--)

@ -14,6 +14,7 @@ Testing a custom strategy.
* (tag: c0) c0 * (tag: c0) c0
" "
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh . ./test-lib.sh
test_expect_success 'set up custom strategy' ' test_expect_success 'set up custom strategy' '