Auto merge of #1065 - Aaron1011:fix/start-return, r=RalfJung
Propagate the return code from the `start` lang item Fixes #1064 This ensures that we set the error code properly when a panic unwinds past `main`. I'm not sure what the best way to write a test for this is
This commit is contained in:
commit
35e92d9420
@ -15,6 +15,7 @@ extern crate rustc_interface;
|
||||
extern crate syntax;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::convert::TryFrom;
|
||||
use std::env;
|
||||
|
||||
use hex::FromHexError;
|
||||
@ -39,7 +40,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
|
||||
// Add filename to `miri` arguments.
|
||||
config.args.insert(0, compiler.input().filestem().to_string());
|
||||
|
||||
miri::eval_main(tcx, entry_def_id, config);
|
||||
if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) {
|
||||
std::process::exit(i32::try_from(return_code).expect("Return value was too large!"));
|
||||
}
|
||||
});
|
||||
|
||||
compiler.session().abort_if_errors();
|
||||
|
38
src/eval.rs
38
src/eval.rs
@ -11,7 +11,7 @@ use syntax::source_map::DUMMY_SP;
|
||||
use crate::{
|
||||
EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError,
|
||||
InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag,
|
||||
TlsEvalContextExt,
|
||||
TlsEvalContextExt, MPlaceTy
|
||||
};
|
||||
|
||||
/// Configuration needed to spawn a Miri instance.
|
||||
@ -29,12 +29,15 @@ pub struct MiriConfig {
|
||||
pub seed: Option<u64>,
|
||||
}
|
||||
|
||||
// Used by priroda.
|
||||
/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
|
||||
/// the location where the return value of the `start` lang item will be
|
||||
/// written to.
|
||||
/// Public because this is also used by `priroda`.
|
||||
pub fn create_ecx<'mir, 'tcx: 'mir>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
main_id: DefId,
|
||||
config: MiriConfig,
|
||||
) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> {
|
||||
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
|
||||
let mut ecx = InterpCx::new(
|
||||
tcx.at(syntax::source_map::DUMMY_SP),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
@ -170,12 +173,15 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
||||
ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
|
||||
ecx.machine.last_error = Some(errno_place);
|
||||
|
||||
Ok(ecx)
|
||||
Ok((ecx, ret_ptr))
|
||||
}
|
||||
|
||||
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
|
||||
let mut ecx = match create_ecx(tcx, main_id, config) {
|
||||
Ok(ecx) => ecx,
|
||||
/// Evaluates the main function specified by `main_id`.
|
||||
/// Returns `Some(return_code)` if program executed completed.
|
||||
/// Returns `None` if an evaluation error occured.
|
||||
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
|
||||
let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) {
|
||||
Ok(v) => v,
|
||||
Err(mut err) => {
|
||||
err.print_backtrace();
|
||||
panic!("Miri initialziation error: {}", err.kind)
|
||||
@ -183,14 +189,18 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
|
||||
};
|
||||
|
||||
// Perform the main execution.
|
||||
let res: InterpResult<'_> = (|| {
|
||||
let res: InterpResult<'_, i64> = (|| {
|
||||
ecx.run()?;
|
||||
ecx.run_tls_dtors()
|
||||
// Read the return code pointer *before* we run TLS destructors, to assert
|
||||
// that it was written to by the time that `start` lang item returned.
|
||||
let return_code = ecx.read_scalar(ret_ptr.into())?.not_undef()?.to_machine_isize(&ecx)?;
|
||||
ecx.run_tls_dtors()?;
|
||||
Ok(return_code)
|
||||
})();
|
||||
|
||||
// Process the result.
|
||||
match res {
|
||||
Ok(()) => {
|
||||
Ok(return_code) => {
|
||||
let leaks = ecx.memory.leak_report();
|
||||
// Disable the leak test on some platforms where we do not
|
||||
// correctly implement TLS destructors.
|
||||
@ -198,12 +208,16 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
|
||||
let ignore_leaks = target_os == "windows" || target_os == "macos";
|
||||
if !ignore_leaks && leaks != 0 {
|
||||
tcx.sess.err("the evaluated program leaked memory");
|
||||
// Ignore the provided return code - let the reported error
|
||||
// determine the return code.
|
||||
return None;
|
||||
}
|
||||
return Some(return_code)
|
||||
}
|
||||
Err(mut e) => {
|
||||
// Special treatment for some error kinds
|
||||
let msg = match e.kind {
|
||||
InterpError::Exit(code) => std::process::exit(code),
|
||||
InterpError::Exit(code) => return Some(code.into()),
|
||||
err_unsup!(NoMirFor(..)) =>
|
||||
format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
|
||||
_ => e.to_string()
|
||||
@ -246,6 +260,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
|
||||
trace!(" local {}: {:?}", i, local.value);
|
||||
}
|
||||
}
|
||||
// Let the reported error determine the return code.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user