Skip to content

Commit 35e92d9

Browse files
committed
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
2 parents 6138794 + 2176bf6 commit 35e92d9

File tree

2 files changed

+31
-12
lines changed

2 files changed

+31
-12
lines changed

src/bin/miri.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ extern crate rustc_interface;
1515
extern crate syntax;
1616

1717
use std::str::FromStr;
18+
use std::convert::TryFrom;
1819
use std::env;
1920

2021
use hex::FromHexError;
@@ -39,7 +40,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
3940
// Add filename to `miri` arguments.
4041
config.args.insert(0, compiler.input().filestem().to_string());
4142

42-
miri::eval_main(tcx, entry_def_id, config);
43+
if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) {
44+
std::process::exit(i32::try_from(return_code).expect("Return value was too large!"));
45+
}
4346
});
4447

4548
compiler.session().abort_if_errors();

src/eval.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use syntax::source_map::DUMMY_SP;
1111
use crate::{
1212
EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError,
1313
InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag,
14-
TlsEvalContextExt,
14+
TlsEvalContextExt, MPlaceTy
1515
};
1616

1717
/// Configuration needed to spawn a Miri instance.
@@ -29,12 +29,15 @@ pub struct MiriConfig {
2929
pub seed: Option<u64>,
3030
}
3131

32-
// Used by priroda.
32+
/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
33+
/// the location where the return value of the `start` lang item will be
34+
/// written to.
35+
/// Public because this is also used by `priroda`.
3336
pub fn create_ecx<'mir, 'tcx: 'mir>(
3437
tcx: TyCtxt<'tcx>,
3538
main_id: DefId,
3639
config: MiriConfig,
37-
) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> {
40+
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
3841
let mut ecx = InterpCx::new(
3942
tcx.at(syntax::source_map::DUMMY_SP),
4043
ty::ParamEnv::reveal_all(),
@@ -170,40 +173,51 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
170173
ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
171174
ecx.machine.last_error = Some(errno_place);
172175

173-
Ok(ecx)
176+
Ok((ecx, ret_ptr))
174177
}
175178

176-
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
177-
let mut ecx = match create_ecx(tcx, main_id, config) {
178-
Ok(ecx) => ecx,
179+
/// Evaluates the main function specified by `main_id`.
180+
/// Returns `Some(return_code)` if program executed completed.
181+
/// Returns `None` if an evaluation error occured.
182+
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
183+
let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) {
184+
Ok(v) => v,
179185
Err(mut err) => {
180186
err.print_backtrace();
181187
panic!("Miri initialziation error: {}", err.kind)
182188
}
183189
};
184190

185191
// Perform the main execution.
186-
let res: InterpResult<'_> = (|| {
192+
let res: InterpResult<'_, i64> = (|| {
187193
ecx.run()?;
188-
ecx.run_tls_dtors()
194+
// Read the return code pointer *before* we run TLS destructors, to assert
195+
// that it was written to by the time that `start` lang item returned.
196+
let return_code = ecx.read_scalar(ret_ptr.into())?.not_undef()?.to_machine_isize(&ecx)?;
197+
ecx.run_tls_dtors()?;
198+
Ok(return_code)
189199
})();
190200

191201
// Process the result.
192202
match res {
193-
Ok(()) => {
203+
Ok(return_code) => {
194204
let leaks = ecx.memory.leak_report();
195205
// Disable the leak test on some platforms where we do not
196206
// correctly implement TLS destructors.
197207
let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
198208
let ignore_leaks = target_os == "windows" || target_os == "macos";
199209
if !ignore_leaks && leaks != 0 {
200210
tcx.sess.err("the evaluated program leaked memory");
211+
// Ignore the provided return code - let the reported error
212+
// determine the return code.
213+
return None;
201214
}
215+
return Some(return_code)
202216
}
203217
Err(mut e) => {
204218
// Special treatment for some error kinds
205219
let msg = match e.kind {
206-
InterpError::Exit(code) => std::process::exit(code),
220+
InterpError::Exit(code) => return Some(code.into()),
207221
err_unsup!(NoMirFor(..)) =>
208222
format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
209223
_ => e.to_string()
@@ -246,6 +260,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
246260
trace!(" local {}: {:?}", i, local.value);
247261
}
248262
}
263+
// Let the reported error determine the return code.
264+
return None;
249265
}
250266
}
251267
}

0 commit comments

Comments
 (0)