On Tue, Dec 18, 2018 at 08:25:28AM +0100, Martin Ågren wrote: > After we set up a `struct repository_format`, it owns various pieces of > allocated memory. We then either use those members, because we decide we > want to use the "candidate" repository format, or we discard the > candidate / scratch space. In the first case, we transfer ownership of > the memory to a few global variables. In the latter case, we just > silently drop the struct and end up leaking memory. > > Introduce a function `clear_repository_format()` which frees the memory > the struct holds on to. Call it in the code paths where we currently > leak the memory. Also call it in the error path of > `read_repository_format()` to clean up any partial result. > > For hygiene, we need to at least set the pointers that we free to NULL. > For future-proofing, let's zero the entire struct instead. It just means > that in the error path of `read_...()` we need to restore the error > sentinel in the `version` field. This seems reasonable, and I very much agree on the zero-ing (even though it _shouldn't_ matter due to the "undefined" rule). That also makes it safe to clear() multiple times, which is a nice property. > +void clear_repository_format(struct repository_format *format) > +{ > + string_list_clear(&format->unknown_extensions, 0); > + free(format->work_tree); > + free(format->partial_clone); > + memset(format, 0, sizeof(*format)); > } For the callers that actually pick the values out, I think it might be a little less error-prone if they actually copied the strings and then called clear_repository_format(). That avoids leaks of values that they didn't know or care about (and the cost of an extra strdup for repository setup is not a big deal). Something like this on top of your patch, I guess (with the idea being that functions which return an error would clear the format, but a "successful" one would get returned back up the stack to setup_git_directory_gently(), which then clears it before returning. -- >8 -- diff --git a/setup.c b/setup.c index babe5ea156..a5699f9ee6 100644 --- a/setup.c +++ b/setup.c @@ -470,6 +470,7 @@ static int check_repository_format_gently(const char *gitdir, struct repository_ warning("%s", err.buf); strbuf_release(&err); *nongit_ok = -1; + clear_repository_format(candidate); return -1; } die("%s", err.buf); @@ -499,7 +500,7 @@ static int check_repository_format_gently(const char *gitdir, struct repository_ } if (candidate->work_tree) { free(git_work_tree_cfg); - git_work_tree_cfg = candidate->work_tree; + git_work_tree_cfg = xstrdup(candidate->work_tree); inside_work_tree = -1; } } else { @@ -1158,6 +1159,7 @@ const char *setup_git_directory_gently(int *nongit_ok) strbuf_release(&dir); strbuf_release(&gitdir); + clear_repository_format(&repo_fmt); return prefix; } -Peff