@@ -184,28 +184,58 @@ mod imp {
184
184
#[ cfg( target_vendor = "apple" ) ]
185
185
mod imp {
186
186
use super :: Args ;
187
- use crate :: ffi:: CStr ;
187
+ use crate :: ffi:: { c_char , c_int , CStr } ;
188
188
use crate :: os:: unix:: prelude:: * ;
189
189
190
- pub unsafe fn init ( _argc : isize , _argv : * const * const u8 ) { }
190
+ pub unsafe fn init ( _argc : isize , _argv : * const * const u8 ) {
191
+ // No need to initialize anything in here, `libdyld.dylib` has already
192
+ // done the work for us.
193
+ }
191
194
192
195
pub fn args ( ) -> Args {
193
196
extern "C" {
194
197
// These functions are in crt_externs.h.
195
- fn _NSGetArgc ( ) -> * mut libc:: c_int ;
196
- fn _NSGetArgv ( ) -> * mut * mut * mut libc:: c_char ;
198
+ fn _NSGetArgc ( ) -> * mut c_int ;
199
+ fn _NSGetArgv ( ) -> * mut * mut * mut c_char ;
200
+ }
201
+
202
+ // SAFETY: The returned pointer points to a static initialized early
203
+ // in the program lifetime by `libdyld.dylib`, and as such is always
204
+ // valid.
205
+ //
206
+ // NOTE: Similar to `_NSGetEnviron`, there technically isn't anything
207
+ // protecting us against concurrent modifications to this, and there
208
+ // doesn't exist a lock that we can take. Instead, it is generally
209
+ // expected that it's only modified in `main` / before other code
210
+ // runs, so reading this here should be fine.
211
+ let argc = unsafe { _NSGetArgc ( ) . read ( ) } ;
212
+ // SAFETY: Same as above.
213
+ let argv = unsafe { _NSGetArgv ( ) . read ( ) } ;
214
+
215
+ let mut vec = Vec :: with_capacity ( argc as usize ) ;
216
+
217
+ for i in 0 ..argc {
218
+ // SAFETY: `argv` is at least as long as `argc`, so reading from
219
+ // it should be safe.
220
+ let ptr = unsafe { argv. offset ( i as isize ) . read ( ) } ;
221
+
222
+ // Entries may have been removed from `argv` by setting them to
223
+ // NULL, without updating `argc`.
224
+ if ptr. is_null ( ) {
225
+ // We continue instead of break here, as an argument may have
226
+ // been set to `NULL` in the middle, instead of at the end of
227
+ // the list.
228
+ //
229
+ // This is the same as what `-[NSProcessInfo arguments]` does.
230
+ continue ;
231
+ }
232
+
233
+ // SAFETY: Just checked that the pointer is not NULL, and
234
+ // arguments are otherwise guaranteed to be valid C strings.
235
+ let cstr = unsafe { CStr :: from_ptr ( ptr) } ;
236
+ vec. push ( OsStringExt :: from_vec ( cstr. to_bytes ( ) . to_vec ( ) ) ) ;
197
237
}
198
238
199
- let vec = unsafe {
200
- let ( argc, argv) =
201
- ( * _NSGetArgc ( ) as isize , * _NSGetArgv ( ) as * const * const libc:: c_char ) ;
202
- ( 0 ..argc as isize )
203
- . map ( |i| {
204
- let bytes = CStr :: from_ptr ( * argv. offset ( i) ) . to_bytes ( ) . to_vec ( ) ;
205
- OsStringExt :: from_vec ( bytes)
206
- } )
207
- . collect :: < Vec < _ > > ( )
208
- } ;
209
239
Args { iter : vec. into_iter ( ) }
210
240
}
211
241
}
0 commit comments