builtin/commit: fix memory leak in `prepare_index()`

Release `pathspec` and the string list `partial`. When we clear the string list, make sure we do not free the `util` pointers. That would result in double-freeing, since we set them up as `item->util = item` in `list_paths()`. Initialize the string list early, so that we can always release it. That introduces some unnecessary overhead in various code paths, but means there is one and only one way out of the function. If we ever accumulate more things we need to free, it should be straightforward to do so. Signed-off-by: Martin Ågren <martin.agren@gmail.com> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Martin Ågren committed Sep 23, 2017 at 01:34 UTC dd1055ed594f8fef18779cce3cd921c4ac66cf9c
1 file changed +10 -5
builtin/commit.c
+10 -5
@@ -336,7 +336,7 @@ static void refresh_cache_or_die(int refresh_flags)
336 static const char *prepare_index(int argc, const char **argv, const char *prefix,
337 const struct commit *current_head, int is_status)
338 {
339 - struct string_list partial;
339 + struct string_list partial = STRING_LIST_INIT_DUP;
340 struct pathspec pathspec;
341 int refresh_flags = REFRESH_QUIET;
342 const char *ret;
@@ -381,7 +381,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
381 warning(_("Failed to update main cache tree"));
382
383 commit_style = COMMIT_NORMAL;
384 - return get_lock_file_path(&index_lock);
384 + ret = get_lock_file_path(&index_lock);
385 + goto out;
386 }
387
388 /*
@@ -404,7 +405,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
405 if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
406 die(_("unable to write new_index file"));
407 commit_style = COMMIT_NORMAL;
407 - return get_lock_file_path(&index_lock);
408 + ret = get_lock_file_path(&index_lock);
409 + goto out;
410 }
411
412 /*
@@ -430,7 +432,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
432 rollback_lock_file(&index_lock);
433 }
434 commit_style = COMMIT_AS_IS;
433 - return get_index_file();
435 + ret = get_index_file();
436 + goto out;
437 }
438
439 /*
@@ -461,7 +464,6 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
464 die(_("cannot do a partial commit during a cherry-pick."));
465 }
466
464 - string_list_init(&partial, 1);
467 if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec))
468 exit(1);
469
@@ -491,6 +493,9 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
493 discard_cache();
494 ret = get_lock_file_path(&false_lock);
495 read_cache_from(ret);
496 +out:
497 + string_list_clear(&partial, 0);
498 + clear_pathspec(&pathspec);
499 return ret;
500 }
501