Skip to content

Make compressed rmeta contain compressed data length after header #101550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 5, 2023
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
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,13 @@ pub fn create_compressed_metadata_file(
symbol_name: &str,
) -> Vec<u8> {
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();
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 {
return compressed.to_vec();
};
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_metadata/src/locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,9 @@ fn get_metadata_section<'p>(
loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
// The header is uncompressed
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);
let header = &buf[..cmp::min(header_len, buf.len())];
if header != METADATA_HEADER {
Expand All @@ -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
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());
// 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.
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ pub(crate) fn rustc_version() -> String {
/// Metadata encoding version.
/// 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()`.
const METADATA_VERSION: u8 = 6;
const METADATA_VERSION: u8 = 7;

/// Metadata header which includes `METADATA_VERSION`.
///
/// This header is followed by the position of the `CrateRoot`,
/// which is encoded as a 32-bit big-endian unsigned integer,
/// and further followed by the rustc version string.
/// This header is followed by the length of the compressed data, then
/// the position of the `CrateRoot`, which is encoded as a 32-bit big-endian
/// 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];

/// A value of type T referred to by its absolute position
Expand Down
13 changes: 8 additions & 5 deletions src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,20 @@ pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
let version = u32::from_be_bytes([dot_rustc[4], dot_rustc[5], dot_rustc[6], dot_rustc[7]]);
// Last supported version is:
// https://github.com/rust-lang/rust/commit/0696e79f2740ad89309269b460579e548a5cd632
match version {
5 | 6 => {}
let snappy_portion = match version {
5 | 6 => &dot_rustc[8..],
7 => {
let len_bytes = &dot_rustc[8..12];
let data_len = u32::from_be_bytes(len_bytes.try_into().unwrap()) as usize;
&dot_rustc[12..data_len + 12]
}
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("unsupported metadata version {version}"),
));
}
}

let snappy_portion = &dot_rustc[8..];
};

let mut snappy_decoder = SnapDecoder::new(snappy_portion);

Expand Down