@@ -6,13 +6,8 @@ use rand::SeedableRng;
6
6
use rustc:: hir:: def_id:: DefId ;
7
7
use rustc:: ty:: layout:: { LayoutOf , Size } ;
8
8
use rustc:: ty:: { self , TyCtxt } ;
9
- use syntax:: source_map:: DUMMY_SP ;
10
9
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 :: * ;
16
11
17
12
/// Configuration needed to spawn a Miri instance.
18
13
#[ derive( Clone ) ]
@@ -65,122 +60,108 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
65
60
tcx. mk_substs ( :: std:: iter:: once ( ty:: subst:: GenericArg :: from ( main_ret_ty) ) ) ,
66
61
)
67
62
. 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 ( ) ;
92
63
93
64
// First argument: pointer to `main()`.
94
65
let main_ptr = ecx
95
66
. memory
96
67
. 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 ( ) ) ;
111
70
// 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 ( ) ) ) ;
118
79
}
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
+ ) ;
165
92
}
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
+ } ;
167
137
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
+ ) ?;
169
150
170
151
// Set the last_error to 0
171
152
let errno_layout = ecx. layout_of ( tcx. types . u32 ) ?;
172
153
let errno_place = ecx. allocate ( errno_layout, MiriMemoryKind :: Static . into ( ) ) ;
173
154
ecx. write_scalar ( Scalar :: from_u32 ( 0 ) , errno_place. into ( ) ) ?;
174
155
ecx. machine . last_error = Some ( errno_place) ;
175
156
176
- Ok ( ( ecx, ret_ptr ) )
157
+ Ok ( ( ecx, ret_place ) )
177
158
}
178
159
179
160
/// Evaluates the main function specified by `main_id`.
180
161
/// Returns `Some(return_code)` if program executed completed.
181
162
/// Returns `None` if an evaluation error occured.
182
163
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) {
164
+ let ( mut ecx, ret_place ) = match create_ecx ( tcx, main_id, config) {
184
165
Ok ( v) => v,
185
166
Err ( mut err) => {
186
167
err. print_backtrace ( ) ;
@@ -193,7 +174,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
193
174
ecx. run ( ) ?;
194
175
// Read the return code pointer *before* we run TLS destructors, to assert
195
176
// 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) ?;
197
178
ecx. run_tls_dtors ( ) ?;
198
179
Ok ( return_code)
199
180
} ) ( ) ;
0 commit comments