@@ -284,7 +284,11 @@ mod lazy {
284284 }
285285
286286 pub unsafe fn get ( & self ) -> Option < & ' static T > {
287- ( * self . inner . get ( ) ) . as_ref ( )
287+ // SAFETY: No reference is ever handed out to the inner cell nor
288+ // mutable reference to the Option<T> inside said cell. This make it
289+ // safe to hand a reference, though the lifetime of 'static
290+ // is itself unsafe, making the get method unsafe.
291+ unsafe { ( * self . inner . get ( ) ) . as_ref ( ) }
288292 }
289293
290294 pub unsafe fn initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> & ' static T {
@@ -293,6 +297,8 @@ mod lazy {
293297 let value = init ( ) ;
294298 let ptr = self . inner . get ( ) ;
295299
300+ // SAFETY:
301+ //
296302 // note that this can in theory just be `*ptr = Some(value)`, but due to
297303 // the compiler will currently codegen that pattern with something like:
298304 //
@@ -305,22 +311,31 @@ mod lazy {
305311 // value (an aliasing violation). To avoid setting the "I'm running a
306312 // destructor" flag we just use `mem::replace` which should sequence the
307313 // operations a little differently and make this safe to call.
308- let _ = mem:: replace ( & mut * ptr, Some ( value) ) ;
309-
310- // After storing `Some` we want to get a reference to the contents of
311- // what we just stored. While we could use `unwrap` here and it should
312- // always work it empirically doesn't seem to always get optimized away,
313- // which means that using something like `try_with` can pull in
314- // panicking code and cause a large size bloat.
315- match * ptr {
316- Some ( ref x) => x,
317- None => hint:: unreachable_unchecked ( ) ,
314+ unsafe {
315+ let _ = mem:: replace ( & mut * ptr, Some ( value) ) ;
316+ }
317+
318+ // SAFETY: the *ptr operation is made safe by the `mem::replace`
319+ // call above that made sure a valid value is present behind it.
320+ unsafe {
321+ // After storing `Some` we want to get a reference to the contents of
322+ // what we just stored. While we could use `unwrap` here and it should
323+ // always work it empirically doesn't seem to always get optimized away,
324+ // which means that using something like `try_with` can pull in
325+ // panicking code and cause a large size bloat.
326+ match * ptr {
327+ Some ( ref x) => x,
328+ None => hint:: unreachable_unchecked ( ) ,
329+ }
318330 }
319331 }
320332
321333 #[ allow( unused) ]
322334 pub unsafe fn take ( & mut self ) -> Option < T > {
323- ( * self . inner . get ( ) ) . take ( )
335+ // SAFETY: The other methods hand out references while taking &self.
336+ // As such, calling this method when such references are still alive
337+ // will fail because it takes a &mut self, conflicting with them.
338+ unsafe { ( * self . inner . get ( ) ) . take ( ) }
324339 }
325340 }
326341}
@@ -409,9 +424,17 @@ pub mod fast {
409424 }
410425
411426 pub unsafe fn get < F : FnOnce ( ) -> T > ( & self , init : F ) -> Option < & ' static T > {
412- match self . inner . get ( ) {
413- Some ( val) => Some ( val) ,
414- None => self . try_initialize ( init) ,
427+ // SAFETY: See the definitions of `LazyKeyInner::get` and
428+ // `try_initialize` for more informations.
429+ //
430+ // The call to `get` is made safe because no mutable references are
431+ // ever handed out and the `try_initialize` is dependant on the
432+ // passed `init` function.
433+ unsafe {
434+ match self . inner . get ( ) {
435+ Some ( val) => Some ( val) ,
436+ None => self . try_initialize ( init) ,
437+ }
415438 }
416439 }
417440
@@ -425,8 +448,10 @@ pub mod fast {
425448 // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
426449 #[ cold]
427450 unsafe fn try_initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> Option < & ' static T > {
428- if !mem:: needs_drop :: < T > ( ) || self . try_register_dtor ( ) {
429- Some ( self . inner . initialize ( init) )
451+ // SAFETY: See comment above.
452+ if !mem:: needs_drop :: < T > ( ) || unsafe { self . try_register_dtor ( ) } {
453+ // SAFETY: See comment above.
454+ Some ( unsafe { self . inner . initialize ( init) } )
430455 } else {
431456 None
432457 }
@@ -438,8 +463,12 @@ pub mod fast {
438463 unsafe fn try_register_dtor ( & self ) -> bool {
439464 match self . dtor_state . get ( ) {
440465 DtorState :: Unregistered => {
441- // dtor registration happens before initialization.
442- register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) ;
466+ // SAFETY: dtor registration happens before initialization.
467+ // Passing `self` as a pointer while using `destroy_value<T>`
468+ // is safe because the function will build a pointer to a
469+ // Key<T>, which is the type of self and so find the correct
470+ // size.
471+ unsafe { register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) } ;
443472 self . dtor_state . set ( DtorState :: Registered ) ;
444473 true
445474 }
@@ -455,13 +484,21 @@ pub mod fast {
455484 unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
456485 let ptr = ptr as * mut Key < T > ;
457486
487+ // SAFETY:
488+ //
489+ // The pointer `ptr` has been built just above and comes from
490+ // `try_register_dtor` where it is originally a Key<T> coming from `self`,
491+ // making it non-NUL and of the correct type.
492+ //
458493 // Right before we run the user destructor be sure to set the
459494 // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
460495 // causes future calls to `get` to run `try_initialize_drop` again,
461496 // which will now fail, and return `None`.
462- let value = ( * ptr) . inner . take ( ) ;
463- ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
464- drop ( value) ;
497+ unsafe {
498+ let value = ( * ptr) . inner . take ( ) ;
499+ ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
500+ drop ( value) ;
501+ }
465502 }
466503}
467504
@@ -530,23 +567,29 @@ pub mod os {
530567 ptr
531568 } ;
532569
533- Some ( ( * ptr) . inner . initialize ( init) )
570+ // SAFETY: ptr has been ensured as non-NUL just above an so can be
571+ // dereferenced safely.
572+ unsafe { Some ( ( * ptr) . inner . initialize ( init) ) }
534573 }
535574 }
536575
537576 unsafe extern "C" fn destroy_value < T : ' static > ( ptr : * mut u8 ) {
577+ // SAFETY:
578+ //
538579 // The OS TLS ensures that this key contains a NULL value when this
539580 // destructor starts to run. We set it back to a sentinel value of 1 to
540581 // ensure that any future calls to `get` for this thread will return
541582 // `None`.
542583 //
543584 // Note that to prevent an infinite loop we reset it back to null right
544585 // before we return from the destructor ourselves.
545- let ptr = Box :: from_raw ( ptr as * mut Value < T > ) ;
546- let key = ptr. key ;
547- key. os . set ( 1 as * mut u8 ) ;
548- drop ( ptr) ;
549- key. os . set ( ptr:: null_mut ( ) ) ;
586+ unsafe {
587+ let ptr = Box :: from_raw ( ptr as * mut Value < T > ) ;
588+ let key = ptr. key ;
589+ key. os . set ( 1 as * mut u8 ) ;
590+ drop ( ptr) ;
591+ key. os . set ( ptr:: null_mut ( ) ) ;
592+ }
550593 }
551594}
552595
0 commit comments