diff --git a/src/internal/pack/decode.rs b/src/internal/pack/decode.rs index 8669dc78..67bb92ff 100644 --- a/src/internal/pack/decode.rs +++ b/src/internal/pack/decode.rs @@ -113,7 +113,10 @@ impl Pack { temp_path.pop(); } let thread_num = thread_num.unwrap_or_else(num_cpus::get); - let cache_mem_size = mem_limit.map(|mem_limit| mem_limit * 4 / 5); + let cache_mem_size = mem_limit.map(|mem_limit| { + // Use wider math to avoid 32-bit overflow when computing 80%. + ((mem_limit as u128) * 4 / 5) as usize + }); Pack { number: 0, signature: ObjectHash::default(), @@ -838,6 +841,20 @@ mod tests { } } + #[test] + #[cfg(target_pointer_width = "32")] + fn test_pack_new_mem_limit_no_overflow_32bit() { + // In the old code, 1.2B * 4 produced an intermediate 4.8B value, which exceeds + // 32-bit usize::MAX (~4.29B) and overflowed before a later division; this test + // covers that former panic path. + let mem_limit = 1_200_000_000usize; + let tmp = PathBuf::from("/tmp/.cache_temp"); + let result = std::panic::catch_unwind(|| { + let _p = Pack::new(Some(1), Some(mem_limit), Some(tmp), true); + }); + assert!(result.is_ok(), "Pack::new should not panic on 32-bit"); + } + /// Helper function to run decode tests without delta objects fn run_decode_no_delta(rel_path: &str, kind: HashKind) { let _guard = set_hash_kind(kind); diff --git a/src/internal/pack/encode.rs b/src/internal/pack/encode.rs index 1ffc7f3b..eb6713e9 100644 --- a/src/internal/pack/encode.rs +++ b/src/internal/pack/encode.rs @@ -753,9 +753,22 @@ mod tests { /// Check if the given data is a valid pack file format by attempting to decode it. fn check_format(data: &Vec) { + // Use a smaller cap on 32-bit targets to avoid usize overflow. + let max_pack_size_u64 = if cfg!(target_pointer_width = "64") { + 6u64 * 1024 * 1024 * 1024 + } else { + 2u64 * 1024 * 1024 * 1024 + }; + let max_pack_size = usize::try_from(max_pack_size_u64).unwrap_or_else(|_| { + panic!( + "internal assertion failed: pack size cap {} does not fit in usize on this \ + target; this should be unreachable given the target_pointer_width configuration", + max_pack_size_u64 + ) + }); let mut p = Pack::new( None, - Some(1024 * 1024 * 1024 * 6), // 6GB + Some(max_pack_size), // 6GB on 64-bit, 2GB on 32-bit Some(PathBuf::from("/tmp/.cache_temp")), true, );