bundle: plug leaks in create_bundle()

When creating a bundle, we set up a revision walk, but never release
data associated with it. Furthermore, we create a mostly-shallow copy of
that revision walk where we only adapt its pending objects such that we
can reuse the walk. While that copy must not be released, the pending
objects array need to be.

Plug those memory leaks by releasing the revision walk and the pending
objects of the copied revision walk.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2024-06-11 11:19:31 +02:00
committed by Junio C Hamano
parent bb8c43d5cd
commit 11ee9a75e7
4 changed files with 22 additions and 10 deletions

View File

@@ -500,6 +500,7 @@ int create_bundle(struct repository *r, const char *path,
struct rev_info revs, revs_copy; struct rev_info revs, revs_copy;
int min_version = 2; int min_version = 2;
struct bundle_prerequisites_info bpi; struct bundle_prerequisites_info bpi;
int ret;
int i; int i;
/* init revs to list objects for pack-objects later */ /* init revs to list objects for pack-objects later */
@@ -525,8 +526,8 @@ int create_bundle(struct repository *r, const char *path,
min_version = 3; min_version = 3;
if (argc > 1) { if (argc > 1) {
error(_("unrecognized argument: %s"), argv[1]); ret = error(_("unrecognized argument: %s"), argv[1]);
goto err; goto out;
} }
bundle_to_stdout = !strcmp(path, "-"); bundle_to_stdout = !strcmp(path, "-");
@@ -591,23 +592,31 @@ int create_bundle(struct repository *r, const char *path,
/* write bundle refs */ /* write bundle refs */
ref_count = write_bundle_refs(bundle_fd, &revs_copy); ref_count = write_bundle_refs(bundle_fd, &revs_copy);
if (!ref_count) if (!ref_count) {
die(_("Refusing to create empty bundle.")); die(_("Refusing to create empty bundle."));
else if (ref_count < 0) } else if (ref_count < 0) {
goto err; ret = -1;
goto out;
}
/* write pack */ /* write pack */
if (write_pack_data(bundle_fd, &revs_copy, pack_options)) if (write_pack_data(bundle_fd, &revs_copy, pack_options)) {
goto err; ret = -1;
goto out;
}
if (!bundle_to_stdout) { if (!bundle_to_stdout) {
if (commit_lock_file(&lock)) if (commit_lock_file(&lock))
die_errno(_("cannot create '%s'"), path); die_errno(_("cannot create '%s'"), path);
} }
return 0;
err: ret = 0;
out:
object_array_clear(&revs_copy.pending);
release_revisions(&revs);
rollback_lock_file(&lock); rollback_lock_file(&lock);
return -1; return ret;
} }
int unbundle(struct repository *r, struct bundle_header *header, int unbundle(struct repository *r, struct bundle_header *header,

View File

@@ -4,6 +4,7 @@ test_description='test local clone'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh . ./test-lib.sh
repo_is_hardlinked() { repo_is_hardlinked() {

View File

@@ -4,6 +4,7 @@ test_description='some bundle related tests'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh . ./test-lib.sh
test_expect_success 'setup' ' test_expect_success 'setup' '

View File

@@ -8,6 +8,7 @@ test_description='Test git-bundle'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh . ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bundle.sh . "$TEST_DIRECTORY"/lib-bundle.sh
. "$TEST_DIRECTORY"/lib-terminal.sh . "$TEST_DIRECTORY"/lib-terminal.sh