Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions src/archive_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>>,
sym_map: &mut Option<&mut SymMap>,
object_reader: &ObjectReader,
Expand All @@ -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
Expand Down Expand Up @@ -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();
Expand Down
23 changes: 23 additions & 0 deletions tests/multiple_objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
);
}
Loading