Auto merge of #3723 - RalfJung:win-tls-callback, r=RalfJung

iter_exported_symbols: also walk used statics in local crate

Since https://github.com/rust-lang/rust/pull/126938 got reverted, we need a different approach.

Fixes https://github.com/rust-lang/miri/issues/3722
This commit is contained in:
bors 2024-06-29 10:20:13 +00:00
commit 9d920ed333
3 changed files with 43 additions and 8 deletions

View File

@ -14,6 +14,7 @@
def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}, def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE},
}; };
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::mir; use rustc_middle::mir;
@ -163,22 +164,39 @@ pub fn iter_exported_symbols<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>, mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
// First, the symbols in the local crate. We can't use `exported_symbols` here as that
// skips `#[used]` statics (since `reachable_set` skips them in binary crates).
// So we walk all HIR items ourselves instead.
let crate_items = tcx.hir_crate_items(());
for def_id in crate_items.definitions() {
let exported = tcx.def_kind(def_id).has_codegen_attrs() && {
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
codegen_attrs.contains_extern_indicator()
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
};
if exported {
f(LOCAL_CRATE, def_id.into())?;
}
}
// Next, all our dependencies.
// `dependency_formats` includes all the transitive informations needed to link a crate, // `dependency_formats` includes all the transitive informations needed to link a crate,
// which is what we need here since we need to dig out `exported_symbols` from all transitive // which is what we need here since we need to dig out `exported_symbols` from all transitive
// dependencies. // dependencies.
let dependency_formats = tcx.dependency_formats(()); let dependency_formats = tcx.dependency_formats(());
// Find the dependencies of the executable we are running.
let dependency_format = dependency_formats let dependency_format = dependency_formats
.iter() .iter()
.find(|(crate_type, _)| *crate_type == CrateType::Executable) .find(|(crate_type, _)| *crate_type == CrateType::Executable)
.expect("interpreting a non-executable crate"); .expect("interpreting a non-executable crate");
for cnum in iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map( for cnum in dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| {
|(num, &linkage)| { // We add 1 to the number because that's what rustc also does everywhere it
// We add 1 to the number because that's what rustc also does everywhere it // calls `CrateNum::new`...
// calls `CrateNum::new`... #[allow(clippy::arithmetic_side_effects)]
#[allow(clippy::arithmetic_side_effects)] (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
(linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) }) {
},
)) {
// We can ignore `_export_info` here: we are a Rust crate, and everything is exported // We can ignore `_export_info` here: we are a Rust crate, and everything is exported
// from a Rust crate. // from a Rust crate.
for &(symbol, _export_info) in tcx.exported_symbols(cnum) { for &(symbol, _export_info) in tcx.exported_symbols(cnum) {

View File

@ -0,0 +1,16 @@
//! Ensure that we call Windows TLS callbacks in the local crate.
//@only-target-windows
// Calling eprintln in the callback seems to (re-)initialize some thread-local storage
// and then leak the memory allocated for that. Let's just ignore these leaks,
// that's not what this test is about.
//@compile-flags: -Zmiri-ignore-leaks
#[link_section = ".CRT$XLB"]
#[used] // Miri only considers explicitly `#[used]` statics for `lookup_link_section`
pub static CALLBACK: unsafe extern "system" fn(*const (), u32, *const ()) = tls_callback;
unsafe extern "system" fn tls_callback(_h: *const (), _dw_reason: u32, _pv: *const ()) {
eprintln!("in tls_callback");
}
fn main() {}

View File

@ -0,0 +1 @@
in tls_callback