From dce3947110a73efebb756242d5c775a3ddad32a9 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 12:50:45 -0500 Subject: [PATCH 1/6] Try adding metadata length prefix, and obey it while decoding --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 1 + compiler/rustc_metadata/src/locator.rs | 9 ++++++++- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 7d3c14fec5fbf..190cd69a0e9cf 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -305,6 +305,7 @@ pub fn create_compressed_metadata_file( symbol_name: &str, ) -> Vec { let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); + compressed.write_all(&(metadata.raw_data().len() as u32).to_be_bytes()).unwrap(); FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap(); let Some(mut file) = create_object_file(sess) else { return compressed.to_vec(); diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 755a24253504e..285d6e22d47d6 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -798,8 +798,15 @@ fn get_metadata_section<'p>( ))); } + // Length of the compressed stream - this allows linkers to pad the section if they want + let usize_len = core::mem::size_of::(); + let Ok(len_bytes) = <[u8; 4]>::try_from(&buf[header_len..cmp::min(header_len + usize_len, 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[header_len..compressed_len + header_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. diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 01691398ad089..9ed4d241bd037 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -55,7 +55,7 @@ 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`. /// From 7df53d5e18cc5b39d9452e4aa3c653d0efa9f65f Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 13:39:28 -0500 Subject: [PATCH 2/6] Fix metadata encoding and decoding to use the right length --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 7 ++++++- compiler/rustc_metadata/src/locator.rs | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 190cd69a0e9cf..75daf33db3047 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -305,8 +305,13 @@ pub fn create_compressed_metadata_file( symbol_name: &str, ) -> Vec { let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); - compressed.write_all(&(metadata.raw_data().len() as u32).to_be_bytes()).unwrap(); + // 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(); }; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 285d6e22d47d6..ea1ba8a9eda94 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -799,14 +799,14 @@ fn get_metadata_section<'p>( } // Length of the compressed stream - this allows linkers to pad the section if they want - let usize_len = core::mem::size_of::(); - let Ok(len_bytes) = <[u8; 4]>::try_from(&buf[header_len..cmp::min(header_len + usize_len, buf.len())]) else { + let u32_len = core::mem::size_of::(); + let Ok(len_bytes) = <[u8; 4]>::try_from(&buf[header_len..cmp::min(header_len + u32_len, 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..compressed_len + header_len]; + let compressed_bytes = &buf[(header_len + u32_len)..(compressed_len + header_len + u32_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. From a9c3eb91e9f5a8da24cb6ef8254458a65bfcb77f Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 13:44:14 -0500 Subject: [PATCH 3/6] Bind header+u32 to variable for clearer math --- compiler/rustc_metadata/src/locator.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index ea1ba8a9eda94..82a321334ae11 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -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(); + let u32_len = core::mem::size_of::(); + let data_start = header_len + u32_len; + debug!("checking {} bytes of metadata-version stamp", header_len); let header = &buf[..cmp::min(header_len, buf.len())]; if header != METADATA_HEADER { @@ -799,14 +802,13 @@ fn get_metadata_section<'p>( } // Length of the compressed stream - this allows linkers to pad the section if they want - let u32_len = core::mem::size_of::(); - let Ok(len_bytes) = <[u8; 4]>::try_from(&buf[header_len..cmp::min(header_len + u32_len, buf.len())]) else { + 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 + u32_len)..(compressed_len + header_len + u32_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. From c14edf90db4b36659a7987bc2f4dcd7247379914 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 13:45:15 -0500 Subject: [PATCH 4/6] Replace u32_len with constant --- compiler/rustc_metadata/src/locator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 82a321334ae11..c48e681eb94ad 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -789,8 +789,8 @@ 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(); - let u32_len = core::mem::size_of::(); - let data_start = header_len + u32_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())]; From 22c80a0bf6ec4608be8a17796e4d1801a8b45c0c Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 14:23:39 -0500 Subject: [PATCH 5/6] Add v7 support to rust-analyzer --- .../crates/proc-macro-api/src/version.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs index 40125c2a512ad..cf637ec359a2d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs @@ -120,17 +120,20 @@ pub fn read_version(dylib_path: &AbsPath) -> io::Result { 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); From 79f0021c16e98e72b8f20b3b11f8e7feac1aedc4 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Tue, 28 Feb 2023 15:52:00 -0500 Subject: [PATCH 6/6] Update header comment --- compiler/rustc_metadata/src/rmeta/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 9ed4d241bd037..3800b27079455 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -59,9 +59,9 @@ 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