From 9f1cbd141ff4ee8d8c03bb084f62296c009b490e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 13 May 2026 13:15:17 +0000 Subject: [PATCH] Avoid panic when there are more than 64k archive members --- src/archive_writer.rs | 15 +++++++-------- tests/multiple_objects.rs | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/archive_writer.rs b/src/archive_writer.rs index e1cbbf5..eaf38a7 100644 --- a/src/archive_writer.rs +++ b/src/archive_writer.rs @@ -549,9 +549,13 @@ fn is_import_descriptor(name: &[u8]) -> bool { // NOTE: LLVM calls this getSymbols and has the get_native_object_symbols // function (moved to object_reader.rs) inlined. +// NOTE: LLVM uses u16 as symbol index. This is only used for the COFF archive +// format. If there are more than 0xfffe archive members however we switch to +// the GNU archive format which ignores the symbol index. As such to avoid an +// overflow accept usize here and only convert to u16 on COFF archives. fn write_symbols( obj: &[u8], - index: u16, + index: usize, sym_names: &mut Cursor>, sym_map: &mut Option<&mut SymMap>, object_reader: &ObjectReader, @@ -575,6 +579,7 @@ fn write_symbols( (object_reader.get_symbols)(obj, &mut |name| { if let Some(map) = &mut map { + let index = u16::try_from(index).unwrap(); let entry = map.entry(name.to_vec().into_boxed_slice()); if matches!(entry, std::collections::btree_map::Entry::Occupied(_)) { return Ok(()); // ignore duplicated symbol @@ -813,13 +818,7 @@ fn compute_member_data<'a, S: Write + Seek>( )?; } - let symbols = write_symbols( - buf, - index.try_into().unwrap(), - sym_names, - sym_map, - m.object_reader, - )?; + let symbols = write_symbols(buf, index, sym_names, sym_map, m.object_reader)?; has_object = true; pos += u64::try_from(header.len() + data.len() + padding.len()).unwrap(); diff --git a/tests/multiple_objects.rs b/tests/multiple_objects.rs index 913bc5a..bf8fce9 100644 --- a/tests/multiple_objects.rs +++ b/tests/multiple_objects.rs @@ -57,3 +57,26 @@ fn multiple_objects_same_name() { }, ); } + +/// Test that we don't get a member index overflow when there are more members than fit in a u16. +#[test] +#[ignore = "takes >60s and requires `ulimit -s unlimited`"] +fn many_objects() { + common::generate_archive_and_compare( + "many_objects", + |architecture, subarch, endianness, binary_format| { + let mut object1 = write::Object::new(binary_format, architecture, endianness); + object1.set_sub_architecture(subarch); + common::add_file_with_functions_to_object(&mut object1, b"file1.c", &[b"func1"]); + + let mut members = vec![]; + for i in 0..u32::from(u16::MAX) + 2 { + members.push(( + &*Box::leak(format!("{i:x}").into_boxed_str()), + object1.write().unwrap(), + )); + } + members + }, + ); +}