@@ -288,15 +288,23 @@ mod lazy {
288288 }
289289
290290 pub unsafe fn get ( & self ) -> Option < & ' static T > {
291- ( * self . inner . get ( ) ) . as_ref ( )
291+ // SAFETY: The caller must ensure no reference is ever handed out to
292+ // the inner cell nor mutable reference to the Option<T> inside said
293+ // cell. This make it safe to hand a reference, though the lifetime
294+ // of 'static is itself unsafe, making the get method unsafe.
295+ unsafe { ( * self . inner . get ( ) ) . as_ref ( ) }
292296 }
293297
298+ /// The caller must ensure that no reference is active: this method
299+ /// needs unique access.
294300 pub unsafe fn initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> & ' static T {
295301 // Execute the initialization up front, *then* move it into our slot,
296302 // just in case initialization fails.
297303 let value = init ( ) ;
298304 let ptr = self . inner . get ( ) ;
299305
306+ // SAFETY:
307+ //
300308 // note that this can in theory just be `*ptr = Some(value)`, but due to
301309 // the compiler will currently codegen that pattern with something like:
302310 //
@@ -309,22 +317,36 @@ mod lazy {
309317 // value (an aliasing violation). To avoid setting the "I'm running a
310318 // destructor" flag we just use `mem::replace` which should sequence the
311319 // 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 ( ) ,
320+ //
321+ // The precondition also ensures that we are the only one accessing
322+ // `self` at the moment so replacing is fine.
323+ unsafe {
324+ let _ = mem:: replace ( & mut * ptr, Some ( value) ) ;
325+ }
326+
327+ // SAFETY: With the call to `mem::replace` it is guaranteed there is
328+ // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked`
329+ // will never be reached.
330+ unsafe {
331+ // After storing `Some` we want to get a reference to the contents of
332+ // what we just stored. While we could use `unwrap` here and it should
333+ // always work it empirically doesn't seem to always get optimized away,
334+ // which means that using something like `try_with` can pull in
335+ // panicking code and cause a large size bloat.
336+ match * ptr {
337+ Some ( ref x) => x,
338+ None => hint:: unreachable_unchecked ( ) ,
339+ }
322340 }
323341 }
324342
343+ /// The other methods hand out references while taking &self.
344+ /// As such, callers of this method must ensure no `&` and `&mut` are
345+ /// available and used at the same time.
325346 #[ allow( unused) ]
326347 pub unsafe fn take ( & mut self ) -> Option < T > {
327- ( * self . inner . get ( ) ) . take ( )
348+ // SAFETY: See doc comment for this method.
349+ unsafe { ( * self . inner . get ( ) ) . take ( ) }
328350 }
329351 }
330352}
@@ -413,9 +435,18 @@ pub mod fast {
413435 }
414436
415437 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) ,
438+ // SAFETY: See the definitions of `LazyKeyInner::get` and
439+ // `try_initialize` for more informations.
440+ //
441+ // The caller must ensure no mutable references are ever active to
442+ // the inner cell or the inner T when this is called.
443+ // The `try_initialize` is dependant on the passed `init` function
444+ // for this.
445+ unsafe {
446+ match self . inner . get ( ) {
447+ Some ( val) => Some ( val) ,
448+ None => self . try_initialize ( init) ,
449+ }
419450 }
420451 }
421452
@@ -428,8 +459,10 @@ pub mod fast {
428459 // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
429460 #[ inline( never) ]
430461 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) )
462+ // SAFETY: See comment above (this function doc).
463+ if !mem:: needs_drop :: < T > ( ) || unsafe { self . try_register_dtor ( ) } {
464+ // SAFETY: See comment above (his function doc).
465+ Some ( unsafe { self . inner . initialize ( init) } )
433466 } else {
434467 None
435468 }
@@ -441,8 +474,12 @@ pub mod fast {
441474 unsafe fn try_register_dtor ( & self ) -> bool {
442475 match self . dtor_state . get ( ) {
443476 DtorState :: Unregistered => {
444- // dtor registration happens before initialization.
445- register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) ;
477+ // SAFETY: dtor registration happens before initialization.
478+ // Passing `self` as a pointer while using `destroy_value<T>`
479+ // is safe because the function will build a pointer to a
480+ // Key<T>, which is the type of self and so find the correct
481+ // size.
482+ unsafe { register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) } ;
446483 self . dtor_state . set ( DtorState :: Registered ) ;
447484 true
448485 }
@@ -458,13 +495,21 @@ pub mod fast {
458495 unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
459496 let ptr = ptr as * mut Key < T > ;
460497
498+ // SAFETY:
499+ //
500+ // The pointer `ptr` has been built just above and comes from
501+ // `try_register_dtor` where it is originally a Key<T> coming from `self`,
502+ // making it non-NUL and of the correct type.
503+ //
461504 // Right before we run the user destructor be sure to set the
462505 // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
463506 // causes future calls to `get` to run `try_initialize_drop` again,
464507 // which will now fail, and return `None`.
465- let value = ( * ptr) . inner . take ( ) ;
466- ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
467- drop ( value) ;
508+ unsafe {
509+ let value = ( * ptr) . inner . take ( ) ;
510+ ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
511+ drop ( value) ;
512+ }
468513 }
469514}
470515
@@ -501,21 +546,30 @@ pub mod os {
501546 Key { os : OsStaticKey :: new ( Some ( destroy_value :: < T > ) ) , marker : marker:: PhantomData }
502547 }
503548
549+ /// It is a requirement for the caller to ensure that no mutable
550+ /// reference is active when this method is called.
504551 pub unsafe fn get ( & ' static self , init : fn ( ) -> T ) -> Option < & ' static T > {
505- let ptr = self . os . get ( ) as * mut Value < T > ;
552+ // SAFETY: See the documentation for this method.
553+ let ptr = unsafe { self . os . get ( ) as * mut Value < T > } ;
506554 if ptr as usize > 1 {
507- if let Some ( ref value) = ( * ptr) . inner . get ( ) {
555+ // SAFETY: the check ensured the pointer is safe (its destructor
556+ // is not running) + it is coming from a trusted source (self).
557+ if let Some ( ref value) = unsafe { ( * ptr) . inner . get ( ) } {
508558 return Some ( value) ;
509559 }
510560 }
511- self . try_initialize ( init)
561+ // SAFETY: At this point we are sure we have no value and so
562+ // initializing (or trying to) is safe.
563+ unsafe { self . try_initialize ( init) }
512564 }
513565
514566 // `try_initialize` is only called once per os thread local variable,
515567 // except in corner cases where thread_local dtors reference other
516568 // thread_local's, or it is being recursively initialized.
517569 unsafe fn try_initialize ( & ' static self , init : fn ( ) -> T ) -> Option < & ' static T > {
518- let ptr = self . os . get ( ) as * mut Value < T > ;
570+ // SAFETY: No mutable references are ever handed out meaning getting
571+ // the value is ok.
572+ let ptr = unsafe { self . os . get ( ) as * mut Value < T > } ;
519573 if ptr as usize == 1 {
520574 // destructor is running
521575 return None ;
@@ -526,29 +580,39 @@ pub mod os {
526580 // local copy, so do that now.
527581 let ptr: Box < Value < T > > = box Value { inner : LazyKeyInner :: new ( ) , key : self } ;
528582 let ptr = Box :: into_raw ( ptr) ;
529- self . os . set ( ptr as * mut u8 ) ;
583+ // SAFETY: At this point we are sure there is no value inside
584+ // ptr so setting it will not affect anyone else.
585+ unsafe {
586+ self . os . set ( ptr as * mut u8 ) ;
587+ }
530588 ptr
531589 } else {
532590 // recursive initialization
533591 ptr
534592 } ;
535593
536- Some ( ( * ptr) . inner . initialize ( init) )
594+ // SAFETY: ptr has been ensured as non-NUL just above an so can be
595+ // dereferenced safely.
596+ unsafe { Some ( ( * ptr) . inner . initialize ( init) ) }
537597 }
538598 }
539599
540600 unsafe extern "C" fn destroy_value < T : ' static > ( ptr : * mut u8 ) {
601+ // SAFETY:
602+ //
541603 // The OS TLS ensures that this key contains a NULL value when this
542604 // destructor starts to run. We set it back to a sentinel value of 1 to
543605 // ensure that any future calls to `get` for this thread will return
544606 // `None`.
545607 //
546608 // Note that to prevent an infinite loop we reset it back to null right
547609 // 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 ( ) ) ;
610+ unsafe {
611+ let ptr = Box :: from_raw ( ptr as * mut Value < T > ) ;
612+ let key = ptr. key ;
613+ key. os . set ( 1 as * mut u8 ) ;
614+ drop ( ptr) ;
615+ key. os . set ( ptr:: null_mut ( ) ) ;
616+ }
553617 }
554618}
0 commit comments