On Mon, May 12, 2025 at 09:13:15AM -0400, Jeff King wrote: > On Mon, May 12, 2025 at 12:22:10PM +0000, Lidong Yan via GitGitGadget wrote: > > > From: Lidong Yan <502024330056@xxxxxxxxxxxxxxxx> > > > > In pack-bitmap.c:load_bitmap_entries_v1, the function `read_bitmap_1` > > allocates a bitmap and reads index data into it. However, if any of > > the validation checks following the allocation fail, the allocated bitmap > > is not freed, resulting in a memory leak. To avoid this, the validation > > checks should be performed before the bitmap is allocated. > > Thanks, this looks correct to me. It looks correct to me as well, and is a strict improvement. But I think there is a leak outside of this function as well that is not touched by this patch. > > @@ -388,10 +388,6 @@ static int load_bitmap_entries_v1(struct bitmap_index *index) > > return error(_("corrupt ewah bitmap: commit index %u out of range"), > > (unsigned)commit_idx_pos); > > > > - bitmap = read_bitmap_1(index); > > - if (!bitmap) > > - return -1; > > - > > if (xor_offset > MAX_XOR_OFFSET || xor_offset > i) > > return error(_("corrupted bitmap pack index")); > > I noticed that this code is also within a loop, so we could still return > early on the next loop iteration. But by that point we will have called > store_bitmap() on the result, so we only have to worry about leaking the > bitmap from the current loop iteration. That's right, though I think there is still a leak here. After going through the "failed" label, load_bitmap() will return -1, and its caller (either prepare_bitmap_walk() or prepare_bitmap_git()) will then call free_bitmap_index(). That function would have done: struct stored_bitmap *sb; kh_foreach_value(b->bitmaps, sb { ewah_pool_free(sb->root); free(sb); }); , but won't since load_bitmap() already called kh_destroy_oid_map() and NULL'd the "bitmaps" pointer from within its "failed" label. So I think if you got part of the way through loading bitmap entries and then failed, you would leak all of the previous entries that you were able to load successfully. I suspect the fix looks something like: --- 8< --- diff --git a/pack-bitmap.c b/pack-bitmap.c index 5299f49d59..7f28532a69 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -631,41 +631,28 @@ static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git, bitmap_git->ext_index.positions = kh_init_oid_pos(); if (load_reverse_index(r, bitmap_git)) - goto failed; + return -1; if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) || !(bitmap_git->trees = read_bitmap_1(bitmap_git)) || !(bitmap_git->blobs = read_bitmap_1(bitmap_git)) || !(bitmap_git->tags = read_bitmap_1(bitmap_git))) - goto failed; + return -1; if (!bitmap_git->table_lookup && load_bitmap_entries_v1(bitmap_git) < 0) - goto failed; + return -1; if (bitmap_git->base) { if (!bitmap_is_midx(bitmap_git)) BUG("non-MIDX bitmap has non-NULL base bitmap index"); if (load_bitmap(r, bitmap_git->base, 1) < 0) - goto failed; + return -1; } if (!recursing) load_all_type_bitmaps(bitmap_git); return 0; - -failed: - munmap(bitmap_git->map, bitmap_git->map_size); - bitmap_git->map = NULL; - bitmap_git->map_size = 0; - - kh_destroy_oid_map(bitmap_git->bitmaps); - bitmap_git->bitmaps = NULL; - - kh_destroy_oid_pos(bitmap_git->ext_index.positions); - bitmap_git->ext_index.positions = NULL; - - return -1; } static int open_pack_bitmap(struct repository *r, --- >8 --- , since all callers of load_bitmap() will themselves call free_bitmap_index(), so there is no need for us to open-code a portion of that function's implementation ourselves. Thanks, Taylor