]> git.ipfire.org Git - thirdparty/git.git/commitdiff
pack-bitmap: add load corrupt bitmap test
authorLidong Yan <502024330056@smail.nju.edu.cn>
Tue, 1 Jul 2025 05:32:09 +0000 (05:32 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 1 Jul 2025 21:41:54 +0000 (14:41 -0700)
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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
pack-bitmap.c
pack-bitmap.h
t/helper/test-bitmap.c
t/t5310-pack-bitmaps.sh

index d1d8814be7f3f3c5b56faa9190c221ef9213e756..d707bc52f7fda33836de811f711787e93d450108 100644 (file)
@@ -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);
index 382d39499af23c70d20d3cd7e74595975d57726a..1bd7a791e2a0d0794dc235b3f71293b5cc142a0b 100644 (file)
@@ -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);
index 3f23f21072681cd95dd7b6d4d52c501f9ef84881..16a01669e4149aaa9123f7f8c91f5b196d30cf70 100644 (file)
@@ -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"
index a62b463eaf0932fe0d38890f549dcd6061653efb..df05d7419185a6e1c1b8de6baf1f376347f3cc33 100755 (executable)
@@ -486,6 +486,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