@@ -288,7 +288,11 @@ mod lazy {
288288 }
289289
290290 pub unsafe fn get ( & self ) -> Option < & ' static T > {
291- ( * self . inner . get ( ) ) . as_ref ( )
291+ // SAFETY: No reference is ever handed out to the inner cell nor
292+ // mutable reference to the Option<T> inside said cell. This make it
293+ // safe to hand a reference, though the lifetime of 'static
294+ // is itself unsafe, making the get method unsafe.
295+ unsafe { ( * self . inner . get ( ) ) . as_ref ( ) }
292296 }
293297
294298 pub unsafe fn initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> & ' static T {
@@ -297,6 +301,8 @@ mod lazy {
297301 let value = init ( ) ;
298302 let ptr = self . inner . get ( ) ;
299303
304+ // SAFETY:
305+ //
300306 // note that this can in theory just be `*ptr = Some(value)`, but due to
301307 // the compiler will currently codegen that pattern with something like:
302308 //
@@ -309,22 +315,31 @@ mod lazy {
309315 // value (an aliasing violation). To avoid setting the "I'm running a
310316 // destructor" flag we just use `mem::replace` which should sequence the
311317 // operations a little differently and make this safe to call.
312- let _ = mem:: replace ( & mut * ptr, Some ( value) ) ;
313-
314- // After storing `Some` we want to get a reference to the contents of
315- // what we just stored. While we could use `unwrap` here and it should
316- // always work it empirically doesn't seem to always get optimized away,
317- // which means that using something like `try_with` can pull in
318- // panicking code and cause a large size bloat.
319- match * ptr {
320- Some ( ref x) => x,
321- None => hint:: unreachable_unchecked ( ) ,
318+ unsafe {
319+ let _ = mem:: replace ( & mut * ptr, Some ( value) ) ;
320+ }
321+
322+ // SAFETY: the *ptr operation is made safe by the `mem::replace`
323+ // call above that made sure a valid value is present behind it.
324+ unsafe {
325+ // After storing `Some` we want to get a reference to the contents of
326+ // what we just stored. While we could use `unwrap` here and it should
327+ // always work it empirically doesn't seem to always get optimized away,
328+ // which means that using something like `try_with` can pull in
329+ // panicking code and cause a large size bloat.
330+ match * ptr {
331+ Some ( ref x) => x,
332+ None => hint:: unreachable_unchecked ( ) ,
333+ }
322334 }
323335 }
324336
325337 #[ allow( unused) ]
326338 pub unsafe fn take ( & mut self ) -> Option < T > {
327- ( * self . inner . get ( ) ) . take ( )
339+ // SAFETY: The other methods hand out references while taking &self.
340+ // As such, calling this method when such references are still alive
341+ // will fail because it takes a &mut self, conflicting with them.
342+ unsafe { ( * self . inner . get ( ) ) . take ( ) }
328343 }
329344 }
330345}
@@ -413,9 +428,17 @@ pub mod fast {
413428 }
414429
415430 pub unsafe fn get < F : FnOnce ( ) -> T > ( & self , init : F ) -> Option < & ' static T > {
416- match self . inner . get ( ) {
417- Some ( val) => Some ( val) ,
418- None => self . try_initialize ( init) ,
431+ // SAFETY: See the definitions of `LazyKeyInner::get` and
432+ // `try_initialize` for more informations.
433+ //
434+ // The call to `get` is made safe because no mutable references are
435+ // ever handed out and the `try_initialize` is dependant on the
436+ // passed `init` function.
437+ unsafe {
438+ match self . inner . get ( ) {
439+ Some ( val) => Some ( val) ,
440+ None => self . try_initialize ( init) ,
441+ }
419442 }
420443 }
421444
@@ -428,8 +451,10 @@ pub mod fast {
428451 // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
429452 #[ inline( never) ]
430453 unsafe fn try_initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> Option < & ' static T > {
431- if !mem:: needs_drop :: < T > ( ) || self . try_register_dtor ( ) {
432- Some ( self . inner . initialize ( init) )
454+ // SAFETY: See comment above.
455+ if !mem:: needs_drop :: < T > ( ) || unsafe { self . try_register_dtor ( ) } {
456+ // SAFETY: See comment above.
457+ Some ( unsafe { self . inner . initialize ( init) } )
433458 } else {
434459 None
435460 }
@@ -441,8 +466,12 @@ pub mod fast {
441466 unsafe fn try_register_dtor ( & self ) -> bool {
442467 match self . dtor_state . get ( ) {
443468 DtorState :: Unregistered => {
444- // dtor registration happens before initialization.
445- register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) ;
469+ // SAFETY: dtor registration happens before initialization.
470+ // Passing `self` as a pointer while using `destroy_value<T>`
471+ // is safe because the function will build a pointer to a
472+ // Key<T>, which is the type of self and so find the correct
473+ // size.
474+ unsafe { register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) } ;
446475 self . dtor_state . set ( DtorState :: Registered ) ;
447476 true
448477 }
@@ -458,13 +487,21 @@ pub mod fast {
458487 unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
459488 let ptr = ptr as * mut Key < T > ;
460489
490+ // SAFETY:
491+ //
492+ // The pointer `ptr` has been built just above and comes from
493+ // `try_register_dtor` where it is originally a Key<T> coming from `self`,
494+ // making it non-NUL and of the correct type.
495+ //
461496 // Right before we run the user destructor be sure to set the
462497 // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
463498 // causes future calls to `get` to run `try_initialize_drop` again,
464499 // which will now fail, and return `None`.
465- let value = ( * ptr) . inner . take ( ) ;
466- ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
467- drop ( value) ;
500+ unsafe {
501+ let value = ( * ptr) . inner . take ( ) ;
502+ ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
503+ drop ( value) ;
504+ }
468505 }
469506}
470507
@@ -533,22 +570,28 @@ pub mod os {
533570 ptr
534571 } ;
535572
536- Some ( ( * ptr) . inner . initialize ( init) )
573+ // SAFETY: ptr has been ensured as non-NUL just above an so can be
574+ // dereferenced safely.
575+ unsafe { Some ( ( * ptr) . inner . initialize ( init) ) }
537576 }
538577 }
539578
540579 unsafe extern "C" fn destroy_value < T : ' static > ( ptr : * mut u8 ) {
580+ // SAFETY:
581+ //
541582 // The OS TLS ensures that this key contains a NULL value when this
542583 // destructor starts to run. We set it back to a sentinel value of 1 to
543584 // ensure that any future calls to `get` for this thread will return
544585 // `None`.
545586 //
546587 // Note that to prevent an infinite loop we reset it back to null right
547588 // before we return from the destructor ourselves.
548- let ptr = Box :: from_raw ( ptr as * mut Value < T > ) ;
549- let key = ptr. key ;
550- key. os . set ( 1 as * mut u8 ) ;
551- drop ( ptr) ;
552- key. os . set ( ptr:: null_mut ( ) ) ;
589+ unsafe {
590+ let ptr = Box :: from_raw ( ptr as * mut Value < T > ) ;
591+ let key = ptr. key ;
592+ key. os . set ( 1 as * mut u8 ) ;
593+ drop ( ptr) ;
594+ key. os . set ( ptr:: null_mut ( ) ) ;
595+ }
553596 }
554597}
0 commit comments