@@ -6,13 +6,8 @@ use rand::SeedableRng;
66use rustc:: hir:: def_id:: DefId ;
77use rustc:: ty:: layout:: { LayoutOf , Size } ;
88use rustc:: ty:: { self , TyCtxt } ;
9- use syntax:: source_map:: DUMMY_SP ;
109
11- use crate :: {
12- EnvVars , Evaluator , FnVal , HelpersEvalContextExt , InterpCx , InterpError ,
13- InterpResult , MemoryExtra , MiriMemoryKind , Pointer , Scalar , StackPopCleanup , Tag ,
14- TlsEvalContextExt , MPlaceTy
15- } ;
10+ use crate :: * ;
1611
1712/// Configuration needed to spawn a Miri instance.
1813#[ derive( Clone ) ]
@@ -65,122 +60,108 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
6560 tcx. mk_substs ( :: std:: iter:: once ( ty:: subst:: GenericArg :: from ( main_ret_ty) ) ) ,
6661 )
6762 . unwrap ( ) ;
68- let start_mir = ecx. load_mir ( start_instance. def , None ) ?;
69-
70- if start_mir. arg_count != 3 {
71- bug ! (
72- "'start' lang item should have three arguments, but has {}" ,
73- start_mir. arg_count
74- ) ;
75- }
76-
77- // Return value (in static memory so that it does not count as leak).
78- let ret = ecx. layout_of ( start_mir. return_ty ( ) ) ?;
79- let ret_ptr = ecx. allocate ( ret, MiriMemoryKind :: Static . into ( ) ) ;
80-
81- // Push our stack frame.
82- ecx. push_stack_frame (
83- start_instance,
84- // There is no call site.
85- DUMMY_SP ,
86- start_mir,
87- Some ( ret_ptr. into ( ) ) ,
88- StackPopCleanup :: None { cleanup : true } ,
89- ) ?;
90-
91- let mut args = ecx. frame ( ) . body . args_iter ( ) ;
9263
9364 // First argument: pointer to `main()`.
9465 let main_ptr = ecx
9566 . memory
9667 . create_fn_alloc ( FnVal :: Instance ( main_instance) ) ;
97- let dest = ecx. local_place ( args. next ( ) . unwrap ( ) ) ?;
98- ecx. write_scalar ( Scalar :: Ptr ( main_ptr) , dest) ?;
99-
100- // Second argument (argc): `1`.
101- let dest = ecx. local_place ( args. next ( ) . unwrap ( ) ) ?;
102- let argc = Scalar :: from_uint ( config. args . len ( ) as u128 , dest. layout . size ) ;
103- ecx. write_scalar ( argc, dest) ?;
104- // Store argc for macOS's `_NSGetArgc`.
105- {
106- let argc_place = ecx. allocate ( dest. layout , MiriMemoryKind :: Env . into ( ) ) ;
107- ecx. write_scalar ( argc, argc_place. into ( ) ) ?;
108- ecx. machine . argc = Some ( argc_place. ptr ) ;
109- }
110-
68+ // Second argument (argc): length of `config.args`.
69+ let argc = Scalar :: from_uint ( config. args . len ( ) as u128 , ecx. pointer_size ( ) ) ;
11170 // Third argument (`argv`): created from `config.args`.
112- let dest = ecx. local_place ( args. next ( ) . unwrap ( ) ) ?;
113- // For Windows, construct a command string with all the aguments.
114- let mut cmd = String :: new ( ) ;
115- for arg in config. args . iter ( ) {
116- if !cmd. is_empty ( ) {
117- cmd. push ( ' ' ) ;
71+ let argv = {
72+ // For Windows, construct a command string with all the aguments (before we take apart `config.args`).
73+ let mut cmd = String :: new ( ) ;
74+ for arg in config. args . iter ( ) {
75+ if !cmd. is_empty ( ) {
76+ cmd. push ( ' ' ) ;
77+ }
78+ cmd. push_str ( & * shell_escape:: windows:: escape ( arg. as_str ( ) . into ( ) ) ) ;
11879 }
119- cmd. push_str ( & * shell_escape:: windows:: escape ( arg. as_str ( ) . into ( ) ) ) ;
120- }
121- // Don't forget `0` terminator.
122- cmd. push ( std:: char:: from_u32 ( 0 ) . unwrap ( ) ) ;
123- // Collect the pointers to the individual strings.
124- let mut argvs = Vec :: < Pointer < Tag > > :: new ( ) ;
125- for arg in config. args {
126- // Add `0` terminator.
127- let mut arg = arg. into_bytes ( ) ;
128- arg. push ( 0 ) ;
129- argvs. push (
130- ecx. memory
131- . allocate_static_bytes ( arg. as_slice ( ) , MiriMemoryKind :: Static . into ( ) ) ,
132- ) ;
133- }
134- // Make an array with all these pointers, in the Miri memory.
135- let argvs_layout = ecx. layout_of (
136- tcx. mk_array ( tcx. mk_imm_ptr ( tcx. types . u8 ) , argvs. len ( ) as u64 ) ,
137- ) ?;
138- let argvs_place = ecx. allocate ( argvs_layout, MiriMemoryKind :: Env . into ( ) ) ;
139- for ( idx, arg) in argvs. into_iter ( ) . enumerate ( ) {
140- let place = ecx. mplace_field ( argvs_place, idx as u64 ) ?;
141- ecx. write_scalar ( Scalar :: Ptr ( arg) , place. into ( ) ) ?;
142- }
143- ecx. memory
144- . mark_immutable ( argvs_place. ptr . assert_ptr ( ) . alloc_id ) ?;
145- // Write a pointer to that place as the argument.
146- let argv = argvs_place. ptr ;
147- ecx. write_scalar ( argv, dest) ?;
148- // Store `argv` for macOS `_NSGetArgv`.
149- {
150- let argv_place = ecx. allocate ( dest. layout , MiriMemoryKind :: Env . into ( ) ) ;
151- ecx. write_scalar ( argv, argv_place. into ( ) ) ?;
152- ecx. machine . argv = Some ( argv_place. ptr ) ;
153- }
154- // Store command line as UTF-16 for Windows `GetCommandLineW`.
155- {
156- let cmd_utf16: Vec < u16 > = cmd. encode_utf16 ( ) . collect ( ) ;
157- let cmd_type = tcx. mk_array ( tcx. types . u16 , cmd_utf16. len ( ) as u64 ) ;
158- let cmd_place = ecx. allocate ( ecx. layout_of ( cmd_type) ?, MiriMemoryKind :: Env . into ( ) ) ;
159- ecx. machine . cmd_line = Some ( cmd_place. ptr ) ;
160- // Store the UTF-16 string. We just allocated so we know the bounds are fine.
161- let char_size = Size :: from_bytes ( 2 ) ;
162- for ( idx, & c) in cmd_utf16. iter ( ) . enumerate ( ) {
163- let place = ecx. mplace_field ( cmd_place, idx as u64 ) ?;
164- ecx. write_scalar ( Scalar :: from_uint ( c, char_size) , place. into ( ) ) ?;
80+ // Don't forget `0` terminator.
81+ cmd. push ( std:: char:: from_u32 ( 0 ) . unwrap ( ) ) ;
82+ // Collect the pointers to the individual strings.
83+ let mut argvs = Vec :: < Pointer < Tag > > :: new ( ) ;
84+ for arg in config. args {
85+ // Add `0` terminator.
86+ let mut arg = arg. into_bytes ( ) ;
87+ arg. push ( 0 ) ;
88+ argvs. push (
89+ ecx. memory
90+ . allocate_static_bytes ( arg. as_slice ( ) , MiriMemoryKind :: Static . into ( ) ) ,
91+ ) ;
16592 }
166- }
93+ // Make an array with all these pointers, in the Miri memory.
94+ let argvs_layout = ecx. layout_of (
95+ tcx. mk_array ( tcx. mk_imm_ptr ( tcx. types . u8 ) , argvs. len ( ) as u64 ) ,
96+ ) ?;
97+ let argvs_place = ecx. allocate ( argvs_layout, MiriMemoryKind :: Env . into ( ) ) ;
98+ for ( idx, arg) in argvs. into_iter ( ) . enumerate ( ) {
99+ let place = ecx. mplace_field ( argvs_place, idx as u64 ) ?;
100+ ecx. write_scalar ( Scalar :: Ptr ( arg) , place. into ( ) ) ?;
101+ }
102+ ecx. memory
103+ . mark_immutable ( argvs_place. ptr . assert_ptr ( ) . alloc_id ) ?;
104+ // A pointer to that place is the argument.
105+ let argv = argvs_place. ptr ;
106+ // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
107+ {
108+ let argc_place = ecx. allocate (
109+ ecx. layout_of ( tcx. types . isize ) ?,
110+ MiriMemoryKind :: Env . into ( ) ,
111+ ) ;
112+ ecx. write_scalar ( argc, argc_place. into ( ) ) ?;
113+ ecx. machine . argc = Some ( argc_place. ptr ) ;
114+
115+ let argv_place = ecx. allocate (
116+ ecx. layout_of ( tcx. mk_imm_ptr ( tcx. types . unit ) ) ?,
117+ MiriMemoryKind :: Env . into ( ) ,
118+ ) ;
119+ ecx. write_scalar ( argv, argv_place. into ( ) ) ?;
120+ ecx. machine . argv = Some ( argv_place. ptr ) ;
121+ }
122+ // Store command line as UTF-16 for Windows `GetCommandLineW`.
123+ {
124+ let cmd_utf16: Vec < u16 > = cmd. encode_utf16 ( ) . collect ( ) ;
125+ let cmd_type = tcx. mk_array ( tcx. types . u16 , cmd_utf16. len ( ) as u64 ) ;
126+ let cmd_place = ecx. allocate ( ecx. layout_of ( cmd_type) ?, MiriMemoryKind :: Env . into ( ) ) ;
127+ ecx. machine . cmd_line = Some ( cmd_place. ptr ) ;
128+ // Store the UTF-16 string. We just allocated so we know the bounds are fine.
129+ let char_size = Size :: from_bytes ( 2 ) ;
130+ for ( idx, & c) in cmd_utf16. iter ( ) . enumerate ( ) {
131+ let place = ecx. mplace_field ( cmd_place, idx as u64 ) ?;
132+ ecx. write_scalar ( Scalar :: from_uint ( c, char_size) , place. into ( ) ) ?;
133+ }
134+ }
135+ argv
136+ } ;
167137
168- args. next ( ) . expect_none ( "start lang item has more arguments than expected" ) ;
138+ // Return place (in static memory so that it does not count as leak).
139+ let ret_place = ecx. allocate (
140+ ecx. layout_of ( tcx. types . isize ) ?,
141+ MiriMemoryKind :: Static . into ( ) ,
142+ ) ;
143+ // Call start function.
144+ ecx. call_function (
145+ start_instance,
146+ & [ main_ptr. into ( ) , argc, argv] ,
147+ Some ( ret_place. into ( ) ) ,
148+ StackPopCleanup :: None { cleanup : true } ,
149+ ) ?;
169150
170151 // Set the last_error to 0
171152 let errno_layout = ecx. layout_of ( tcx. types . u32 ) ?;
172153 let errno_place = ecx. allocate ( errno_layout, MiriMemoryKind :: Static . into ( ) ) ;
173154 ecx. write_scalar ( Scalar :: from_u32 ( 0 ) , errno_place. into ( ) ) ?;
174155 ecx. machine . last_error = Some ( errno_place) ;
175156
176- Ok ( ( ecx, ret_ptr ) )
157+ Ok ( ( ecx, ret_place ) )
177158}
178159
179160/// Evaluates the main function specified by `main_id`.
180161/// Returns `Some(return_code)` if program executed completed.
181162/// Returns `None` if an evaluation error occured.
182163pub 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) {
164+ let ( mut ecx, ret_place ) = match create_ecx ( tcx, main_id, config) {
184165 Ok ( v) => v,
185166 Err ( mut err) => {
186167 err. print_backtrace ( ) ;
@@ -193,7 +174,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
193174 ecx. run ( ) ?;
194175 // Read the return code pointer *before* we run TLS destructors, to assert
195176 // 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) ?;
177+ let return_code = ecx. read_scalar ( ret_place . into ( ) ) ?. not_undef ( ) ?. to_machine_isize ( & ecx) ?;
197178 ecx. run_tls_dtors ( ) ?;
198179 Ok ( return_code)
199180 } ) ( ) ;
0 commit comments