未验证 提交 41f33a64 编写于 作者: H hyd-dev

Implement calls to exported symbols

上级 71f41405
#![feature(rustc_private)]
#![feature(rustc_private, bool_to_option, stmt_expr_attributes)]
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_metadata;
extern crate rustc_middle;
extern crate rustc_session;
use std::convert::TryFrom;
use std::env;
use std::path::PathBuf;
use std::rc::Rc;
use std::str::FromStr;
use hex::FromHexError;
......@@ -16,14 +19,34 @@
use rustc_driver::Compilation;
use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType};
use rustc_middle::ty::TyCtxt;
use rustc_session::{config::ErrorOutputType, CtfeBacktrace};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_interface::interface::Config;
use rustc_middle::{
middle::exported_symbols::{ExportedSymbol, SymbolExportLevel},
ty::{query::Providers, TyCtxt},
};
use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace};
struct MiriCompilerCalls {
miri_config: miri::MiriConfig,
}
impl rustc_driver::Callbacks for MiriCompilerCalls {
fn config(&mut self, config: &mut Config) {
config.override_queries = Some(|_, _, external_providers| {
external_providers.used_crate_source = |tcx, cnum| {
let mut providers = Providers::default();
rustc_metadata::provide_extern(&mut providers);
let mut crate_source = (providers.used_crate_source)(tcx, cnum);
// HACK: rustc will emit "crate ... required to be available in rlib format, but
// was not found in this form" errors once we use `tcx.dependency_formats()` if
// there's no rlib provided, so setting a dummy path here to workaround those errors.
Rc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
crate_source
};
});
}
fn after_analysis<'tcx>(
&mut self,
compiler: &rustc_interface::interface::Compiler,
......@@ -67,6 +90,39 @@ fn after_analysis<'tcx>(
}
}
struct MiriBeRustCompilerCalls {
target_crate: bool,
}
impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
fn config(&mut self, config: &mut Config) {
if config.opts.prints.is_empty() && self.target_crate {
// Queries overriden here affects the data stored in `rmeta` files of dependencies,
// which will be used later in non-`MIRI_BE_RUSTC` mode.
config.override_queries = Some(|_, local_providers, _| {
// `exported_symbols()` provided by rustc always returns empty result if
// `tcx.sess.opts.output_types.should_codegen()` is false.
local_providers.exported_symbols = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
tcx.arena.alloc_from_iter(
// This is based on:
// 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,
))
}),
)
}
});
}
}
}
fn init_early_loggers() {
// Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
// initialize them both, and we always initialize `miri`'s first.
......@@ -179,11 +235,7 @@ fn main() {
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
rustc_driver::init_rustc_env_logger();
// Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building a
// "host" crate. That may cause procedural macros (and probably build scripts) to depend
// on Miri-only symbols, such as `miri_resolve_frame`:
// https://github.com/rust-lang/miri/issues/1760
let insert_default_args = if crate_kind == "target" {
let target_crate = if crate_kind == "target" {
true
} else if crate_kind == "host" {
false
......@@ -192,8 +244,16 @@ fn main() {
};
// We cannot use `rustc_driver::main` as we need to adjust the CLI arguments.
let mut callbacks = rustc_driver::TimePassesCallbacks::default();
run_compiler(env::args().collect(), &mut callbacks, insert_default_args)
run_compiler(
env::args().collect(),
&mut MiriBeRustCompilerCalls { target_crate },
// Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building
// a "host" crate. That may cause procedural macros (and probably build scripts) to
// depend on Miri-only symbols, such as `miri_resolve_frame`:
// https://github.com/rust-lang/miri/issues/1760
#[rustfmt::skip]
/* insert_default_args: */ target_crate,
)
}
// Init loggers the Miri way.
......
......@@ -5,7 +5,7 @@
use log::trace;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, Span};
use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol};
use crate::*;
......@@ -14,8 +14,18 @@ pub enum TerminationInfo {
Exit(i64),
Abort(String),
UnsupportedInIsolation(String),
ExperimentalUb { msg: String, url: String },
ExperimentalUb {
msg: String,
url: String,
},
Deadlock,
MultipleSymbolDefinitions {
link_name: Symbol,
first: SpanData,
first_crate: Symbol,
second: SpanData,
second_crate: Symbol,
},
}
impl fmt::Display for TerminationInfo {
......@@ -27,6 +37,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
UnsupportedInIsolation(msg) => write!(f, "{}", msg),
ExperimentalUb { msg, .. } => write!(f, "{}", msg),
Deadlock => write!(f, "the evaluated program deadlocked"),
MultipleSymbolDefinitions { link_name, .. } =>
write!(f, "multiple definitions of symbol `{}`", link_name),
}
}
}
......@@ -55,19 +67,25 @@ pub fn report_error<'tcx, 'mir>(
use TerminationInfo::*;
let title = match info {
Exit(code) => return Some(*code),
Abort(_) => "abnormal termination",
UnsupportedInIsolation(_) => "unsupported operation",
ExperimentalUb { .. } => "Undefined Behavior",
Deadlock => "deadlock",
Abort(_) => Some("abnormal termination"),
UnsupportedInIsolation(_) => Some("unsupported operation"),
ExperimentalUb { .. } => Some("Undefined Behavior"),
Deadlock => Some("deadlock"),
MultipleSymbolDefinitions { .. } => None,
};
#[rustfmt::skip]
let helps = match info {
UnsupportedInIsolation(_) =>
vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")],
vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation"))],
ExperimentalUb { url, .. } =>
vec![
format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"),
format!("see {} for further information", url),
(None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")),
(None, format!("see {} for further information", url)),
],
MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
vec![
(Some(*first), format!("it's first defined here, in crate `{}`", first_crate)),
(Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)),
],
_ => vec![],
};
......@@ -90,26 +108,26 @@ pub fn report_error<'tcx, 'mir>(
#[rustfmt::skip]
let helps = match e.kind() {
Unsupported(UnsupportedOpInfo::NoMirFor(..)) =>
vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")],
vec![(None, format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"))],
Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) =>
panic!("Error should never be raised by Miri: {:?}", e.kind()),
Unsupported(_) =>
vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")],
vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic
=>
vec![
format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"),
(None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
(None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
],
UndefinedBehavior(_) =>
vec![
format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
(None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
(None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
],
_ => vec![],
};
(title, helps)
(Some(title), helps)
}
};
......@@ -118,7 +136,7 @@ pub fn report_error<'tcx, 'mir>(
report_msg(
*ecx.tcx,
/*error*/ true,
&format!("{}: {}", title, msg),
&if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() },
msg,
helps,
&ecx.generate_stacktrace(),
......@@ -157,7 +175,7 @@ fn report_msg<'tcx>(
error: bool,
title: &str,
span_msg: String,
mut helps: Vec<String>,
mut helps: Vec<(Option<SpanData>, String)>,
stacktrace: &[FrameInfo<'tcx>],
) {
let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
......@@ -177,9 +195,13 @@ fn report_msg<'tcx>(
// Show help messages.
if !helps.is_empty() {
// Add visual separator before backtrace.
helps.last_mut().unwrap().push_str("\n");
for help in helps {
err.help(&help);
helps.last_mut().unwrap().1.push_str("\n");
for (span_data, help) in helps {
if let Some(span_data) = span_data {
err.span_help(span_data.span(), &help);
} else {
err.help(&help);
}
}
}
// Add backtrace
......
......@@ -3,6 +3,7 @@
#![feature(map_try_insert)]
#![feature(never_type)]
#![feature(try_blocks)]
#![feature(bool_to_option)]
#![warn(rust_2018_idioms)]
#![allow(clippy::cast_lossless)]
......@@ -14,6 +15,7 @@
extern crate rustc_hir;
extern crate rustc_index;
extern crate rustc_mir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
......
......@@ -17,7 +17,7 @@
ty::{
self,
layout::{LayoutCx, LayoutError, TyAndLayout},
TyCtxt,
Instance, TyCtxt,
},
};
use rustc_span::def_id::DefId;
......@@ -294,6 +294,9 @@ pub struct Evaluator<'mir, 'tcx> {
/// Used with `profiler` to cache the `StringId`s for event names
/// uesd with `measureme`.
string_cache: FxHashMap<String, measureme::StringId>,
/// Cache of `Instance` exported under the given `Symbol` name.
pub(crate) exported_symbols_cache: FxHashMap<Symbol, Instance<'tcx>>,
}
impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
......@@ -322,6 +325,7 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>)
static_roots: Vec::new(),
profiler,
string_cache: Default::default(),
exported_symbols_cache: FxHashMap::default(),
}
}
}
......
......@@ -6,19 +6,37 @@
use log::trace;
use rustc_apfloat::Float;
use rustc_hir::def_id::DefId;
use rustc_hir::{
def::DefKind,
def_id::{CrateNum, DefId, LOCAL_CRATE},
};
use rustc_middle::middle::{
codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage,
exported_symbols::ExportedSymbol,
};
use rustc_middle::mir;
use rustc_middle::ty;
use rustc_span::symbol::sym;
use rustc_session::config::CrateType;
use rustc_span::{symbol::sym, Symbol};
use rustc_target::{
abi::{Align, Size},
spec::{abi::Abi, PanicStrategy},
spec::abi::Abi,
};
use super::backtrace::EvalContextExt as _;
use crate::*;
use helpers::{check_abi, check_arg_count};
/// Returned by `emulate_foreign_item_by_name`.
pub enum EmulateByNameResult {
/// The caller is expected to jump to the return block.
NeedsJumping,
/// Jumping has already been taken care of.
AlreadyJumped,
/// The item is not supported.
NotSupported,
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
/// Returns the minimum alignment for the target architecture for allocations of the given size.
......@@ -108,6 +126,76 @@ fn realloc(
}
}
/// Lookup the body of a function that has `link_name` as the symbol name.
fn lookup_exported_symbol(
&mut self,
link_name: Symbol,
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
let this = self.eval_context_mut();
let tcx = this.tcx.tcx;
// If the result was cached, just return it.
if let Some(instance) = this.machine.exported_symbols_cache.get(&link_name) {
return Ok(Some(this.load_mir(instance.def, None)?));
}
// Find it if it was not cached.
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None;
// `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
// dependencies.
let dependency_formats = tcx.dependency_formats(());
let dependency_format = dependency_formats
.iter()
.find(|(crate_type, _)| *crate_type == CrateType::Executable)
.expect("interpreting a non-executable crate");
for cnum in
iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map(
|(num, &linkage)| (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)),
))
{
// FIXME: Do we need to check `SymbolExportLevel` (the `_` below)?
for &(symbol, _) in tcx.exported_symbols(cnum) {
if let ExportedSymbol::NonGeneric(def_id) = symbol {
let attrs = tcx.codegen_fn_attrs(def_id);
let symbol_name = if let Some(export_name) = attrs.export_name {
export_name
} else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
tcx.item_name(def_id)
} else {
// Skip over items without an explicitly defined symbol name.
continue;
};
if symbol_name == link_name {
if let Some((instance, original_cnum)) = instance_and_crate {
throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions {
link_name,
first: tcx.def_span(instance.def_id()).data(),
first_crate: tcx.crate_name(original_cnum),
second: tcx.def_span(def_id).data(),
second_crate: tcx.crate_name(cnum),
});
}
if tcx.def_kind(def_id) != DefKind::Fn {
throw_ub_format!(
"attempt to call an exported symbol that is not defined as a function"
);
}
instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum));
}
}
}
}
// Cache it and load its MIR, if found.
instance_and_crate
.map(|(instance, _)| {
this.machine.exported_symbols_cache.insert(link_name, instance);
this.load_mir(instance.def, None)
})
.transpose()
}
/// Emulates calling a foreign item, failing if the item is not supported.
/// This function will handle `goto_block` if needed.
/// Returns Ok(None) if the foreign item was completely handled
......@@ -124,10 +212,12 @@ fn emulate_foreign_item(
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
let this = self.eval_context_mut();
let attrs = this.tcx.get_attrs(def_id);
let link_name = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) {
Some(name) => name.as_str(),
None => this.tcx.item_name(def_id).as_str(),
let link_name_sym = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name)
{
Some(name) => name,
None => this.tcx.item_name(def_id),
};
let link_name = link_name_sym.as_str();
// Strip linker suffixes (seen on 32-bit macOS).
let link_name = link_name.trim_end_matches("$UNIX2003");
let tcx = this.tcx.tcx;
......@@ -164,48 +254,35 @@ fn emulate_foreign_item(
"the program aborted execution".to_owned()
))
}
_ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name),
_ => {
if let Some(body) = this.lookup_exported_symbol(link_name_sym)? {
return Ok(Some(body));
}
throw_unsup_format!("can't call (diverging) foreign function: {}", link_name);
}
},
Some(p) => p,
};
// Second: some functions that we forward to MIR implementations.
match link_name {
// This matches calls to the foreign item `__rust_start_panic`, that is,
// calls to `extern "Rust" { fn __rust_start_panic(...) }`
// (and `__rust_panic_cleanup`, respectively).
// We forward this to the underlying *implementation* in the panic runtime crate.
// Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could
// also be a custom user-provided implementation via `#![feature(panic_runtime)]`
#[rustfmt::skip]
"__rust_start_panic" |
"__rust_panic_cleanup" => {
check_abi(this, abi, Abi::C { unwind: false })?;
// This replicates some of the logic in `inject_panic_runtime`.
// FIXME: is there a way to reuse that logic?
let panic_runtime = match this.tcx.sess.panic_strategy() {
PanicStrategy::Unwind => sym::panic_unwind,
PanicStrategy::Abort => sym::panic_abort,
};
let start_panic_instance =
this.resolve_path(&[&*panic_runtime.as_str(), link_name]);
return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?));
// Second: functions that return.
match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? {
EmulateByNameResult::NeedsJumping => {
trace!("{:?}", this.dump_place(**dest));
this.go_to_block(ret);
}
EmulateByNameResult::AlreadyJumped => (),
EmulateByNameResult::NotSupported => {
if let Some(body) = this.lookup_exported_symbol(link_name_sym)? {
return Ok(Some(body));
}
throw_unsup_format!("can't call foreign function: {}", link_name);
}
_ => {}
}
// Third: functions that return.
if this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? {
trace!("{:?}", this.dump_place(**dest));
this.go_to_block(ret);
}
Ok(None)
}
/// Emulates calling a foreign item using its name, failing if the item is not supported.
/// Returns `true` if the caller is expected to jump to the return block, and `false` if
/// jumping has already been taken care of.
/// Emulates calling a foreign item using its name.
fn emulate_foreign_item_by_name(
&mut self,
link_name: &str,
......@@ -213,7 +290,7 @@ fn emulate_foreign_item_by_name(
args: &[OpTy<'tcx, Tag>],
dest: &PlaceTy<'tcx, Tag>,
ret: mir::BasicBlock,
) -> InterpResult<'tcx, bool> {
) -> InterpResult<'tcx, EmulateByNameResult> {
let this = self.eval_context_mut();
// Here we dispatch all the shims for foreign functions. If you have a platform specific
......@@ -549,7 +626,9 @@ fn emulate_foreign_item_by_name(
}
};
Ok(true)
// We only fall through to here if we did *not* hit the `_` arm above,
// i.e., if we actually emulated the function.
Ok(EmulateByNameResult::NeedsJumping)
}
/// Check some basic requirements for this allocation request:
......
......@@ -6,6 +6,7 @@
use crate::*;
use helpers::{check_abi, check_arg_count};
use shims::foreign_items::EmulateByNameResult;
use shims::posix::fs::EvalContextExt as _;
use shims::posix::sync::EvalContextExt as _;
use shims::posix::thread::EvalContextExt as _;
......@@ -19,7 +20,7 @@ fn emulate_foreign_item_by_name(
args: &[OpTy<'tcx, Tag>],
dest: &PlaceTy<'tcx, Tag>,
ret: mir::BasicBlock,
) -> InterpResult<'tcx, bool> {
) -> InterpResult<'tcx, EmulateByNameResult> {
let this = self.eval_context_mut();
match link_name {
......@@ -524,6 +525,6 @@ fn emulate_foreign_item_by_name(
}
};
Ok(true)
Ok(EmulateByNameResult::NeedsJumping)
}
}
......@@ -3,6 +3,7 @@
use crate::helpers::{check_abi, check_arg_count};
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::posix::fs::EvalContextExt as _;
use shims::posix::linux::sync::futex;
use shims::posix::sync::EvalContextExt as _;
......@@ -17,7 +18,7 @@ fn emulate_foreign_item_by_name(
args: &[OpTy<'tcx, Tag>],
dest: &PlaceTy<'tcx, Tag>,
_ret: mir::BasicBlock,
) -> InterpResult<'tcx, bool> {
) -> InterpResult<'tcx, EmulateByNameResult> {
let this = self.eval_context_mut();
match link_name {
......@@ -214,10 +215,10 @@ fn emulate_foreign_item_by_name(
this.write_null(dest)?;
}
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
_ => return Ok(EmulateByNameResult::NotSupported),
};
Ok(true)
Ok(EmulateByNameResult::NeedsJumping)
}
}
......
......@@ -3,6 +3,7 @@
use crate::*;
use helpers::{check_abi, check_arg_count};
use shims::foreign_items::EmulateByNameResult;
use shims::posix::fs::EvalContextExt as _;
use shims::posix::thread::EvalContextExt as _;
......@@ -15,7 +16,7 @@ fn emulate_foreign_item_by_name(
args: &[OpTy<'tcx, Tag>],
dest: &PlaceTy<'tcx, Tag>,
_ret: mir::BasicBlock,
) -> InterpResult<'tcx, bool> {
) -> InterpResult<'tcx, EmulateByNameResult> {
let this = self.eval_context_mut();
match link_name {
......@@ -156,9 +157,9 @@ fn emulate_foreign_item_by_name(
this.write_scalar(addr, dest)?;
}
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
_ => return Ok(EmulateByNameResult::NotSupported),
};
Ok(true)
Ok(EmulateByNameResult::NeedsJumping)
}
}
......@@ -6,6 +6,7 @@
use crate::*;
use helpers::{check_abi, check_arg_count};
use shims::foreign_items::EmulateByNameResult;
use shims::windows::sync::EvalContextExt as _;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
......@@ -17,7 +18,7 @@ fn emulate_foreign_item_by_name(
args: &[OpTy<'tcx, Tag>],
dest: &PlaceTy<'tcx, Tag>,
_ret: mir::BasicBlock,
) -> InterpResult<'tcx, bool> {
) -> InterpResult<'tcx, EmulateByNameResult> {
let this = self.eval_context_mut();
// Windows API stubs.
......@@ -415,9 +416,9 @@ fn emulate_foreign_item_by_name(
this.write_scalar(Scalar::from_i32(1), dest)?;
}
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
_ => return Ok(EmulateByNameResult::NotSupported),
}
Ok(true)
Ok(EmulateByNameResult::NeedsJumping)
}
}
......@@ -14,6 +14,7 @@ version = "0.1.0"
dependencies = [
"byteorder",
"cdylib",
"exported_symbol",
"getrandom 0.1.16",
"getrandom 0.2.2",
"issue_1567",
......@@ -37,6 +38,17 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "exported_symbol"
version = "0.1.0"
dependencies = [
"exported_symbol_dep",
]
[[package]]
name = "exported_symbol_dep"
version = "0.1.0"
[[package]]
name = "getrandom"
version = "0.1.16"
......
[workspace]
members = ["subcrate", "issue-1567"]
members = ["subcrate", "issue-1567", "exported-symbol-dep"]
[package]
name = "cargo-miri-test"
......@@ -10,6 +10,7 @@ edition = "2018"
[dependencies]
byteorder = "1.0"
cdylib = { path = "cdylib" }
exported_symbol = { path = "exported-symbol" }
issue_1567 = { path = "issue-1567" }
issue_1691 = { path = "issue-1691" }
issue_1705 = { path = "issue-1705" }
......
[package]
name = "exported_symbol_dep"
version = "0.1.0"
authors = ["Miri Team"]
edition = "2018"
#[no_mangle]
fn exported_symbol() -> i32 {
123456
}
[package]
name = "exported_symbol"
version = "0.1.0"
authors = ["Miri Team"]
edition = "2018"
[dependencies]
# This will become a transitive dependency of doctests in `test-cargo-miri/src/lib.rs`,
# and the purpose of the test is to make sure Miri can find a `#[no_mangle]` function in a
# transitive dependency like `exported_symbol_dep`.
exported_symbol_dep = { path = "../exported-symbol-dep" }
extern crate exported_symbol_dep;
extern crate exported_symbol;
/// Doc-test test
/// ```rust
/// assert!(cargo_miri_test::make_true());
/// // Repeat calls to make sure the `Instance` cache is not broken.
/// for _ in 0..3 {
/// extern "Rust" {
/// fn exported_symbol() -> i32;
/// fn make_true() -> bool;
/// }
/// assert_eq!(unsafe { exported_symbol() }, 123456);
/// assert!(unsafe { make_true() });
/// }
/// ```
/// ```compile_fail
/// // Make sure `exported_symbol_dep` is not a direct dependency for doctests.
/// use exported_symbol_dep;
/// ```
/// ```rust,no_run
/// assert!(!cargo_miri_test::make_true());
......@@ -8,6 +23,7 @@
/// ```rust,compile_fail
/// assert!(cargo_miri_test::make_true() == 5);
/// ```
#[no_mangle]
pub fn make_true() -> bool {
issue_1567::use_the_dependency();
issue_1705::use_the_dependency();
......
......@@ -10,10 +10,11 @@ running 7 tests
test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out
running 3 tests
test src/lib.rs - make_true (line 2) ... ok
test src/lib.rs - make_true (line 5) ... ok
test src/lib.rs - make_true (line 8) ... ok
running 4 tests
test src/lib.rs - make_true (line 16) ... ok
test src/lib.rs - make_true (line 20) ... ok
test src/lib.rs - make_true (line 23) ... ok
test src/lib.rs - make_true (line 4) ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
......@@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME
// revisions: no_cache cache
#[no_mangle]
fn foo() {}
fn main() {
#[cfg(cache)]
{
// `Instance` caching should not suppress ABI check.
extern "Rust" {
fn foo();
}
unsafe { foo() }
}
#[cfg_attr(cache, allow(clashing_extern_declarations))]
extern "C" {
fn foo();
}
unsafe { foo() }
//[no_cache]~^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C
//[cache]~^^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C
}
// compile-flags: -Zmiri-disable-abi-check
#![feature(c_unwind)]
#[no_mangle]
extern "C-unwind" fn unwind() {
panic!();
}
fn main() {
extern "C" {
fn unwind();
}
unsafe { unwind() }
//~^ ERROR unwinding past a stack frame that does not allow unwinding
}
// revisions: extern_block definition both
#![feature(rustc_attrs, c_unwind)]
#[cfg_attr(any(definition, both), rustc_allocator_nounwind)]
#[no_mangle]
extern "C-unwind" fn nounwind() {
panic!();
}
fn main() {
extern "C-unwind" {
#[cfg_attr(any(extern_block, both), rustc_allocator_nounwind)]
fn nounwind();
}
unsafe { nounwind() }
//[extern_block]~^ ERROR unwinding past a stack frame that does not allow unwinding
//[definition]~^^ ERROR unwinding past a stack frame that does not allow unwinding
//[both]~^^^ ERROR unwinding past a stack frame that does not allow unwinding
}
#![feature(unwind_attributes)]
#![feature(c_unwind)] // make sure it doesn't insert abort-on-unwind for the `#[unwind(allowed)]` function
#[unwind(allowed)]
#[no_mangle]
extern "C" fn unwind() {
panic!();
}
fn main() {
extern "C" {
fn unwind();
}
unsafe { unwind() }
//~^ ERROR unwinding past a stack frame that does not allow unwinding
}
#[no_mangle]
fn foo() {}
//~^ HELP then it's defined here again, in crate `exported_symbol_clashing`
#[export_name = "foo"]
fn bar() {}
//~^ HELP it's first defined here, in crate `exported_symbol_clashing`
fn main() {
extern "Rust" {
fn foo();
}
unsafe { foo() }
//~^ ERROR multiple definitions of symbol `foo`
}
#[no_mangle]
fn foo() {}
fn main() {
extern "Rust" {
fn foo(_: i32);
}
unsafe { foo(1) } //~ ERROR calling a function with more arguments than it expected
}
#[no_mangle]
static FOO: () = ();
fn main() {
extern "C" {
fn FOO();
}
unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function
}
// compile-flags: -Zmiri-disable-abi-check
extern "C" {
fn miri_start_panic(payload: *mut u8) -> !;
}
fn main() {
unsafe { miri_start_panic(&mut 0) }
//~^ ERROR unwinding past a stack frame that does not allow unwinding
}
#![feature(rustc_attrs, c_unwind)]
#[rustc_allocator_nounwind]
extern "C-unwind" fn nounwind() {
panic!();
}
fn main() {
nounwind(); //~ ERROR unwinding past a stack frame that does not allow unwinding
}
#![feature(rustc_attrs)]
#[no_mangle]
extern "C" fn foo() -> i32 {
-1
}
#[export_name = "bar"]
fn bar() -> i32 {
-2
}
#[rustc_std_internal_symbol]
fn baz() -> i32 {
-3
}
// Make sure shims take precedence.
#[no_mangle]
extern "C" fn exit(_: i32) -> ! {
unreachable!()
}
#[no_mangle]
extern "C" fn ExitProcess(_: u32) -> ! {
unreachable!()
}
fn main() {
// Repeat calls to make sure the `Instance` cache is not broken.
for _ in 0..3 {
extern "C" {
fn foo() -> i32;
}
assert_eq!(unsafe { foo() }, -1);
assert_eq!(unsafe { foo() }, -1);
extern "Rust" {
fn bar() -> i32;
fn baz() -> i32;
}
assert_eq!(unsafe { bar() }, -2);
assert_eq!(unsafe { baz() }, -3);
}
}
// Make sure the workaround for "crate ... required to be available in rlib format, but was not
// found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function
// foreign function `__rust_start_panic`).
// no-prefer-dynamic
#![feature(c_unwind, unboxed_closures, unwind_attributes)]
use std::panic;
#[no_mangle]
#[unwind(allowed)]
extern "C" fn good_unwind_allowed() {
panic!();
}
#[no_mangle]
extern "C-unwind" fn good_unwind_c() {
panic!();
}
#[no_mangle]
fn good_unwind_rust() {
panic!();
}
// Diverging function calls are on a different code path.
#[no_mangle]
extern "rust-call" fn good_unwind_rust_call(_: ()) -> ! {
panic!();
}
fn main() -> ! {
extern "C" {
#[unwind(allowed)]
fn good_unwind_allowed();
}
panic::catch_unwind(|| unsafe { good_unwind_allowed() }).unwrap_err();
extern "C-unwind" {
fn good_unwind_c();
}
panic::catch_unwind(|| unsafe { good_unwind_c() }).unwrap_err();
extern "Rust" {
fn good_unwind_rust();
}
panic::catch_unwind(|| unsafe { good_unwind_rust() }).unwrap_err();
extern "rust-call" {
fn good_unwind_rust_call(_: ()) -> !;
}
unsafe { good_unwind_rust_call(()) }
}
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:12:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:17:5
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:22:5
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:28:5
// compile-flags: -Zmiri-disable-abi-check
#![feature(unwind_attributes, c_unwind)]
#[no_mangle]
extern "C-unwind" fn unwind() {
panic!();
}
fn main() {
extern "C" {
#[unwind(allowed)]
fn unwind();
}
unsafe { unwind() }
}
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_unwind_allowed.rs:6:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
#![feature(c_unwind, unboxed_closures, unwind_attributes)]
use std::panic;
extern "C-unwind" fn good_unwind_c() {
panic!();
}
#[unwind(allowed)]
extern "C" fn good_unwind_allowed() {
panic!();
}
fn good_unwind_rust() {
panic!();
}
extern "rust-call" fn good_unwind_rust_call(_: ()) {
panic!();
}
fn main() {
panic::catch_unwind(|| good_unwind_c()).unwrap_err();
panic::catch_unwind(|| good_unwind_allowed()).unwrap_err();
panic::catch_unwind(|| good_unwind_rust()).unwrap_err();
good_unwind_rust_call(());
}
thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:6:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:11:5
thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:15:5
thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:19:5
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册