mirror of
https://github.com/git/git
synced 2024-11-05 01:58:18 +00:00
Merge branch 'jk/sparse-leakfix'
Many memory leaks in the sparse-checkout code paths have been plugged. * jk/sparse-leakfix: sparse-checkout: free duplicate hashmap entries sparse-checkout: free string list after displaying sparse-checkout: free pattern list in sparse_checkout_list() sparse-checkout: free sparse_filename after use sparse-checkout: refactor temporary sparse_checkout_patterns sparse-checkout: always free "line" strbuf after reading input sparse-checkout: reuse --stdin buffer when reading patterns dir.c: always copy input to add_pattern() dir.c: free removed sparse-pattern hashmap entries sparse-checkout: clear patterns when init() sees existing sparse file dir.c: free strings in sparse cone pattern hashmaps sparse-checkout: pass string literals directly to add_pattern() sparse-checkout: free string list in write_cone_to_file()
This commit is contained in:
commit
51ea70c18a
7 changed files with 65 additions and 36 deletions
|
@ -96,10 +96,11 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
string_list_clear(&sl, 0);
|
||||
} else {
|
||||
write_patterns_to_file(stdout, &pl);
|
||||
}
|
||||
|
||||
write_patterns_to_file(stdout, &pl);
|
||||
clear_pattern_list(&pl);
|
||||
|
||||
return 0;
|
||||
|
@ -205,11 +206,13 @@ static int update_working_directory(struct pattern_list *pl)
|
|||
struct unpack_trees_options o;
|
||||
struct lock_file lock_file = LOCK_INIT;
|
||||
struct repository *r = the_repository;
|
||||
struct pattern_list *old_pl;
|
||||
|
||||
/* If no branch has been checked out, there are no updates to make. */
|
||||
if (is_index_unborn(r->index))
|
||||
return UPDATE_SPARSITY_SUCCESS;
|
||||
|
||||
old_pl = r->index->sparse_checkout_patterns;
|
||||
r->index->sparse_checkout_patterns = pl;
|
||||
|
||||
memset(&o, 0, sizeof(o));
|
||||
|
@ -241,7 +244,12 @@ static int update_working_directory(struct pattern_list *pl)
|
|||
|
||||
clean_tracked_sparse_directories(r);
|
||||
|
||||
r->index->sparse_checkout_patterns = NULL;
|
||||
if (r->index->sparse_checkout_patterns != pl) {
|
||||
clear_pattern_list(r->index->sparse_checkout_patterns);
|
||||
FREE_AND_NULL(r->index->sparse_checkout_patterns);
|
||||
}
|
||||
r->index->sparse_checkout_patterns = old_pl;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -311,6 +319,8 @@ static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
|
|||
fprintf(fp, "%s/\n", pattern);
|
||||
free(pattern);
|
||||
}
|
||||
|
||||
string_list_clear(&sl, 0);
|
||||
}
|
||||
|
||||
static int write_patterns_and_update(struct pattern_list *pl)
|
||||
|
@ -440,7 +450,6 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
|
|||
char *sparse_filename;
|
||||
int res;
|
||||
struct object_id oid;
|
||||
struct strbuf pattern = STRBUF_INIT;
|
||||
|
||||
static struct option builtin_sparse_checkout_init_options[] = {
|
||||
OPT_BOOL(0, "cone", &init_opts.cone_mode,
|
||||
|
@ -471,6 +480,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
|
|||
/* If we already have a sparse-checkout file, use it. */
|
||||
if (res >= 0) {
|
||||
free(sparse_filename);
|
||||
clear_pattern_list(&pl);
|
||||
return update_working_directory(NULL);
|
||||
}
|
||||
|
||||
|
@ -491,10 +501,10 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
|
|||
return 0;
|
||||
}
|
||||
|
||||
strbuf_addstr(&pattern, "/*");
|
||||
add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
|
||||
strbuf_addstr(&pattern, "!/*/");
|
||||
add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
|
||||
free(sparse_filename);
|
||||
|
||||
add_pattern("/*", empty_base, 0, &pl, 0);
|
||||
add_pattern("!/*/", empty_base, 0, &pl, 0);
|
||||
pl.use_cone_patterns = init_opts.cone_mode;
|
||||
|
||||
return write_patterns_and_update(&pl);
|
||||
|
@ -513,6 +523,7 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
|
|||
char *slash = strrchr(e->pattern, '/');
|
||||
char *oldpattern = e->pattern;
|
||||
size_t newlen;
|
||||
struct pattern_entry *dup;
|
||||
|
||||
if (!slash || slash == e->pattern)
|
||||
break;
|
||||
|
@ -523,8 +534,14 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
|
|||
e->pattern = xstrndup(oldpattern, newlen);
|
||||
hashmap_entry_init(&e->ent, fspathhash(e->pattern));
|
||||
|
||||
if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
|
||||
dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
|
||||
if (!dup) {
|
||||
hashmap_add(&pl->parent_hashmap, &e->ent);
|
||||
} else {
|
||||
free(e->pattern);
|
||||
free(e);
|
||||
e = dup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -581,15 +598,15 @@ static void add_patterns_from_input(struct pattern_list *pl,
|
|||
strbuf_to_cone_pattern(&line, pl);
|
||||
}
|
||||
}
|
||||
strbuf_release(&line);
|
||||
} else {
|
||||
if (file) {
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
|
||||
while (!strbuf_getline(&line, file)) {
|
||||
size_t len;
|
||||
char *buf = strbuf_detach(&line, &len);
|
||||
add_pattern(buf, empty_base, 0, pl, 0);
|
||||
}
|
||||
while (!strbuf_getline(&line, file))
|
||||
add_pattern(line.buf, empty_base, 0, pl, 0);
|
||||
|
||||
strbuf_release(&line);
|
||||
} else {
|
||||
for (i = 0; i < argc; i++)
|
||||
add_pattern(argv[i], empty_base, 0, pl, 0);
|
||||
|
@ -891,7 +908,6 @@ static int sparse_checkout_disable(int argc, const char **argv,
|
|||
OPT_END(),
|
||||
};
|
||||
struct pattern_list pl;
|
||||
struct strbuf match_all = STRBUF_INIT;
|
||||
|
||||
/*
|
||||
* We do not exit early if !core_apply_sparse_checkout; due to the
|
||||
|
@ -917,8 +933,7 @@ static int sparse_checkout_disable(int argc, const char **argv,
|
|||
pl.use_cone_patterns = 0;
|
||||
core_apply_sparse_checkout = 1;
|
||||
|
||||
strbuf_addstr(&match_all, "/*");
|
||||
add_pattern(strbuf_detach(&match_all, NULL), empty_base, 0, &pl, 0);
|
||||
add_pattern("/*", empty_base, 0, &pl, 0);
|
||||
|
||||
prepare_repo_settings(the_repository);
|
||||
the_repository->settings.sparse_index = 0;
|
||||
|
|
42
dir.c
42
dir.c
|
@ -733,6 +733,17 @@ static char *dup_and_filter_pattern(const char *pattern)
|
|||
return result;
|
||||
}
|
||||
|
||||
static void clear_pattern_entry_hashmap(struct hashmap *map)
|
||||
{
|
||||
struct hashmap_iter iter;
|
||||
struct pattern_entry *entry;
|
||||
|
||||
hashmap_for_each_entry(map, &iter, entry, ent) {
|
||||
free(entry->pattern);
|
||||
}
|
||||
hashmap_clear_and_free(map, struct pattern_entry, ent);
|
||||
}
|
||||
|
||||
static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern *given)
|
||||
{
|
||||
struct pattern_entry *translated;
|
||||
|
@ -806,6 +817,8 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
|
|||
|
||||
if (given->patternlen > 2 &&
|
||||
!strcmp(given->pattern + given->patternlen - 2, "/*")) {
|
||||
struct pattern_entry *old;
|
||||
|
||||
if (!(given->flags & PATTERN_FLAG_NEGATIVE)) {
|
||||
/* Not a cone pattern. */
|
||||
warning(_("unrecognized pattern: '%s'"), given->pattern);
|
||||
|
@ -831,7 +844,11 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
|
|||
}
|
||||
|
||||
hashmap_add(&pl->parent_hashmap, &translated->ent);
|
||||
hashmap_remove(&pl->recursive_hashmap, &translated->ent, &data);
|
||||
old = hashmap_remove_entry(&pl->recursive_hashmap, translated, ent, &data);
|
||||
if (old) {
|
||||
free(old->pattern);
|
||||
free(old);
|
||||
}
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
|
@ -862,8 +879,8 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
|
|||
|
||||
clear_hashmaps:
|
||||
warning(_("disabling cone pattern matching"));
|
||||
hashmap_clear_and_free(&pl->parent_hashmap, struct pattern_entry, ent);
|
||||
hashmap_clear_and_free(&pl->recursive_hashmap, struct pattern_entry, ent);
|
||||
clear_pattern_entry_hashmap(&pl->recursive_hashmap);
|
||||
clear_pattern_entry_hashmap(&pl->parent_hashmap);
|
||||
pl->use_cone_patterns = 0;
|
||||
}
|
||||
|
||||
|
@ -915,12 +932,7 @@ void add_pattern(const char *string, const char *base,
|
|||
int nowildcardlen;
|
||||
|
||||
parse_path_pattern(&string, &patternlen, &flags, &nowildcardlen);
|
||||
if (flags & PATTERN_FLAG_MUSTBEDIR) {
|
||||
FLEXPTR_ALLOC_MEM(pattern, pattern, string, patternlen);
|
||||
} else {
|
||||
pattern = xmalloc(sizeof(*pattern));
|
||||
pattern->pattern = string;
|
||||
}
|
||||
FLEX_ALLOC_MEM(pattern, pattern, string, patternlen);
|
||||
pattern->patternlen = patternlen;
|
||||
pattern->nowildcardlen = nowildcardlen;
|
||||
pattern->base = base;
|
||||
|
@ -962,9 +974,8 @@ void clear_pattern_list(struct pattern_list *pl)
|
|||
for (i = 0; i < pl->nr; i++)
|
||||
free(pl->patterns[i]);
|
||||
free(pl->patterns);
|
||||
free(pl->filebuf);
|
||||
hashmap_clear_and_free(&pl->recursive_hashmap, struct pattern_entry, ent);
|
||||
hashmap_clear_and_free(&pl->parent_hashmap, struct pattern_entry, ent);
|
||||
clear_pattern_entry_hashmap(&pl->recursive_hashmap);
|
||||
clear_pattern_entry_hashmap(&pl->parent_hashmap);
|
||||
|
||||
memset(pl, 0, sizeof(*pl));
|
||||
}
|
||||
|
@ -1162,6 +1173,7 @@ static int add_patterns(const char *fname, const char *base, int baselen,
|
|||
}
|
||||
|
||||
add_patterns_from_buffer(buf, size, base, baselen, pl);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1169,16 +1181,15 @@ static int add_patterns_from_buffer(char *buf, size_t size,
|
|||
const char *base, int baselen,
|
||||
struct pattern_list *pl)
|
||||
{
|
||||
char *orig = buf;
|
||||
int i, lineno = 1;
|
||||
char *entry;
|
||||
|
||||
hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
|
||||
hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
|
||||
|
||||
pl->filebuf = buf;
|
||||
|
||||
if (skip_utf8_bom(&buf, size))
|
||||
size -= buf - pl->filebuf;
|
||||
size -= buf - orig;
|
||||
|
||||
entry = buf;
|
||||
|
||||
|
@ -1225,6 +1236,7 @@ int add_patterns_from_blob_to_list(
|
|||
}
|
||||
|
||||
add_patterns_from_buffer(buf, size, base, baselen, pl);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
6
dir.h
6
dir.h
|
@ -62,7 +62,6 @@ struct path_pattern {
|
|||
*/
|
||||
struct pattern_list *pl;
|
||||
|
||||
const char *pattern;
|
||||
int patternlen;
|
||||
int nowildcardlen;
|
||||
const char *base;
|
||||
|
@ -74,6 +73,8 @@ struct path_pattern {
|
|||
* and from -1 decrementing for patterns from CLI args.
|
||||
*/
|
||||
int srcpos;
|
||||
|
||||
char pattern[FLEX_ARRAY];
|
||||
};
|
||||
|
||||
/* used for hashmaps for cone patterns */
|
||||
|
@ -94,9 +95,6 @@ struct pattern_list {
|
|||
int nr;
|
||||
int alloc;
|
||||
|
||||
/* remember pointer to exclude file contents so we can free() */
|
||||
char *filebuf;
|
||||
|
||||
/* origin of list, e.g. path to filename, or descriptive string */
|
||||
const char *src;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
|||
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
||||
|
||||
TEST_CREATE_REPO_NO_TEMPLATE=1
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
|
|
|
@ -8,6 +8,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
|||
GIT_TEST_SPLIT_INDEX=false
|
||||
export GIT_TEST_SPLIT_INDEX
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
list_files() {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
test_description='git rm in sparse checked out working trees'
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' "
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
test_description='git mv in sparse working trees'
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
setup_sparse_checkout () {
|
||||
|
|
Loading…
Reference in a new issue