@@ -11,7 +11,7 @@ use syntax::source_map::DUMMY_SP;
11
11
use crate :: {
12
12
EnvVars , Evaluator , FnVal , HelpersEvalContextExt , InterpCx , InterpError ,
13
13
InterpResult , MemoryExtra , MiriMemoryKind , Pointer , Scalar , StackPopCleanup , Tag ,
14
- TlsEvalContextExt ,
14
+ TlsEvalContextExt , MPlaceTy
15
15
} ;
16
16
17
17
/// Configuration needed to spawn a Miri instance.
@@ -29,12 +29,15 @@ pub struct MiriConfig {
29
29
pub seed : Option < u64 > ,
30
30
}
31
31
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`.
33
36
pub fn create_ecx < ' mir , ' tcx : ' mir > (
34
37
tcx : TyCtxt < ' tcx > ,
35
38
main_id : DefId ,
36
39
config : MiriConfig ,
37
- ) -> InterpResult < ' tcx , InterpCx < ' mir , ' tcx , Evaluator < ' tcx > > > {
40
+ ) -> InterpResult < ' tcx , ( InterpCx < ' mir , ' tcx , Evaluator < ' tcx > > , MPlaceTy < ' tcx , Tag > ) > {
38
41
let mut ecx = InterpCx :: new (
39
42
tcx. at ( syntax:: source_map:: DUMMY_SP ) ,
40
43
ty:: ParamEnv :: reveal_all ( ) ,
@@ -170,40 +173,51 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
170
173
ecx. write_scalar ( Scalar :: from_u32 ( 0 ) , errno_place. into ( ) ) ?;
171
174
ecx. machine . last_error = Some ( errno_place) ;
172
175
173
- Ok ( ecx)
176
+ Ok ( ( ecx, ret_ptr ) )
174
177
}
175
178
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,
179
185
Err ( mut err) => {
180
186
err. print_backtrace ( ) ;
181
187
panic ! ( "Miri initialziation error: {}" , err. kind)
182
188
}
183
189
} ;
184
190
185
191
// Perform the main execution.
186
- let res: InterpResult < ' _ > = ( || {
192
+ let res: InterpResult < ' _ , i64 > = ( || {
187
193
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)
189
199
} ) ( ) ;
190
200
191
201
// Process the result.
192
202
match res {
193
- Ok ( ( ) ) => {
203
+ Ok ( return_code ) => {
194
204
let leaks = ecx. memory . leak_report ( ) ;
195
205
// Disable the leak test on some platforms where we do not
196
206
// correctly implement TLS destructors.
197
207
let target_os = ecx. tcx . tcx . sess . target . target . target_os . to_lowercase ( ) ;
198
208
let ignore_leaks = target_os == "windows" || target_os == "macos" ;
199
209
if !ignore_leaks && leaks != 0 {
200
210
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 ;
201
214
}
215
+ return Some ( return_code)
202
216
}
203
217
Err ( mut e) => {
204
218
// Special treatment for some error kinds
205
219
let msg = match e. kind {
206
- InterpError :: Exit ( code) => std :: process :: exit ( code) ,
220
+ InterpError :: Exit ( code) => return Some ( code. into ( ) ) ,
207
221
err_unsup ! ( NoMirFor ( ..) ) =>
208
222
format ! ( "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`." , e) ,
209
223
_ => e. to_string ( )
@@ -246,6 +260,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
246
260
trace ! ( " local {}: {:?}" , i, local. value) ;
247
261
}
248
262
}
263
+ // Let the reported error determine the return code.
264
+ return None ;
249
265
}
250
266
}
251
267
}
0 commit comments