diff options
author | Elijah Newren <newren@gmail.com> | 2020-08-19 00:58:26 +0200 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2020-08-19 02:17:31 +0200 |
commit | eceba5321410bbcc9e0b11e6aa479832f574eca8 (patch) | |
tree | cd31d4f411acc27ef42499dc5331c683fe022a90 /dir.c | |
parent | dir: make clear_directory() free all relevant memory (diff) | |
download | git-eceba5321410bbcc9e0b11e6aa479832f574eca8.tar.xz git-eceba5321410bbcc9e0b11e6aa479832f574eca8.zip |
dir: fix problematic API to avoid memory leaks
The dir structure seemed to have a number of leaks and problems around
it. First I noticed that parent_hashmap and recursive_hashmap were
being leaked (though Peff noticed and submitted fixes before me). Then
I noticed in the previous commit that clear_directory() was only taking
responsibility for a subset of fields within dir_struct, despite the
fact that entries[] and ignored[] we allocated internally to dir.c.
That, of course, resulted in many callers either leaking or haphazardly
trying to free these arrays and their contents.
Digging further, I found that despite the pretty clear documentation
near the top of dir.h that folks were supposed to call clear_directory()
when the user no longer needed the dir_struct, there were four callers
that didn't bother doing that at all. However, two of them clearly
thought about leaks since they had an UNLEAK(dir) directive, which to me
suggests that the method to free the data was too unclear. I suspect
the non-obviousness of the API and its holes led folks to avoid it,
which then snowballed into further problems with the entries[],
ignored[], parent_hashmap, and recursive_hashmap problems.
Rename clear_directory() to dir_clear() to be more in line with other
data structures in git, and introduce a dir_init() to handle the
suggested memsetting of dir_struct to all zeroes. I hope that a name
like "dir_clear()" is more clear, and that the presence of dir_init()
will provide a hint to those looking at the code that they need to look
for either a dir_clear() or a dir_free() and lead them to find
dir_clear().
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'dir.c')
-rw-r--r-- | dir.c | 9 |
1 files changed, 7 insertions, 2 deletions
@@ -54,6 +54,11 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, static int resolve_dtype(int dtype, struct index_state *istate, const char *path, int len); +void dir_init(struct dir_struct *dir) +{ + memset(dir, 0, sizeof(*dir)); +} + int count_slashes(const char *s) { int cnt = 0; @@ -3012,7 +3017,7 @@ int remove_path(const char *name) * Frees memory within dir which was allocated, and resets fields for further * use. Does not free dir itself. */ -void clear_directory(struct dir_struct *dir) +void dir_clear(struct dir_struct *dir) { int i, j; struct exclude_list_group *group; @@ -3045,7 +3050,7 @@ void clear_directory(struct dir_struct *dir) } strbuf_release(&dir->basebuf); - memset(&dir, 0, sizeof(*dir)); + dir_init(dir); } struct ondisk_untracked_cache { |