1
Fork 0

Auto merge of #101550 - CraftSpider:link-dead-windows, r=wesleywiser

Make compressed rmeta contain compressed data length after header

Fixes #90056, which is caused by link.exe introducing padding to the `.rustc` section, since it assumes this will have no effect besides allowing it to possibly use the extra space in future links.
This commit is contained in:
bors 2023-03-05 02:00:58 +00:00
commit a512c6c771
3 changed files with 20 additions and 5 deletions

View file

@ -306,7 +306,13 @@ pub fn create_compressed_metadata_file(
symbol_name: &str, symbol_name: &str,
) -> Vec<u8> { ) -> Vec<u8> {
let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
// Our length will be backfilled once we're done writing
compressed.write_all(&[0; 4]).unwrap();
FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap(); FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
let meta_len = rustc_metadata::METADATA_HEADER.len();
let data_len = (compressed.len() - meta_len - 4) as u32;
compressed[meta_len..meta_len + 4].copy_from_slice(&data_len.to_be_bytes());
let Some(mut file) = create_object_file(sess) else { let Some(mut file) = create_object_file(sess) else {
return compressed.to_vec(); return compressed.to_vec();
}; };

View file

@ -789,6 +789,9 @@ fn get_metadata_section<'p>(
loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?; loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
// The header is uncompressed // The header is uncompressed
let header_len = METADATA_HEADER.len(); let header_len = METADATA_HEADER.len();
// header + u32 length of data
let data_start = header_len + 4;
debug!("checking {} bytes of metadata-version stamp", header_len); debug!("checking {} bytes of metadata-version stamp", header_len);
let header = &buf[..cmp::min(header_len, buf.len())]; let header = &buf[..cmp::min(header_len, buf.len())];
if header != METADATA_HEADER { if header != METADATA_HEADER {
@ -798,8 +801,14 @@ fn get_metadata_section<'p>(
))); )));
} }
// Length of the compressed stream - this allows linkers to pad the section if they want
let Ok(len_bytes) = <[u8; 4]>::try_from(&buf[header_len..cmp::min(data_start, buf.len())]) else {
return Err(MetadataError::LoadFailure("invalid metadata length found".to_string()));
};
let compressed_len = u32::from_be_bytes(len_bytes) as usize;
// Header is okay -> inflate the actual metadata // Header is okay -> inflate the actual metadata
let compressed_bytes = &buf[header_len..]; let compressed_bytes = &buf[data_start..(data_start + compressed_len)];
debug!("inflating {} bytes of compressed metadata", compressed_bytes.len()); debug!("inflating {} bytes of compressed metadata", compressed_bytes.len());
// Assume the decompressed data will be at least the size of the compressed data, so we // Assume the decompressed data will be at least the size of the compressed data, so we
// don't have to grow the buffer as much. // don't have to grow the buffer as much.

View file

@ -55,13 +55,13 @@ pub(crate) fn rustc_version() -> String {
/// Metadata encoding version. /// Metadata encoding version.
/// N.B., increment this if you change the format of metadata such that /// N.B., increment this if you change the format of metadata such that
/// the rustc version can't be found to compare with `rustc_version()`. /// the rustc version can't be found to compare with `rustc_version()`.
const METADATA_VERSION: u8 = 6; const METADATA_VERSION: u8 = 7;
/// Metadata header which includes `METADATA_VERSION`. /// Metadata header which includes `METADATA_VERSION`.
/// ///
/// This header is followed by the position of the `CrateRoot`, /// This header is followed by the length of the compressed data, then
/// which is encoded as a 32-bit big-endian unsigned integer, /// the position of the `CrateRoot`, which is encoded as a 32-bit big-endian
/// and further followed by the rustc version string. /// unsigned integer, and further followed by the rustc version string.
pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
/// A value of type T referred to by its absolute position /// A value of type T referred to by its absolute position