@@ -184,28 +184,58 @@ mod imp {
184184#[ cfg( target_vendor = "apple" ) ]
185185mod imp {
186186 use super :: Args ;
187- use crate :: ffi:: CStr ;
187+ use crate :: ffi:: { c_char , c_int , CStr } ;
188188 use crate :: os:: unix:: prelude:: * ;
189189
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+ }
191194
192195 pub fn args ( ) -> Args {
193196 extern "C" {
194197 // 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 ( ) ) ) ;
197237 }
198238
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- } ;
209239 Args { iter : vec. into_iter ( ) }
210240 }
211241}
0 commit comments