Merge branch 'pw/midx-repack-overflow-fix'

Integer overflow fix around code paths for "git multi-pack-index repack"..

* pw/midx-repack-overflow-fix:
  midx docs: clarify tie breaking
  midx: avoid negative array index
  midx repack: avoid potential integer overflow on 64 bit systems
  midx repack: avoid integer overflow on 32 bit systems
This commit is contained in:
Junio C Hamano 2025-05-30 11:59:16 -07:00
commit 48a25bbbbb
3 changed files with 39 additions and 10 deletions

View File

@ -38,10 +38,13 @@ write::
+
--
--preferred-pack=<pack>::
Optionally specify the tie-breaking pack used when
multiple packs contain the same object. `<pack>` must
contain at least one object. If not given, ties are
broken in favor of the pack with the lowest mtime.
When specified, break ties in favor of this pack when
there are additional copies of its objects in other
packs. Ties for objects not found in the preferred
pack are always resolved in favor of the copy in the
pack with the highest mtime. If unspecified, the pack
with the lowest mtime is used by default. The
preferred pack must have at least one object.
--[no-]bitmap::
Control whether or not a multi-pack bitmap is written.

View File

@ -668,6 +668,22 @@ static inline int cast_size_t_to_int(size_t a)
return (int)a;
}
static inline uint64_t u64_mult(uint64_t a, uint64_t b)
{
if (unsigned_mult_overflows(a, b))
die("uint64_t overflow: %"PRIuMAX" * %"PRIuMAX,
(uintmax_t)a, (uintmax_t)b);
return a * b;
}
static inline uint64_t u64_add(uint64_t a, uint64_t b)
{
if (unsigned_add_overflows(a, b))
die("uint64_t overflow: %"PRIuMAX" + %"PRIuMAX,
(uintmax_t)a, (uintmax_t)b);
return a + b;
}
/*
* Limit size of IO chunks, because huge chunks only cause pain. OS X
* 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in

View File

@ -1566,7 +1566,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
_("Counting referenced objects"),
m->num_objects);
for (i = 0; i < m->num_objects; i++) {
int pack_int_id = nth_midxed_pack_int_id(m, i);
uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
count[pack_int_id]++;
display_progress(progress, i + 1);
}
@ -1697,21 +1697,31 @@ static void fill_included_packs_batch(struct repository *r,
total_size = 0;
for (i = 0; total_size < batch_size && i < m->num_packs; i++) {
int pack_int_id = pack_info[i].pack_int_id;
uint32_t pack_int_id = pack_info[i].pack_int_id;
struct packed_git *p = m->packs[pack_int_id];
size_t expected_size;
uint64_t expected_size;
if (!want_included_pack(r, m, pack_kept_objects, pack_int_id))
continue;
expected_size = st_mult(p->pack_size,
pack_info[i].referenced_objects);
/*
* Use shifted integer arithmetic to calculate the
* expected pack size to ~4 significant digits without
* overflow for packsizes less that 1PB.
*/
expected_size = (uint64_t)pack_info[i].referenced_objects << 14;
expected_size /= p->num_objects;
expected_size = u64_mult(expected_size, p->pack_size);
expected_size = u64_add(expected_size, 1u << 13) >> 14;
if (expected_size >= batch_size)
continue;
total_size += expected_size;
if (unsigned_add_overflows(total_size, (size_t)expected_size))
total_size = SIZE_MAX;
else
total_size += expected_size;
include_pack[pack_int_id] = 1;
}