Git fork

pack-bitmap: add load corrupt bitmap test

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>

authored by

Lidong Yan and committed by
Junio C Hamano
bfd5522e 73bf771b

+96 -5
+57 -5
pack-bitmap.c
··· 31 struct object_id oid; 32 struct ewah_bitmap *root; 33 struct stored_bitmap *xor; 34 int flags; 35 }; 36 ··· 314 struct ewah_bitmap *root, 315 const struct object_id *oid, 316 struct stored_bitmap *xor_with, 317 - int flags) 318 { 319 struct stored_bitmap *stored; 320 khiter_t hash_pos; 321 int ret; 322 323 stored = xmalloc(sizeof(struct stored_bitmap)); 324 stored->root = root; 325 stored->xor = xor_with; 326 stored->flags = flags; ··· 376 struct stored_bitmap *xor_bitmap = NULL; 377 uint32_t commit_idx_pos; 378 struct object_id oid; 379 380 if (index->map_size - index->map_pos < 6) 381 return error(_("corrupt ewah bitmap: truncated header for entry %d"), i); 382 383 commit_idx_pos = read_be32(index->map, &index->map_pos); 384 xor_offset = read_u8(index->map, &index->map_pos); 385 flags = read_u8(index->map, &index->map_pos); ··· 402 if (!bitmap) 403 return -1; 404 405 - recent_bitmaps[i % MAX_XOR_OFFSET] = store_bitmap( 406 - index, bitmap, &oid, xor_bitmap, flags); 407 } 408 409 return 0; ··· 869 int xor_flags; 870 khiter_t hash_pos; 871 struct bitmap_lookup_table_xor_item *xor_item; 872 873 if (is_corrupt) 874 return NULL; ··· 928 goto corrupt; 929 } 930 931 bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t); 932 xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos); 933 bitmap = read_bitmap_1(bitmap_git); ··· 935 if (!bitmap) 936 goto corrupt; 937 938 - xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags); 939 xor_items_nr--; 940 } 941 ··· 969 * Instead, we can skip ahead and immediately read the flags and 970 * ewah bitmap. 971 */ 972 bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t); 973 flags = read_u8(bitmap_git->map, &bitmap_git->map_pos); 974 bitmap = read_bitmap_1(bitmap_git); ··· 976 if (!bitmap) 977 goto corrupt; 978 979 - return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags); 980 981 corrupt: 982 free(xor_items); ··· 2851 kh_foreach(bitmap_git->bitmaps, oid, value, { 2852 printf_ln("%s", oid_to_hex(&oid)); 2853 }); 2854 2855 free_bitmap_index(bitmap_git); 2856
··· 31 struct object_id oid; 32 struct ewah_bitmap *root; 33 struct stored_bitmap *xor; 34 + size_t map_pos; 35 int flags; 36 }; 37 ··· 315 struct ewah_bitmap *root, 316 const struct object_id *oid, 317 struct stored_bitmap *xor_with, 318 + int flags, size_t map_pos) 319 { 320 struct stored_bitmap *stored; 321 khiter_t hash_pos; 322 int ret; 323 324 stored = xmalloc(sizeof(struct stored_bitmap)); 325 + stored->map_pos = map_pos; 326 stored->root = root; 327 stored->xor = xor_with; 328 stored->flags = flags; ··· 378 struct stored_bitmap *xor_bitmap = NULL; 379 uint32_t commit_idx_pos; 380 struct object_id oid; 381 + size_t entry_map_pos; 382 383 if (index->map_size - index->map_pos < 6) 384 return error(_("corrupt ewah bitmap: truncated header for entry %d"), i); 385 386 + entry_map_pos = index->map_pos; 387 commit_idx_pos = read_be32(index->map, &index->map_pos); 388 xor_offset = read_u8(index->map, &index->map_pos); 389 flags = read_u8(index->map, &index->map_pos); ··· 406 if (!bitmap) 407 return -1; 408 409 + recent_bitmaps[i % MAX_XOR_OFFSET] = 410 + store_bitmap(index, bitmap, &oid, xor_bitmap, flags, 411 + entry_map_pos); 412 } 413 414 return 0; ··· 874 int xor_flags; 875 khiter_t hash_pos; 876 struct bitmap_lookup_table_xor_item *xor_item; 877 + size_t entry_map_pos; 878 879 if (is_corrupt) 880 return NULL; ··· 934 goto corrupt; 935 } 936 937 + entry_map_pos = bitmap_git->map_pos; 938 bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t); 939 xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos); 940 bitmap = read_bitmap_1(bitmap_git); ··· 942 if (!bitmap) 943 goto corrupt; 944 945 + xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, 946 + xor_bitmap, xor_flags, entry_map_pos); 947 xor_items_nr--; 948 } 949 ··· 977 * Instead, we can skip ahead and immediately read the flags and 978 * ewah bitmap. 979 */ 980 + entry_map_pos = bitmap_git->map_pos; 981 bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t); 982 flags = read_u8(bitmap_git->map, &bitmap_git->map_pos); 983 bitmap = read_bitmap_1(bitmap_git); ··· 985 if (!bitmap) 986 goto corrupt; 987 988 + return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags, 989 + entry_map_pos); 990 991 corrupt: 992 free(xor_items); ··· 2861 kh_foreach(bitmap_git->bitmaps, oid, value, { 2862 printf_ln("%s", oid_to_hex(&oid)); 2863 }); 2864 + 2865 + free_bitmap_index(bitmap_git); 2866 + 2867 + return 0; 2868 + } 2869 + 2870 + int test_bitmap_commits_with_offset(struct repository *r) 2871 + { 2872 + struct object_id oid; 2873 + struct stored_bitmap *stored; 2874 + struct bitmap_index *bitmap_git; 2875 + size_t commit_idx_pos_map_pos, xor_offset_map_pos, flag_map_pos, 2876 + ewah_bitmap_map_pos; 2877 + 2878 + bitmap_git = prepare_bitmap_git(r); 2879 + if (!bitmap_git) 2880 + die(_("failed to load bitmap indexes")); 2881 + 2882 + /* 2883 + * Since this function needs to know the position of each individual 2884 + * bitmap, bypass the commit lookup table (if one exists) by forcing 2885 + * the bitmap to eagerly load its entries. 2886 + */ 2887 + if (bitmap_git->table_lookup) { 2888 + if (load_bitmap_entries_v1(bitmap_git) < 0) 2889 + die(_("failed to load bitmap indexes")); 2890 + } 2891 + 2892 + kh_foreach (bitmap_git->bitmaps, oid, stored, { 2893 + commit_idx_pos_map_pos = stored->map_pos; 2894 + xor_offset_map_pos = stored->map_pos + sizeof(uint32_t); 2895 + flag_map_pos = xor_offset_map_pos + sizeof(uint8_t); 2896 + ewah_bitmap_map_pos = flag_map_pos + sizeof(uint8_t); 2897 + 2898 + printf_ln("%s %"PRIuMAX" %"PRIuMAX" %"PRIuMAX" %"PRIuMAX, 2899 + oid_to_hex(&oid), 2900 + (uintmax_t)commit_idx_pos_map_pos, 2901 + (uintmax_t)xor_offset_map_pos, 2902 + (uintmax_t)flag_map_pos, 2903 + (uintmax_t)ewah_bitmap_map_pos); 2904 + }) 2905 + ; 2906 2907 free_bitmap_index(bitmap_git); 2908
+1
pack-bitmap.h
··· 81 show_reachable_fn show_reachable); 82 void test_bitmap_walk(struct rev_info *revs); 83 int test_bitmap_commits(struct repository *r); 84 int test_bitmap_hashes(struct repository *r); 85 int test_bitmap_pseudo_merges(struct repository *r); 86 int test_bitmap_pseudo_merge_commits(struct repository *r, uint32_t n);
··· 81 show_reachable_fn show_reachable); 82 void test_bitmap_walk(struct rev_info *revs); 83 int test_bitmap_commits(struct repository *r); 84 + int test_bitmap_commits_with_offset(struct repository *r); 85 int test_bitmap_hashes(struct repository *r); 86 int test_bitmap_pseudo_merges(struct repository *r); 87 int test_bitmap_pseudo_merge_commits(struct repository *r, uint32_t n);
+8
t/helper/test-bitmap.c
··· 10 return test_bitmap_commits(the_repository); 11 } 12 13 static int bitmap_dump_hashes(void) 14 { 15 return test_bitmap_hashes(the_repository); ··· 36 37 if (argc == 2 && !strcmp(argv[1], "list-commits")) 38 return bitmap_list_commits(); 39 if (argc == 2 && !strcmp(argv[1], "dump-hashes")) 40 return bitmap_dump_hashes(); 41 if (argc == 2 && !strcmp(argv[1], "dump-pseudo-merges")) ··· 46 return bitmap_dump_pseudo_merge_objects(atoi(argv[2])); 47 48 usage("\ttest-tool bitmap list-commits\n" 49 "\ttest-tool bitmap dump-hashes\n" 50 "\ttest-tool bitmap dump-pseudo-merges\n" 51 "\ttest-tool bitmap dump-pseudo-merge-commits <n>\n"
··· 10 return test_bitmap_commits(the_repository); 11 } 12 13 + static int bitmap_list_commits_with_offset(void) 14 + { 15 + return test_bitmap_commits_with_offset(the_repository); 16 + } 17 + 18 static int bitmap_dump_hashes(void) 19 { 20 return test_bitmap_hashes(the_repository); ··· 41 42 if (argc == 2 && !strcmp(argv[1], "list-commits")) 43 return bitmap_list_commits(); 44 + if (argc == 2 && !strcmp(argv[1], "list-commits-with-offset")) 45 + return bitmap_list_commits_with_offset(); 46 if (argc == 2 && !strcmp(argv[1], "dump-hashes")) 47 return bitmap_dump_hashes(); 48 if (argc == 2 && !strcmp(argv[1], "dump-pseudo-merges")) ··· 53 return bitmap_dump_pseudo_merge_objects(atoi(argv[2])); 54 55 usage("\ttest-tool bitmap list-commits\n" 56 + "\ttest-tool bitmap list-commits-with-offset\n" 57 "\ttest-tool bitmap dump-hashes\n" 58 "\ttest-tool bitmap dump-pseudo-merges\n" 59 "\ttest-tool bitmap dump-pseudo-merge-commits <n>\n"
+30
t/t5310-pack-bitmaps.sh
··· 486 grep "ignoring extra bitmap" trace2.txt 487 ) 488 ' 489 } 490 491 test_bitmap_cases
··· 486 grep "ignoring extra bitmap" trace2.txt 487 ) 488 ' 489 + 490 + test_expect_success 'load corrupt bitmap' ' 491 + rm -fr repo && 492 + git init repo && 493 + test_when_finished "rm -fr repo" && 494 + ( 495 + cd repo && 496 + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && 497 + 498 + test_commit base && 499 + 500 + git repack -adb && 501 + bitmap="$(ls .git/objects/pack/pack-*.bitmap)" && 502 + chmod +w $bitmap && 503 + 504 + test-tool bitmap list-commits-with-offset >offsets && 505 + xor_off=$(head -n1 offsets | awk "{print \$3}") && 506 + printf '\161' | 507 + dd of=$bitmap count=1 bs=1 conv=notrunc seek=$xor_off && 508 + 509 + git rev-list --objects --no-object-names HEAD >expect.raw && 510 + git rev-list --objects --use-bitmap-index --no-object-names HEAD \ 511 + >actual.raw && 512 + 513 + sort expect.raw >expect && 514 + sort actual.raw >actual && 515 + 516 + test_cmp expect actual 517 + ) 518 + ' 519 } 520 521 test_bitmap_cases