git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com>
Cc: git@vger.kernel.org,  me@ttaylorr.com,
	 Derrick Stolee <stolee@gmail.com>
Subject: Re: [PATCH 1/5] midx-write: only load initialized packs
Date: Thu, 28 Aug 2025 13:19:02 -0700	[thread overview]
Message-ID: <xmqqbjnzurm1.fsf@gitster.g> (raw)
In-Reply-To: <4a4b35c69413ff18f87930dd15335f018ec71910.1756402795.git.gitgitgadget@gmail.com> (Derrick Stolee via GitGitGadget's message of "Thu, 28 Aug 2025 17:39:51 +0000")

"Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes:

> The fill_packs_from_midx() method was refactored in fcb2205b77 (midx:
> implement support for writing incremental MIDX chains, 2024-08-06) to
> allow for preferred packfiles and incremental multi-pack-indexes.
> However, this led to some conditions that can cause improperly
> initialized memory in the context's list of packfiles.
>
> The conditions caring about the preferred pack name or the incremental
> flag are currently necessary to load a packfile. But the context is
> still being populated with pack_info structs based on the packfile array
> for the existing multi-pack-index even if prepare_midx_pack() isn't
> called.
>
> Add a new test that breaks under --stress when compiled with
> SANITIZE=address. The chosen number of 100 packfiles was selected to get
> the --stress output to fail about 50% of the time, while 50 packfiles
> could not get a failure in most --stress runs. This test has a very
> minor check at the end confirming only one packfile remaining. The
> failing nature of this test actually relies on auto-GC cleaning up some
> packfiles during the creation of the commits, as tests setting gc.auto
> to zero make the packfile count match the number of added commits but
> also avoids hitting the memory issue.
>
> The test case is marked as EXPENSIVE not only because of the number of
> packfiles it creates, but because some CI environments were reporting
> errors during the test that I could not reproduce, specifically around
> being unable to open the packfiles or their pack-indexes.
>
> When it fails under SANITIZE=address, it provides the following error:
>
> AddressSanitizer:DEADLYSIGNAL
> =================================================================
> ==3263517==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000027
> ==3263517==The signal is caused by a READ memory access.
> ==3263517==Hint: address points to the zero page.
>     #0 0x562d5d82d1fb in close_pack_windows packfile.c:299
>     #1 0x562d5d82d3ab in close_pack packfile.c:354
>     #2 0x562d5d7bfdb4 in write_midx_internal midx-write.c:1490
>     #3 0x562d5d7c7aec in midx_repack midx-write.c:1795
>     #4 0x562d5d46fff6 in cmd_multi_pack_index builtin/multi-pack-index.c:305
>     ...
>
> This failure stack trace is disconnected from the real fix because it
> the bad pointers are accessed later when closing the packfiles from the
> context.

"because it the bad pointers" -> ???  Perhaps just drop "it"?

> There are a few different aspects to this fix that are worth noting:
>
>  1. We return to the previous behavior of fill_packs_from_midx to not
>     rely on the incremental flag or existence of a preferred pack.
>
>  2. The behavior to scan all layers of an incremental midx is kept, so
>     this is not a full revert of the change.
>
>  3. We skip allocating more room in the pack_info array if the pack
>     fails prepare_midx_pack().
>
>  4. The method has always returned 0 for success and 1 for failure, but
>     the condition checking for error added a check for a negative result
>     for failure, so that is now updated.

So did the callee think it is signalling an error, but the sole
caller was not taking that as an error, and that was one of the bugs
this change fixes?

Even if that is the case, I still do not understand why we want to
say in the callee

	error("message");
	return 1;

and adjust the caller to it, when we can just say

	return error("message");

in the callee(), especially if the only caller is expecting to be
signalled by a negative return value for an error already.

>  5. The call to open_pack_index() is removed, but this is needed later
>     in the case of a preferred pack. That call is moved to immediately
>     before its result is needed (checking for the object count).
>
> Signed-off-by: Derrick Stolee <stolee@gmail.com>
> ---
>  midx-write.c                | 38 ++++++++++++-------------------------
>  t/t5319-multi-pack-index.sh | 17 +++++++++++++++++
>  2 files changed, 29 insertions(+), 26 deletions(-)

Thanks.

> diff --git a/midx-write.c b/midx-write.c
> index a0aceab5e0..d8f9679868 100644
> --- a/midx-write.c
> +++ b/midx-write.c
> @@ -920,8 +920,7 @@ static struct multi_pack_index *lookup_multi_pack_index(struct repository *r,
>  	return get_multi_pack_index(source);
>  }
>  
> -static int fill_packs_from_midx(struct write_midx_context *ctx,
> -				const char *preferred_pack_name, uint32_t flags)
> +static int fill_packs_from_midx(struct write_midx_context *ctx)
>  {
>  	struct multi_pack_index *m;
>  
> @@ -929,30 +928,13 @@ static int fill_packs_from_midx(struct write_midx_context *ctx,
>  		uint32_t i;
>  
>  		for (i = 0; i < m->num_packs; i++) {
> -			ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
> -
> -			/*
> -			 * If generating a reverse index, need to have
> -			 * packed_git's loaded to compare their
> -			 * mtimes and object count.
> -			 *
> -			 * If a preferred pack is specified, need to
> -			 * have packed_git's loaded to ensure the chosen
> -			 * preferred pack has a non-zero object count.
> -			 */
> -			if (flags & MIDX_WRITE_REV_INDEX ||
> -			    preferred_pack_name) {
> -				if (prepare_midx_pack(ctx->repo, m,
> -						      m->num_packs_in_base + i)) {
> -					error(_("could not load pack"));
> -					return 1;
> -				}
> -
> -				if (open_pack_index(m->packs[i]))
> -					die(_("could not open index for %s"),
> -					    m->packs[i]->pack_name);
> +			if (prepare_midx_pack(ctx->repo, m,
> +					      m->num_packs_in_base + i)) {
> +				error(_("could not load pack"));
> +				return 1;
>  			}
>  
> +			ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
>  			fill_pack_info(&ctx->info[ctx->nr++], m->packs[i],
>  				       m->pack_names[i],
>  				       m->num_packs_in_base + i);
> @@ -1123,8 +1105,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
>  			ctx.num_multi_pack_indexes_before++;
>  			m = m->base_midx;
>  		}
> -	} else if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name,
> -						 flags) < 0) {
> +	} else if (ctx.m && fill_packs_from_midx(&ctx)) {
>  		goto cleanup;
>  	}
>  
> @@ -1223,6 +1204,11 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
>  
>  	if (ctx.preferred_pack_idx > -1) {
>  		struct packed_git *preferred = ctx.info[ctx.preferred_pack_idx].p;
> +
> +		if (open_pack_index(preferred))
> +			die(_("failed to open preferred pack %s"),
> +			    ctx.info[ctx.preferred_pack_idx].pack_name);
> +
>  		if (!preferred->num_objects) {
>  			error(_("cannot select preferred pack %s with no objects"),
>  			      preferred->pack_name);
> diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
> index bd75dea950..49705c62a2 100755
> --- a/t/t5319-multi-pack-index.sh
> +++ b/t/t5319-multi-pack-index.sh
> @@ -989,6 +989,23 @@ test_expect_success 'repack --batch-size=0 repacks everything' '
>  	)
>  '
>  
> +test_expect_success EXPENSIVE 'repack/expire with many packs' '
> +	cp -r dup many &&
> +	(
> +		cd many &&
> +
> +		for i in $(test_seq 1 100)
> +		do
> +			test_commit extra$i &&
> +			git maintenance run --task=loose-objects || return 1
> +		done &&
> +
> +		git multi-pack-index write &&
> +		git multi-pack-index repack &&
> +		git multi-pack-index expire
> +	)
> +'
> +
>  test_expect_success 'repack --batch-size=<large> repacks everything' '
>  	(
>  		cd dup2 &&

  reply	other threads:[~2025-08-28 20:19 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-28 17:39 [PATCH 0/5] midx-write: fix segfault and do several cleanups Derrick Stolee via GitGitGadget
2025-08-28 17:39 ` [PATCH 1/5] midx-write: only load initialized packs Derrick Stolee via GitGitGadget
2025-08-28 20:19   ` Junio C Hamano [this message]
2025-08-29  1:20   ` Taylor Blau
2025-08-30 14:33     ` Derrick Stolee
2025-08-28 17:39 ` [PATCH 2/5] midx-write: put failing response value back Derrick Stolee via GitGitGadget
2025-08-28 20:45   ` Junio C Hamano
2025-08-29  1:26     ` Taylor Blau
2025-08-28 17:39 ` [PATCH 3/5] midx-write: use cleanup when incremental midx fails Derrick Stolee via GitGitGadget
2025-08-28 20:51   ` Junio C Hamano
2025-08-29  1:29     ` Taylor Blau
2025-08-30 14:44       ` Derrick Stolee
2025-08-28 17:39 ` [PATCH 4/5] midx-write: use uint32_t for preferred_pack_idx Derrick Stolee via GitGitGadget
2025-08-28 20:58   ` Junio C Hamano
2025-08-29  1:35   ` Taylor Blau
2025-08-28 17:39 ` [PATCH 5/5] midx-write: reenable signed comparison errors Derrick Stolee via GitGitGadget
2025-08-28 21:01   ` Junio C Hamano
2025-08-29  1:35     ` Taylor Blau
2025-08-29  1:36 ` [PATCH 0/5] midx-write: fix segfault and do several cleanups Taylor Blau
2025-08-30 21:23 ` [PATCH v2 0/6] " Derrick Stolee via GitGitGadget
2025-08-30 21:23   ` [PATCH v2 1/6] midx-write: only load initialized packs Derrick Stolee via GitGitGadget
2025-09-03 10:14     ` Patrick Steinhardt
2025-09-05 18:58       ` Derrick Stolee
2025-08-30 21:23   ` [PATCH v2 2/6] midx-write: put failing response value back Derrick Stolee via GitGitGadget
2025-09-03 10:15     ` Patrick Steinhardt
2025-09-05 19:03       ` Derrick Stolee
2025-08-30 21:23   ` [PATCH v2 3/6] midx-write: use cleanup when incremental midx fails Derrick Stolee via GitGitGadget
2025-09-03 10:15     ` Patrick Steinhardt
2025-08-30 21:23   ` [PATCH v2 4/6] midx-write: use uint32_t for preferred_pack_idx Derrick Stolee via GitGitGadget
2025-09-03 10:15     ` Patrick Steinhardt
2025-09-05 19:05       ` Derrick Stolee
2025-08-30 21:23   ` [PATCH v2 5/6] midx-write: reenable signed comparison errors Derrick Stolee via GitGitGadget
2025-09-03 10:15     ` Patrick Steinhardt
2025-08-30 21:23   ` [PATCH v2 6/6] midx-write: simplify error cases Derrick Stolee via GitGitGadget
2025-09-03 10:15     ` Patrick Steinhardt
2025-09-03 18:43       ` Junio C Hamano
2025-09-05 19:26   ` [PATCH v3 0/6] midx-write: fix segfault and do several cleanups Derrick Stolee via GitGitGadget
2025-09-05 19:26     ` [PATCH v3 1/6] midx-write: only load initialized packs Derrick Stolee via GitGitGadget
2025-09-05 19:26     ` [PATCH v3 2/6] midx-write: put failing response value back Derrick Stolee via GitGitGadget
2025-09-05 19:26     ` [PATCH v3 3/6] midx-write: use cleanup when incremental midx fails Derrick Stolee via GitGitGadget
2025-09-05 19:26     ` [PATCH v3 4/6] midx-write: use uint32_t for preferred_pack_idx Derrick Stolee via GitGitGadget
2025-09-05 19:26     ` [PATCH v3 5/6] midx-write: reenable signed comparison errors Derrick Stolee via GitGitGadget
2025-09-05 19:26     ` [PATCH v3 6/6] midx-write: simplify error cases Derrick Stolee via GitGitGadget
2025-09-05 19:38     ` [PATCH v3 0/6] midx-write: fix segfault and do several cleanups Junio C Hamano
2025-09-05 19:57       ` Derrick Stolee
2025-09-11 23:13         ` Taylor Blau
2025-09-11 23:44           ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=xmqqbjnzurm1.fsf@gitster.g \
    --to=gitster@pobox.com \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=me@ttaylorr.com \
    --cc=stolee@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).