Skip to content

Commit f31d155

Browse files
committed
Merge branch 'ly/load-bitmap-leakfix'
Leakfix with a new and a bit invasive test. * ly/load-bitmap-leakfix: pack-bitmap: add load corrupt bitmap test pack-bitmap: reword comments in test_bitmap_commits() pack-bitmap: fix memory leak if load_bitmap() failed
2 parents 51b50c5 + bfd5522 commit f31d155

File tree

4 files changed

+103
-24
lines changed

4 files changed

+103
-24
lines changed

pack-bitmap.c

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct stored_bitmap {
3131
struct object_id oid;
3232
struct ewah_bitmap *root;
3333
struct stored_bitmap *xor;
34+
size_t map_pos;
3435
int flags;
3536
};
3637

@@ -314,13 +315,14 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index,
314315
struct ewah_bitmap *root,
315316
const struct object_id *oid,
316317
struct stored_bitmap *xor_with,
317-
int flags)
318+
int flags, size_t map_pos)
318319
{
319320
struct stored_bitmap *stored;
320321
khiter_t hash_pos;
321322
int ret;
322323

323324
stored = xmalloc(sizeof(struct stored_bitmap));
325+
stored->map_pos = map_pos;
324326
stored->root = root;
325327
stored->xor = xor_with;
326328
stored->flags = flags;
@@ -376,10 +378,12 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
376378
struct stored_bitmap *xor_bitmap = NULL;
377379
uint32_t commit_idx_pos;
378380
struct object_id oid;
381+
size_t entry_map_pos;
379382

380383
if (index->map_size - index->map_pos < 6)
381384
return error(_("corrupt ewah bitmap: truncated header for entry %d"), i);
382385

386+
entry_map_pos = index->map_pos;
383387
commit_idx_pos = read_be32(index->map, &index->map_pos);
384388
xor_offset = read_u8(index->map, &index->map_pos);
385389
flags = read_u8(index->map, &index->map_pos);
@@ -402,8 +406,9 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
402406
if (!bitmap)
403407
return -1;
404408

405-
recent_bitmaps[i % MAX_XOR_OFFSET] = store_bitmap(
406-
index, bitmap, &oid, xor_bitmap, flags);
409+
recent_bitmaps[i % MAX_XOR_OFFSET] =
410+
store_bitmap(index, bitmap, &oid, xor_bitmap, flags,
411+
entry_map_pos);
407412
}
408413

409414
return 0;
@@ -630,41 +635,28 @@ static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git,
630635
bitmap_git->ext_index.positions = kh_init_oid_pos();
631636

632637
if (load_reverse_index(r, bitmap_git))
633-
goto failed;
638+
return -1;
634639

635640
if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) ||
636641
!(bitmap_git->trees = read_bitmap_1(bitmap_git)) ||
637642
!(bitmap_git->blobs = read_bitmap_1(bitmap_git)) ||
638643
!(bitmap_git->tags = read_bitmap_1(bitmap_git)))
639-
goto failed;
644+
return -1;
640645

641646
if (!bitmap_git->table_lookup && load_bitmap_entries_v1(bitmap_git) < 0)
642-
goto failed;
647+
return -1;
643648

644649
if (bitmap_git->base) {
645650
if (!bitmap_is_midx(bitmap_git))
646651
BUG("non-MIDX bitmap has non-NULL base bitmap index");
647652
if (load_bitmap(r, bitmap_git->base, 1) < 0)
648-
goto failed;
653+
return -1;
649654
}
650655

651656
if (!recursing)
652657
load_all_type_bitmaps(bitmap_git);
653658

654659
return 0;
655-
656-
failed:
657-
munmap(bitmap_git->map, bitmap_git->map_size);
658-
bitmap_git->map = NULL;
659-
bitmap_git->map_size = 0;
660-
661-
kh_destroy_oid_map(bitmap_git->bitmaps);
662-
bitmap_git->bitmaps = NULL;
663-
664-
kh_destroy_oid_pos(bitmap_git->ext_index.positions);
665-
bitmap_git->ext_index.positions = NULL;
666-
667-
return -1;
668660
}
669661

670662
static int open_pack_bitmap(struct repository *r,
@@ -882,6 +874,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_
882874
int xor_flags;
883875
khiter_t hash_pos;
884876
struct bitmap_lookup_table_xor_item *xor_item;
877+
size_t entry_map_pos;
885878

886879
if (is_corrupt)
887880
return NULL;
@@ -941,14 +934,16 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_
941934
goto corrupt;
942935
}
943936

937+
entry_map_pos = bitmap_git->map_pos;
944938
bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t);
945939
xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
946940
bitmap = read_bitmap_1(bitmap_git);
947941

948942
if (!bitmap)
949943
goto corrupt;
950944

951-
xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags);
945+
xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid,
946+
xor_bitmap, xor_flags, entry_map_pos);
952947
xor_items_nr--;
953948
}
954949

@@ -982,14 +977,16 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_
982977
* Instead, we can skip ahead and immediately read the flags and
983978
* ewah bitmap.
984979
*/
980+
entry_map_pos = bitmap_git->map_pos;
985981
bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t);
986982
flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
987983
bitmap = read_bitmap_1(bitmap_git);
988984

989985
if (!bitmap)
990986
goto corrupt;
991987

992-
return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags);
988+
return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags,
989+
entry_map_pos);
993990

994991
corrupt:
995992
free(xor_items);
@@ -2852,8 +2849,9 @@ int test_bitmap_commits(struct repository *r)
28522849
die(_("failed to load bitmap indexes"));
28532850

28542851
/*
2855-
* As this function is only used to print bitmap selected
2856-
* commits, we don't have to read the commit table.
2852+
* Since this function needs to print the bitmapped
2853+
* commits, bypass the commit lookup table (if one exists)
2854+
* by forcing the bitmap to eagerly load its entries.
28572855
*/
28582856
if (bitmap_git->table_lookup) {
28592857
if (load_bitmap_entries_v1(bitmap_git) < 0)
@@ -2869,6 +2867,48 @@ int test_bitmap_commits(struct repository *r)
28692867
return 0;
28702868
}
28712869

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+
2909+
return 0;
2910+
}
2911+
28722912
int test_bitmap_hashes(struct repository *r)
28732913
{
28742914
struct bitmap_index *bitmap_git = prepare_bitmap_git(r);

pack-bitmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ void traverse_bitmap_commit_list(struct bitmap_index *,
8181
show_reachable_fn show_reachable);
8282
void test_bitmap_walk(struct rev_info *revs);
8383
int test_bitmap_commits(struct repository *r);
84+
int test_bitmap_commits_with_offset(struct repository *r);
8485
int test_bitmap_hashes(struct repository *r);
8586
int test_bitmap_pseudo_merges(struct repository *r);
8687
int test_bitmap_pseudo_merge_commits(struct repository *r, uint32_t n);

t/helper/test-bitmap.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ static int bitmap_list_commits(void)
1010
return test_bitmap_commits(the_repository);
1111
}
1212

13+
static int bitmap_list_commits_with_offset(void)
14+
{
15+
return test_bitmap_commits_with_offset(the_repository);
16+
}
17+
1318
static int bitmap_dump_hashes(void)
1419
{
1520
return test_bitmap_hashes(the_repository);
@@ -36,6 +41,8 @@ int cmd__bitmap(int argc, const char **argv)
3641

3742
if (argc == 2 && !strcmp(argv[1], "list-commits"))
3843
return bitmap_list_commits();
44+
if (argc == 2 && !strcmp(argv[1], "list-commits-with-offset"))
45+
return bitmap_list_commits_with_offset();
3946
if (argc == 2 && !strcmp(argv[1], "dump-hashes"))
4047
return bitmap_dump_hashes();
4148
if (argc == 2 && !strcmp(argv[1], "dump-pseudo-merges"))
@@ -46,6 +53,7 @@ int cmd__bitmap(int argc, const char **argv)
4653
return bitmap_dump_pseudo_merge_objects(atoi(argv[2]));
4754

4855
usage("\ttest-tool bitmap list-commits\n"
56+
"\ttest-tool bitmap list-commits-with-offset\n"
4957
"\ttest-tool bitmap dump-hashes\n"
5058
"\ttest-tool bitmap dump-pseudo-merges\n"
5159
"\ttest-tool bitmap dump-pseudo-merge-commits <n>\n"

t/t5310-pack-bitmaps.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,36 @@ test_bitmap_cases () {
495495
grep "ignoring extra bitmap" trace2.txt
496496
)
497497
'
498+
499+
test_expect_success 'load corrupt bitmap' '
500+
rm -fr repo &&
501+
git init repo &&
502+
test_when_finished "rm -fr repo" &&
503+
(
504+
cd repo &&
505+
git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
506+
507+
test_commit base &&
508+
509+
git repack -adb &&
510+
bitmap="$(ls .git/objects/pack/pack-*.bitmap)" &&
511+
chmod +w $bitmap &&
512+
513+
test-tool bitmap list-commits-with-offset >offsets &&
514+
xor_off=$(head -n1 offsets | awk "{print \$3}") &&
515+
printf '\161' |
516+
dd of=$bitmap count=1 bs=1 conv=notrunc seek=$xor_off &&
517+
518+
git rev-list --objects --no-object-names HEAD >expect.raw &&
519+
git rev-list --objects --use-bitmap-index --no-object-names HEAD \
520+
>actual.raw &&
521+
522+
sort expect.raw >expect &&
523+
sort actual.raw >actual &&
524+
525+
test_cmp expect actual
526+
)
527+
'
498528
}
499529

500530
test_bitmap_cases

0 commit comments

Comments
 (0)