diff --git a/src/bin/miri.rs b/src/bin/miri.rs index fae45d9fc0..d593f24c71 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -19,7 +19,7 @@ use log::debug; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; -use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, @@ -109,12 +109,27 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63 // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174 tcx.reachable_set(()).iter().filter_map(|&local_def_id| { - tcx.codegen_fn_attrs(local_def_id) - .contains_extern_indicator() - .then_some(( - ExportedSymbol::NonGeneric(local_def_id.to_def_id()), - SymbolExportLevel::C, - )) + // Do the same filtering that rustc does: + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102 + // Otherwise it may cause unexpected behaviours and ICEs + // (https://github.com/rust-lang/rust/issues/86261). + let is_reachable_non_generic = matches!( + tcx.hir().get(tcx.hir().local_def_id_to_hir_id(local_def_id)), + Node::Item(&hir::Item { + kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn(..), + .. + }) | Node::ImplItem(&hir::ImplItem { + kind: hir::ImplItemKind::Fn(..), + .. + }) + if !tcx.generics_of(local_def_id).requires_monomorphization(tcx) + ); + (is_reachable_non_generic + && tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator()) + .then_some(( + ExportedSymbol::NonGeneric(local_def_id.to_def_id()), + SymbolExportLevel::C, + )) }), ) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8f3dfdc4f8..bcb2d262e8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx second_crate: tcx.crate_name(cnum), }); } - if tcx.def_kind(def_id) != DefKind::Fn { + if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { throw_ub_format!( "attempt to call an exported symbol that is not defined as a function" ); diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 9a9fa4797b..7f06fdf28d 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -21,6 +21,7 @@ dependencies = [ "issue_1691", "issue_1705", "issue_1760", + "issue_rust_86261", "rand", "serde_derive", ] @@ -102,6 +103,10 @@ dependencies = [ name = "issue_1760" version = "0.1.0" +[[package]] +name = "issue_rust_86261" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.92" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index cf557bd60e..39ce1757f0 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -15,6 +15,7 @@ issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } issue_1760 = { path = "issue-1760" } +issue_rust_86261 = { path = "issue-rust-86261" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } diff --git a/test-cargo-miri/exported-symbol-dep/src/lib.rs b/test-cargo-miri/exported-symbol-dep/src/lib.rs index 4cc18fb9b2..db257dcb22 100644 --- a/test-cargo-miri/exported-symbol-dep/src/lib.rs +++ b/test-cargo-miri/exported-symbol-dep/src/lib.rs @@ -2,3 +2,12 @@ fn exported_symbol() -> i32 { 123456 } + +pub struct AssocFn; + +impl AssocFn { + #[no_mangle] + pub fn assoc_fn_as_exported_symbol() -> i32 { + -123456 + } +} diff --git a/test-cargo-miri/issue-rust-86261/Cargo.toml b/test-cargo-miri/issue-rust-86261/Cargo.toml new file mode 100644 index 0000000000..a6b65ebb53 --- /dev/null +++ b/test-cargo-miri/issue-rust-86261/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "issue_rust_86261" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" diff --git a/test-cargo-miri/issue-rust-86261/src/lib.rs b/test-cargo-miri/issue-rust-86261/src/lib.rs new file mode 100644 index 0000000000..db725fdb64 --- /dev/null +++ b/test-cargo-miri/issue-rust-86261/src/lib.rs @@ -0,0 +1,23 @@ +#![allow(unused_imports, unused_attributes, no_mangle_generic_items)] + +// Regression test for https://github.com/rust-lang/rust/issues/86261: +// `#[no_mangle]` on a `use` item. +#[no_mangle] +use std::{thread,panic, io, boxed, any, string}; + +// `#[no_mangle]` on a struct has a similar problem. +#[no_mangle] +pub struct NoMangleStruct; + +// If `#[no_mangle]` has effect on the `struct` above, calling `NoMangleStruct` will fail with +// "multiple definitions of symbol `NoMangleStruct`" error. +#[export_name = "NoMangleStruct"] +fn no_mangle_struct() {} + +// `#[no_mangle]` on a generic function can also cause ICEs. +#[no_mangle] +fn no_mangle_generic() {} + +// Same as `no_mangle_struct()` but for the `no_mangle_generic()` generic function. +#[export_name = "no_mangle_generic"] +fn no_mangle_generic2() {} diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index a5669ef308..cb1512d050 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -62,15 +62,22 @@ mod test { fn exported_symbol() { extern crate cargo_miri_test; extern crate exported_symbol; + extern crate issue_rust_86261; // Test calling exported symbols in (transitive) dependencies. // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { extern "Rust" { fn exported_symbol() -> i32; + fn assoc_fn_as_exported_symbol() -> i32; fn make_true() -> bool; + fn NoMangleStruct(); + fn no_mangle_generic(); } assert_eq!(unsafe { exported_symbol() }, 123456); + assert_eq!(unsafe { assoc_fn_as_exported_symbol() }, -123456); assert!(unsafe { make_true() }); + unsafe { NoMangleStruct() } + unsafe { no_mangle_generic() } } } }