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:
commit
9d920ed333
@ -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) {
|
||||||
|
16
src/tools/miri/tests/pass/tls/win_tls_callback.rs
Normal file
16
src/tools/miri/tests/pass/tls/win_tls_callback.rs
Normal 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() {}
|
1
src/tools/miri/tests/pass/tls/win_tls_callback.stderr
Normal file
1
src/tools/miri/tests/pass/tls/win_tls_callback.stderr
Normal file
@ -0,0 +1 @@
|
|||||||
|
in tls_callback
|
Loading…
Reference in New Issue
Block a user