git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Lidong Yan via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Jeff King <peff@peff.net>, Taylor Blau <me@ttaylorr.com>,
	Lidong Yan <502024330056@smail.nju.edu.cn>,
	Lidong Yan <502024330056@smail.nju.edu.cn>
Subject: [PATCH v6 3/3] pack-bitmap: add load corrupt bitmap test
Date: Tue, 01 Jul 2025 05:32:09 +0000	[thread overview]
Message-ID: <c1b5d030133fafc6adaa70facf13027b37edf632.1751347929.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1962.v6.git.git.1751347929.gitgitgadget@gmail.com>

From: Lidong Yan <502024330056@smail.nju.edu.cn>

t5310 lacks a test to ensure git works correctly when commit bitmap
data is corrupted. So this patch add test helper in pack-bitmap.c to
list each commit bitmap position in bitmap file and `load corrupt bitmap`
test case in t/t5310 to corrupt a commit bitmap before loading it.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
---
 pack-bitmap.c           | 62 +++++++++++++++++++++++++++++++++++++----
 pack-bitmap.h           |  1 +
 t/helper/test-bitmap.c  |  8 ++++++
 t/t5310-pack-bitmaps.sh | 30 ++++++++++++++++++++
 4 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/pack-bitmap.c b/pack-bitmap.c
index 330f07609835..499d77a1d368 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -31,6 +31,7 @@ struct stored_bitmap {
 	struct object_id oid;
 	struct ewah_bitmap *root;
 	struct stored_bitmap *xor;
+	size_t map_pos;
 	int flags;
 };
 
@@ -314,13 +315,14 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index,
 					  struct ewah_bitmap *root,
 					  const struct object_id *oid,
 					  struct stored_bitmap *xor_with,
-					  int flags)
+					  int flags, size_t map_pos)
 {
 	struct stored_bitmap *stored;
 	khiter_t hash_pos;
 	int ret;
 
 	stored = xmalloc(sizeof(struct stored_bitmap));
+	stored->map_pos = map_pos;
 	stored->root = root;
 	stored->xor = xor_with;
 	stored->flags = flags;
@@ -376,10 +378,12 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
 		struct stored_bitmap *xor_bitmap = NULL;
 		uint32_t commit_idx_pos;
 		struct object_id oid;
+		size_t entry_map_pos;
 
 		if (index->map_size - index->map_pos < 6)
 			return error(_("corrupt ewah bitmap: truncated header for entry %d"), i);
 
+		entry_map_pos = index->map_pos;
 		commit_idx_pos = read_be32(index->map, &index->map_pos);
 		xor_offset = read_u8(index->map, &index->map_pos);
 		flags = read_u8(index->map, &index->map_pos);
@@ -402,8 +406,9 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
 		if (!bitmap)
 			return -1;
 
-		recent_bitmaps[i % MAX_XOR_OFFSET] = store_bitmap(
-			index, bitmap, &oid, xor_bitmap, flags);
+		recent_bitmaps[i % MAX_XOR_OFFSET] =
+			store_bitmap(index, bitmap, &oid, xor_bitmap, flags,
+				     entry_map_pos);
 	}
 
 	return 0;
@@ -869,6 +874,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_
 	int xor_flags;
 	khiter_t hash_pos;
 	struct bitmap_lookup_table_xor_item *xor_item;
+	size_t entry_map_pos;
 
 	if (is_corrupt)
 		return NULL;
@@ -928,6 +934,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_
 			goto corrupt;
 		}
 
+		entry_map_pos = bitmap_git->map_pos;
 		bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t);
 		xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
 		bitmap = read_bitmap_1(bitmap_git);
@@ -935,7 +942,8 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_
 		if (!bitmap)
 			goto corrupt;
 
-		xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags);
+		xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid,
+					  xor_bitmap, xor_flags, entry_map_pos);
 		xor_items_nr--;
 	}
 
@@ -969,6 +977,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_
 	 * Instead, we can skip ahead and immediately read the flags and
 	 * ewah bitmap.
 	 */
+	entry_map_pos = bitmap_git->map_pos;
 	bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t);
 	flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
 	bitmap = read_bitmap_1(bitmap_git);
@@ -976,7 +985,8 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_
 	if (!bitmap)
 		goto corrupt;
 
-	return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags);
+	return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags,
+			    entry_map_pos);
 
 corrupt:
 	free(xor_items);
@@ -2857,6 +2867,48 @@ int test_bitmap_commits(struct repository *r)
 	return 0;
 }
 
+int test_bitmap_commits_with_offset(struct repository *r)
+{
+	struct object_id oid;
+	struct stored_bitmap *stored;
+	struct bitmap_index *bitmap_git;
+	size_t commit_idx_pos_map_pos, xor_offset_map_pos, flag_map_pos,
+		ewah_bitmap_map_pos;
+
+	bitmap_git = prepare_bitmap_git(r);
+	if (!bitmap_git)
+		die(_("failed to load bitmap indexes"));
+
+	/*
+	 * Since this function needs to know the position of each individual
+	 * bitmap, bypass the commit lookup table (if one exists) by forcing
+	 * the bitmap to eagerly load its entries.
+	 */
+	if (bitmap_git->table_lookup) {
+		if (load_bitmap_entries_v1(bitmap_git) < 0)
+			die(_("failed to load bitmap indexes"));
+	}
+
+	kh_foreach (bitmap_git->bitmaps, oid, stored, {
+		commit_idx_pos_map_pos = stored->map_pos;
+		xor_offset_map_pos = stored->map_pos + sizeof(uint32_t);
+		flag_map_pos = xor_offset_map_pos + sizeof(uint8_t);
+		ewah_bitmap_map_pos = flag_map_pos + sizeof(uint8_t);
+
+		printf_ln("%s %"PRIuMAX" %"PRIuMAX" %"PRIuMAX" %"PRIuMAX,
+			  oid_to_hex(&oid),
+			  (uintmax_t)commit_idx_pos_map_pos,
+			  (uintmax_t)xor_offset_map_pos,
+			  (uintmax_t)flag_map_pos,
+			  (uintmax_t)ewah_bitmap_map_pos);
+	})
+		;
+
+	free_bitmap_index(bitmap_git);
+
+	return 0;
+}
+
 int test_bitmap_hashes(struct repository *r)
 {
 	struct bitmap_index *bitmap_git = prepare_bitmap_git(r);
diff --git a/pack-bitmap.h b/pack-bitmap.h
index 382d39499af2..1bd7a791e2a0 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -81,6 +81,7 @@ void traverse_bitmap_commit_list(struct bitmap_index *,
 				 show_reachable_fn show_reachable);
 void test_bitmap_walk(struct rev_info *revs);
 int test_bitmap_commits(struct repository *r);
+int test_bitmap_commits_with_offset(struct repository *r);
 int test_bitmap_hashes(struct repository *r);
 int test_bitmap_pseudo_merges(struct repository *r);
 int test_bitmap_pseudo_merge_commits(struct repository *r, uint32_t n);
diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c
index 3f23f2107268..16a01669e414 100644
--- a/t/helper/test-bitmap.c
+++ b/t/helper/test-bitmap.c
@@ -10,6 +10,11 @@ static int bitmap_list_commits(void)
 	return test_bitmap_commits(the_repository);
 }
 
+static int bitmap_list_commits_with_offset(void)
+{
+	return test_bitmap_commits_with_offset(the_repository);
+}
+
 static int bitmap_dump_hashes(void)
 {
 	return test_bitmap_hashes(the_repository);
@@ -36,6 +41,8 @@ int cmd__bitmap(int argc, const char **argv)
 
 	if (argc == 2 && !strcmp(argv[1], "list-commits"))
 		return bitmap_list_commits();
+	if (argc == 2 && !strcmp(argv[1], "list-commits-with-offset"))
+		return bitmap_list_commits_with_offset();
 	if (argc == 2 && !strcmp(argv[1], "dump-hashes"))
 		return bitmap_dump_hashes();
 	if (argc == 2 && !strcmp(argv[1], "dump-pseudo-merges"))
@@ -46,6 +53,7 @@ int cmd__bitmap(int argc, const char **argv)
 		return bitmap_dump_pseudo_merge_objects(atoi(argv[2]));
 
 	usage("\ttest-tool bitmap list-commits\n"
+	      "\ttest-tool bitmap list-commits-with-offset\n"
 	      "\ttest-tool bitmap dump-hashes\n"
 	      "\ttest-tool bitmap dump-pseudo-merges\n"
 	      "\ttest-tool bitmap dump-pseudo-merge-commits <n>\n"
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index b6926f102708..6718fb98c057 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -495,6 +495,36 @@ test_bitmap_cases () {
 			grep "ignoring extra bitmap" trace2.txt
 		)
 	'
+
+	test_expect_success 'load corrupt bitmap' '
+		rm -fr repo &&
+		git init repo &&
+		test_when_finished "rm -fr repo" &&
+		(
+			cd repo &&
+			git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+
+			test_commit base &&
+
+			git repack -adb &&
+			bitmap="$(ls .git/objects/pack/pack-*.bitmap)" &&
+			chmod +w $bitmap &&
+
+			test-tool bitmap list-commits-with-offset >offsets &&
+			xor_off=$(head -n1 offsets | awk "{print \$3}") &&
+			printf '\161' |
+				dd of=$bitmap count=1 bs=1 conv=notrunc seek=$xor_off &&
+
+			git rev-list --objects --no-object-names HEAD >expect.raw &&
+			git rev-list --objects --use-bitmap-index --no-object-names HEAD \
+				>actual.raw &&
+
+			sort expect.raw >expect &&
+			sort actual.raw >actual &&
+
+		    test_cmp expect actual
+		)
+	'
 }
 
 test_bitmap_cases
-- 
gitgitgadget

  parent reply	other threads:[~2025-07-01  5:32 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-12 12:22 [PATCH] pack-bitmap: fix memory leak if `load_bitmap_entries_v1` failed Lidong Yan via GitGitGadget
2025-05-12 13:13 ` Jeff King
2025-05-13 17:47   ` Taylor Blau
2025-05-14 13:18     ` Junio C Hamano
2025-05-14 18:03     ` Jeff King
2025-05-15  1:37       ` lidongyan
2025-05-20  9:23 ` [PATCH v2 0/3] pack-bitmap: fix memory leak if load_bitmap_entries_v1 failed Lidong Yan via GitGitGadget
2025-05-20  9:23   ` [PATCH v2 1/3] pack-bitmap: fix memory leak if `load_bitmap_entries_v1` failed Lidong Yan via GitGitGadget
2025-05-20  9:23   ` [PATCH v2 2/3] " Taylor Blau via GitGitGadget
2025-05-21 23:54     ` Taylor Blau
2025-05-22 15:15       ` lidongyan
2025-05-22 21:22       ` Junio C Hamano
2025-05-20  9:23   ` [PATCH v2 3/3] pack-bitmap: add loading corrupt bitmap_index test Lidong Yan via GitGitGadget
2025-05-22  0:08     ` Taylor Blau
2025-05-22 15:05       ` lidongyan
2025-05-23  0:31         ` Taylor Blau
2025-05-23  7:17           ` lidongyan
2025-05-25  2:06   ` [PATCH v3 0/2] pack-bitmap: fix memory leak if load_bitmap_entries_v1 failed Lidong Yan via GitGitGadget
2025-05-25  2:06     ` [PATCH v3 1/2] pack-bitmap: fix memory leak if `load_bitmap_entries_v1` failed Taylor Blau via GitGitGadget
2025-05-25  2:06     ` [PATCH v3 2/2] pack-bitmap: add load corrupt bitmap test Lidong Yan via GitGitGadget
2025-05-25  2:43     ` [PATCH v4 0/2] pack-bitmap: fix memory leak if load_bitmap failed Lidong Yan via GitGitGadget
2025-05-25  2:43       ` [PATCH v4 1/2] pack-bitmap: fix memory leak if load_bitmap() failed Taylor Blau via GitGitGadget
2025-05-29 15:33         ` Junio C Hamano
2025-05-29 19:57           ` Taylor Blau
2025-05-29 22:04             ` Junio C Hamano
2025-05-30  3:50           ` lidongyan
2025-05-25  2:43       ` [PATCH v4 2/2] pack-bitmap: add load corrupt bitmap test Lidong Yan via GitGitGadget
2025-05-29 15:45         ` Junio C Hamano
2025-05-29 21:21           ` Taylor Blau
2025-05-30  3:53           ` lidongyan
2025-05-29 21:20         ` Taylor Blau
2025-05-30  4:03           ` lidongyan
2025-06-03  3:14       ` [PATCH v5 0/3] pack-bitmap: fix memory leak if load_bitmap failed Lidong Yan via GitGitGadget
2025-06-03  3:14         ` [PATCH v5 1/3] pack-bitmap: fix memory leak if load_bitmap() failed Taylor Blau via GitGitGadget
2025-06-03  3:14         ` [PATCH v5 2/3] pack-bitmap: reword comments in test_bitmap_commits() Lidong Yan via GitGitGadget
2025-06-03 22:13           ` Taylor Blau
2025-06-03  3:14         ` [PATCH v5 3/3] pack-bitmap: add load corrupt bitmap test Lidong Yan via GitGitGadget
2025-06-03 22:14         ` [PATCH v5 0/3] pack-bitmap: fix memory leak if load_bitmap failed Taylor Blau
2025-07-01  5:32         ` [PATCH v6 " Lidong Yan via GitGitGadget
2025-07-01  5:32           ` [PATCH v6 1/3] pack-bitmap: fix memory leak if load_bitmap() failed Taylor Blau via GitGitGadget
2025-07-01  5:32           ` [PATCH v6 2/3] pack-bitmap: reword comments in test_bitmap_commits() Lidong Yan via GitGitGadget
2025-07-01  5:32           ` Lidong Yan via GitGitGadget [this message]
2025-07-07 22:53           ` [PATCH v6 0/3] pack-bitmap: fix memory leak if load_bitmap failed Junio C Hamano
2025-07-08 22:10             ` Taylor Blau
2025-07-08 22:35               ` 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=c1b5d030133fafc6adaa70facf13027b37edf632.1751347929.git.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=502024330056@smail.nju.edu.cn \
    --cc=git@vger.kernel.org \
    --cc=me@ttaylorr.com \
    --cc=peff@peff.net \
    /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).