Skip to content
Open
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
35 changes: 21 additions & 14 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,9 @@ fn link_rlib<'a>(
.collect();

let metadata_link_file = if matches!(flavor, RlibFlavor::Normal) {
let metadata_link = rmeta_link::RmetaLink { rust_object_files };
let native_lib_filenames: Vec<Option<String>> =
crate_info.used_libraries_filenames.iter().map(|f| f.map(|s| s.to_string())).collect();
let metadata_link = rmeta_link::RmetaLink { rust_object_files, native_lib_filenames };
let metadata_link_data = metadata_link.encode();
let (wrapper, _) =
create_wrapper_file(sess, rmeta_link::SECTION.to_string(), &metadata_link_data);
Expand Down Expand Up @@ -386,12 +388,12 @@ fn link_rlib<'a>(
// feature then we'll need to figure out how to record what objects were
// loaded from the libraries found here and then encode that into the
// metadata of the rlib we're generating somehow.
for lib in crate_info.used_libraries.iter() {
for (i, lib) in crate_info.used_libraries.iter().enumerate() {
let NativeLibKind::Static { bundle: None | Some(true), .. } = lib.kind else {
continue;
};
if flavor == RlibFlavor::Normal
&& let Some(filename) = lib.filename
&& let Some(filename) = crate_info.used_libraries_filenames[i]
{
let path = find_native_static_library(filename.as_str(), true, sess);
let src = read(path)
Expand Down Expand Up @@ -504,11 +506,16 @@ fn link_staticlib(
let lto = are_upstream_rust_objects_already_included(sess)
&& !ignored_for_lto(sess, crate_info, cnum);

let native_libs = crate_info.native_libraries[&cnum].iter();
let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib));
let relevant_libs: FxIndexSet<_> = relevant.filter_map(|lib| lib.filename).collect();
let native_libs = &crate_info.native_libraries[&cnum];
let filenames = &crate_info.native_libraries_filenames[&cnum];
let relevant_libs: FxIndexSet<_> = native_libs
.iter()
.zip(filenames.iter())
.filter(|(lib, _)| relevant_lib(sess, lib))
.filter_map(|(_, f)| *f)
.collect();

let bundled_libs: FxIndexSet<_> = native_libs.filter_map(|lib| lib.filename).collect();
let bundled_libs: FxIndexSet<_> = filenames.iter().filter_map(|f| *f).collect();
ab.add_archive(
path,
Some(Box::new(move |fname: &str, metadata_link| {
Expand Down Expand Up @@ -2893,13 +2900,13 @@ fn add_native_libs_from_crate(
.unwrap_or_else(|e| sess.dcx().emit_fatal(e));
}

let native_libs = match cnum {
LOCAL_CRATE => &crate_info.used_libraries,
_ => &crate_info.native_libraries[&cnum],
let (native_libs, filenames): (&Vec<NativeLib>, &Vec<Option<Symbol>>) = match cnum {
LOCAL_CRATE => (&crate_info.used_libraries, &crate_info.used_libraries_filenames),
_ => (&crate_info.native_libraries[&cnum], &crate_info.native_libraries_filenames[&cnum]),
};

let mut last = (None, NativeLibKind::Unspecified, false);
for lib in native_libs {
for (i, lib) in native_libs.iter().enumerate() {
if !relevant_lib(sess, lib) {
continue;
}
Expand All @@ -2919,7 +2926,7 @@ fn add_native_libs_from_crate(
let bundle = bundle.unwrap_or(true);
let whole_archive = whole_archive == Some(true);
if bundle && cnum != LOCAL_CRATE {
if let Some(filename) = lib.filename {
if let Some(filename) = filenames[i] {
// If rlib contains native libs as archives, they are unpacked to tmpdir.
let path = tmpdir.join(filename.as_str());
cmd.link_staticlib_by_path(&path, whole_archive);
Expand Down Expand Up @@ -3040,9 +3047,9 @@ fn add_upstream_rust_crates(
match linkage {
Linkage::Static | Linkage::IncludedFromDylib | Linkage::NotLinked => {
if link_static_crate {
bundled_libs = crate_info.native_libraries[&cnum]
bundled_libs = crate_info.native_libraries_filenames[&cnum]
.iter()
.filter_map(|lib| lib.filename)
.filter_map(|f| *f)
.collect();
add_static_crate(
cmd,
Expand Down
35 changes: 35 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,41 @@ impl MetadataLoader for DefaultMetadataLoader {
load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
}
}

fn get_rlib_native_lib_filenames(&self, target: &Target, path: &Path) -> Vec<Option<String>> {
debug!("getting rmeta-link native lib filenames for {}", path.display());
let Ok(file) = File::open(path) else {
debug!("failed to open rlib for native-lib filenames: {}", path.display());
return Vec::new();
};
let Ok(mmap) = (unsafe { Mmap::map(file) }) else {
debug!("failed to mmap rlib for native-lib filenames: {}", path.display());
return Vec::new();
};

if target.is_like_aix {
let Ok(archive) = object::read::archive::ArchiveFile::parse(&*mmap) else {
return Vec::new();
};
for entry in archive.members() {
let Ok(entry) = entry else { continue };
if entry.name() == super::rmeta_link::FILENAME.as_bytes() {
let Ok(member_data) = entry.data(&*mmap) else { continue };
let Ok(section_data) = get_metadata_xcoff(path, member_data) else {
continue;
};
return super::rmeta_link::RmetaLink::decode(section_data)
.map(|rl| rl.native_lib_filenames)
.unwrap_or_default();
}
}
return Vec::new();
}

super::rmeta_link::read_from_data(&mmap, path)
.map(|rl| rl.native_lib_filenames)
.unwrap_or_default()
}
}

pub(super) fn search_for_section<'a>(
Expand Down
13 changes: 10 additions & 3 deletions compiler/rustc_codegen_ssa/src/back/rmeta_link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,28 @@ pub(crate) const SECTION: &str = ".rmeta-link";

pub struct RmetaLink {
pub rust_object_files: Vec<String>,
pub native_lib_filenames: Vec<Option<String>>,
}

impl RmetaLink {
pub(crate) fn encode(&self) -> Vec<u8> {
let mut encoder = MemEncoder::new();
self.rust_object_files.encode(&mut encoder);
self.native_lib_filenames.encode(&mut encoder);
let mut data = encoder.finish();
data.extend_from_slice(MAGIC_END_BYTES);
data
}

pub(crate) fn decode(data: &[u8]) -> Option<RmetaLink> {
let mut decoder = MemDecoder::new(data, 0).ok()?;
let rust_object_files = Vec::<String>::decode(&mut decoder);
Some(RmetaLink { rust_object_files })
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
Copy link
Copy Markdown
Contributor

@petrochenkov petrochenkov May 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the motivation for this change?
Currently the compiler can ICE if corrupted metadata is given to it, that's considered ok.

View changes since the review

let mut decoder = MemDecoder::new(data, 0).ok()?;
let rust_object_files = Vec::<String>::decode(&mut decoder);
let native_lib_filenames = Vec::<Option<String>>::decode(&mut decoder);
Some(RmetaLink { rust_object_files, native_lib_filenames })
}))
.ok()
.flatten()
}
}

Expand Down
27 changes: 22 additions & 5 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_hir::attrs::{DebuggerVisualizerType, OptimizeAttr};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ItemId, Target, find_attr};
use rustc_metadata::creader::CStore;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Dependencies;
Expand Down Expand Up @@ -50,7 +51,8 @@ use crate::mir::operand::OperandValue;
use crate::mir::place::PlaceRef;
use crate::traits::*;
use crate::{
CachedModuleCodegen, CodegenLintLevelSpecs, CrateInfo, ModuleCodegen, errors, meth, mir,
CachedModuleCodegen, CodegenLintLevelSpecs, CrateInfo, ModuleCodegen, NativeLib, errors, meth,
mir,
};

pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
Expand Down Expand Up @@ -948,7 +950,9 @@ impl CrateInfo {
profiler_runtime: None,
is_no_builtins: Default::default(),
native_libraries: Default::default(),
native_libraries_filenames: Default::default(),
used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
used_libraries_filenames: tcx.native_library_filenames(()).clone(),
crate_name: UnordMap::with_capacity(n_crates),
used_crates,
used_crate_source: UnordMap::with_capacity(n_crates),
Expand All @@ -964,11 +968,24 @@ impl CrateInfo {
info.native_libraries.reserve(n_crates);

for &cnum in crates.iter() {
info.native_libraries
.insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
info.crate_name.insert(cnum, tcx.crate_name(cnum));

let native_libs: Vec<NativeLib> =
tcx.native_libraries(cnum).iter().map(Into::into).collect();
let used_crate_source = tcx.used_crate_source(cnum);
let mut filenames_vec: Vec<Option<Symbol>> = vec![None; native_libs.len()];
if let Some(rlib_path) = used_crate_source.rlib.as_ref() {
let cstore = CStore::from_tcx(tcx);
let filenames = cstore
.metadata_loader()
.get_rlib_native_lib_filenames(&tcx.sess.target, rlib_path);
for (out, raw) in filenames_vec.iter_mut().zip(filenames.iter()) {
if let Some(name) = raw {
*out = Some(Symbol::intern(name));
}
}
}
info.native_libraries.insert(cnum, native_libs);
info.native_libraries_filenames.insert(cnum, filenames_vec);
info.crate_name.insert(cnum, tcx.crate_name(cnum));
info.used_crate_source.insert(cnum, Arc::clone(used_crate_source));
if tcx.is_profiler_runtime(cnum) {
info.profiler_runtime = Some(cnum);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ bitflags::bitflags! {
pub struct NativeLib {
pub kind: NativeLibKind,
pub name: Symbol,
pub filename: Option<Symbol>,
pub cfg: Option<CfgEntry>,
pub verbatim: bool,
pub dll_imports: Vec<cstore::DllImport>,
Expand All @@ -218,7 +217,6 @@ impl From<&cstore::NativeLib> for NativeLib {
fn from(lib: &cstore::NativeLib) -> Self {
NativeLib {
kind: lib.kind,
filename: lib.filename,
name: lib.name,
cfg: lib.cfg.clone(),
verbatim: lib.verbatim.unwrap_or(false),
Expand Down Expand Up @@ -248,8 +246,10 @@ pub struct CrateInfo {
pub profiler_runtime: Option<CrateNum>,
pub is_no_builtins: FxHashSet<CrateNum>,
pub native_libraries: FxIndexMap<CrateNum, Vec<NativeLib>>,
pub native_libraries_filenames: FxIndexMap<CrateNum, Vec<Option<Symbol>>>,
pub crate_name: UnordMap<CrateNum, Symbol>,
pub used_libraries: Vec<NativeLib>,
pub used_libraries_filenames: Vec<Option<Symbol>>,
pub used_crate_source: UnordMap<CrateNum, Arc<CrateSource>>,
pub used_crates: Vec<CrateNum>,
pub dependency_formats: Arc<Dependencies>,
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ use crate::rmeta::{
pub trait MetadataLoader {
fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;

fn get_rlib_native_lib_filenames(
&self,
_target: &Target,
_filename: &Path,
) -> Vec<Option<String>> {
Vec::new()
}
}

pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync;
Expand Down Expand Up @@ -234,6 +242,10 @@ impl CStore {
self.metas[cnum].as_ref().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"))
}

pub fn metadata_loader(&self) -> &MetadataLoaderDyn {
&*self.metadata_loader
}

pub(crate) fn get_crate_data_mut(&mut self, cnum: CrateNum) -> &mut CrateMetadata {
self.metas[cnum].as_mut().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"))
}
Expand Down
23 changes: 7 additions & 16 deletions compiler/rustc_metadata/src/native_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib>
collector.libs
}

pub(crate) fn collect_filenames(tcx: TyCtxt<'_>, _: ()) -> Vec<Option<Symbol>> {
tcx.native_libraries(LOCAL_CRATE)
.iter()
.map(|lib| find_bundled_library(lib.name, lib.verbatim, lib.kind, lib.cfg.is_some(), tcx))
.collect()
}

pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
match lib.cfg {
Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(),
Expand Down Expand Up @@ -245,16 +252,8 @@ impl<'tcx> Collector<'tcx> {
}
};

let filename = find_bundled_library(
attr.name,
attr.verbatim,
attr.kind,
attr.cfg.is_some(),
self.tcx,
);
self.libs.push(NativeLib {
name: attr.name,
filename,
kind: attr.kind,
cfg: attr.cfg.clone(),
foreign_module: Some(def_id.to_def_id()),
Expand Down Expand Up @@ -334,16 +333,8 @@ impl<'tcx> Collector<'tcx> {
// Add if not found
let new_name: Option<&str> = passed_lib.new_name.as_deref();
let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name));
let filename = find_bundled_library(
name,
passed_lib.verbatim,
passed_lib.kind,
false,
self.tcx,
);
self.libs.push(NativeLib {
name,
filename,
kind: passed_lib.kind,
cfg: None,
foreign_module: None,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
})
},
native_libraries: native_libs::collect,
native_library_filenames: native_libs::collect_filenames,
foreign_modules: foreign_modules::collect,
externally_implementable_items: eii::collect,

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,11 @@ rustc_queries! {
separate_provide_extern
}

query native_library_filenames(_: ()) -> &'tcx Vec<Option<Symbol>> {
arena_cache
desc { "looking up bundled native library filenames of the local crate" }
}

query shallow_lint_levels_on(key: hir::OwnerId) -> &'tcx rustc_middle::lint::ShallowLintLevelMap {
arena_cache
desc { "looking up lint levels for `{}`", tcx.def_path_str(key) }
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_session/src/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,10 @@ pub enum LinkagePreference {
RequireStatic,
}

#[derive(Debug, Encodable, Decodable, StableHash)]
#[derive(Debug, StableHash, Encodable, Decodable)]
pub struct NativeLib {
pub kind: NativeLibKind,
pub name: Symbol,
/// If packed_bundled_libs enabled, actual filename of library is stored.
pub filename: Option<Symbol>,
pub cfg: Option<CfgEntry>,
pub foreign_module: Option<DefId>,
pub verbatim: Option<bool>,
Expand Down
Loading