@@ -151,40 +151,65 @@ mod imp {
151151 }
152152}
153153
154- #[ cfg( target_os = "macos " ) ]
154+ #[ cfg( target_vendor = "apple " ) ]
155155mod imp {
156- use crate :: fs:: File ;
157- use crate :: io:: Read ;
158- use crate :: sys:: os:: errno;
159- use crate :: sys:: weak:: weak;
156+ use crate :: io;
160157 use libc:: { c_int, c_void, size_t} ;
161158
162- fn getentropy_fill_bytes ( v : & mut [ u8 ] ) -> bool {
163- weak ! ( fn getentropy( * mut c_void, size_t) -> c_int) ;
164-
165- getentropy
166- . get ( )
167- . map ( |f| {
168- // getentropy(2) permits a maximum buffer size of 256 bytes
169- for s in v. chunks_mut ( 256 ) {
170- let ret = unsafe { f ( s. as_mut_ptr ( ) as * mut c_void , s. len ( ) ) } ;
171- if ret == -1 {
172- panic ! ( "unexpected getentropy error: {}" , errno( ) ) ;
173- }
174- }
175- true
176- } )
177- . unwrap_or ( false )
159+ #[ inline( always) ]
160+ fn random_failure ( ) -> ! {
161+ panic ! ( "unexpected random generation error: {}" , io:: Error :: last_os_error( ) ) ;
178162 }
179163
180- pub fn fill_bytes ( v : & mut [ u8 ] ) {
181- if getentropy_fill_bytes ( v) {
182- return ;
164+ #[ cfg( target_os = "macos" ) ]
165+ fn getentropy_fill_bytes ( v : & mut [ u8 ] ) {
166+ extern "C" {
167+ fn getentropy ( bytes : * mut c_void , count : size_t ) -> c_int ;
183168 }
184169
185- // for older macos which doesn't support getentropy
186- let mut file = File :: open ( "/dev/urandom" ) . expect ( "failed to open /dev/urandom" ) ;
187- file. read_exact ( v) . expect ( "failed to read /dev/urandom" )
170+ // getentropy(2) permits a maximum buffer size of 256 bytes
171+ for s in v. chunks_mut ( 256 ) {
172+ let ret = unsafe { getentropy ( s. as_mut_ptr ( ) . cast ( ) , s. len ( ) ) } ;
173+ if ret == -1 {
174+ random_failure ( )
175+ }
176+ }
177+ }
178+
179+ #[ cfg( not( target_os = "macos" ) ) ]
180+ fn ccrandom_fill_bytes ( v : & mut [ u8 ] ) {
181+ extern "C" {
182+ fn CCRandomGenerateBytes ( bytes : * mut c_void , count : size_t ) -> c_int ;
183+ }
184+
185+ let ret = unsafe { CCRandomGenerateBytes ( v. as_mut_ptr ( ) . cast ( ) , v. len ( ) ) } ;
186+ if ret == -1 {
187+ random_failure ( )
188+ }
189+ }
190+
191+ pub fn fill_bytes ( v : & mut [ u8 ] ) {
192+ // All supported versions of macOS (10.12+) support getentropy.
193+ //
194+ // `getentropy` is measurably faster (via Divan) then the other alternatives so its preferred
195+ // when usable.
196+ #[ cfg( target_os = "macos" ) ]
197+ getentropy_fill_bytes ( v) ;
198+
199+ // On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
200+ // call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
201+ // manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
202+ // its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
203+ // so we only use it on non-Mac OSes where the better entrypoints are blocked.
204+ //
205+ // `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
206+ // via `libSystem` (libc) while the other needs to link to `Security.framework`.
207+ //
208+ // Note that while `getentropy` has a available attribute in the macOS headers, the lack
209+ // of a header in the iOS (and others) SDK means that its can cause app store rejections.
210+ // Just use `CCRandomGenerateBytes` instead.
211+ #[ cfg( not( target_os = "macos" ) ) ]
212+ ccrandom_fill_bytes ( v) ;
188213 }
189214}
190215
@@ -203,36 +228,6 @@ mod imp {
203228 }
204229}
205230
206- // On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
207- // `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
208- // from `/dev/random` and which runs on its own thread accessed via GCD.
209- // This seems needlessly heavyweight for the purposes of generating two u64s
210- // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
211- // only used on iOS where direct access to `/dev/urandom` is blocked by the
212- // sandbox.
213- #[ cfg( any( target_os = "ios" , target_os = "tvos" , target_os = "watchos" ) ) ]
214- mod imp {
215- use crate :: io;
216- use crate :: ptr;
217- use libc:: { c_int, size_t} ;
218-
219- enum SecRandom { }
220-
221- #[ allow( non_upper_case_globals) ]
222- const kSecRandomDefault: * const SecRandom = ptr:: null ( ) ;
223-
224- extern "C" {
225- fn SecRandomCopyBytes ( rnd : * const SecRandom , count : size_t , bytes : * mut u8 ) -> c_int ;
226- }
227-
228- pub fn fill_bytes ( v : & mut [ u8 ] ) {
229- let ret = unsafe { SecRandomCopyBytes ( kSecRandomDefault, v. len ( ) , v. as_mut_ptr ( ) ) } ;
230- if ret == -1 {
231- panic ! ( "couldn't generate random bytes: {}" , io:: Error :: last_os_error( ) ) ;
232- }
233- }
234- }
235-
236231// FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification.
237232#[ cfg( target_os = "netbsd" ) ]
238233mod imp {
0 commit comments