Skip to content

Commit 6d10775

Browse files
peffgitster
authored andcommitted
sparse-checkout: free duplicate hashmap entries
In insert_recursive_pattern(), we create a new pattern_entry to insert into the parent_hashmap. If we find that the same entry already exists in the hashmap, we skip adding the new one. But we forget to free the new one, creating a leak. We can fix it by cleaning up the discarded entry. It would probably be possible to avoid creating it in the first place, but it's non-trivial. We'd have to define a "keydata" struct that lets us compare the existing entries to the broken-out fields. It's probably not worth the complexity, so we'll punt on that for now. There is one subtlety here: our insertion is happening in a loop, with each iteration looking at the pattern we just inserted (hence the "recursive" in the name). So if we skip insertion, what do we look at? The obvious answer is that we should remember the existing duplicate we found and use that. But I _think_ in that case, we probably already have all of the recursive bits already (from when the original entry was added). And so just breaking out of the loop would be correct. But I'm not 100% sure on that; after all, the original leaky code could have done the same break, but it didn't. So I went with the "obvious answer" above, which has no chance of changing the behavior aside from fixing the leak. With this patch, t1091 can now be marked leak-free. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a544b7d commit 6d10775

File tree

2 files changed

+9
-1
lines changed

2 files changed

+9
-1
lines changed

builtin/sparse-checkout.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
523523
char *slash = strrchr(e->pattern, '/');
524524
char *oldpattern = e->pattern;
525525
size_t newlen;
526+
struct pattern_entry *dup;
526527

527528
if (!slash || slash == e->pattern)
528529
break;
@@ -533,8 +534,14 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
533534
e->pattern = xstrndup(oldpattern, newlen);
534535
hashmap_entry_init(&e->ent, fspathhash(e->pattern));
535536

536-
if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
537+
dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
538+
if (!dup) {
537539
hashmap_add(&pl->parent_hashmap, &e->ent);
540+
} else {
541+
free(e->pattern);
542+
free(e);
543+
e = dup;
544+
}
538545
}
539546
}
540547

t/t1091-sparse-checkout-builtin.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
88
GIT_TEST_SPLIT_INDEX=false
99
export GIT_TEST_SPLIT_INDEX
1010

11+
TEST_PASSES_SANITIZE_LEAK=true
1112
. ./test-lib.sh
1213

1314
list_files() {

0 commit comments

Comments
 (0)