@@ -289,15 +289,23 @@ mod lazy {
289289 }
290290
291291 pub unsafe fn get ( & self ) -> Option < & ' static T > {
292- ( * self . inner . get ( ) ) . as_ref ( )
292+ // SAFETY: The caller must ensure no reference is ever handed out to
293+ // the inner cell nor mutable reference to the Option<T> inside said
294+ // cell. This make it safe to hand a reference, though the lifetime
295+ // of 'static is itself unsafe, making the get method unsafe.
296+ unsafe { ( * self . inner . get ( ) ) . as_ref ( ) }
293297 }
294298
299+ /// The caller must ensure that no reference is active: this method
300+ /// needs unique access.
295301 pub unsafe fn initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> & ' static T {
296302 // Execute the initialization up front, *then* move it into our slot,
297303 // just in case initialization fails.
298304 let value = init ( ) ;
299305 let ptr = self . inner . get ( ) ;
300306
307+ // SAFETY:
308+ //
301309 // note that this can in theory just be `*ptr = Some(value)`, but due to
302310 // the compiler will currently codegen that pattern with something like:
303311 //
@@ -310,22 +318,36 @@ mod lazy {
310318 // value (an aliasing violation). To avoid setting the "I'm running a
311319 // destructor" flag we just use `mem::replace` which should sequence the
312320 // operations a little differently and make this safe to call.
313- let _ = mem:: replace ( & mut * ptr, Some ( value) ) ;
314-
315- // After storing `Some` we want to get a reference to the contents of
316- // what we just stored. While we could use `unwrap` here and it should
317- // always work it empirically doesn't seem to always get optimized away,
318- // which means that using something like `try_with` can pull in
319- // panicking code and cause a large size bloat.
320- match * ptr {
321- Some ( ref x) => x,
322- None => hint:: unreachable_unchecked ( ) ,
321+ //
322+ // The precondition also ensures that we are the only one accessing
323+ // `self` at the moment so replacing is fine.
324+ unsafe {
325+ let _ = mem:: replace ( & mut * ptr, Some ( value) ) ;
326+ }
327+
328+ // SAFETY: With the call to `mem::replace` it is guaranteed there is
329+ // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked`
330+ // will never be reached.
331+ unsafe {
332+ // After storing `Some` we want to get a reference to the contents of
333+ // what we just stored. While we could use `unwrap` here and it should
334+ // always work it empirically doesn't seem to always get optimized away,
335+ // which means that using something like `try_with` can pull in
336+ // panicking code and cause a large size bloat.
337+ match * ptr {
338+ Some ( ref x) => x,
339+ None => hint:: unreachable_unchecked ( ) ,
340+ }
323341 }
324342 }
325343
344+ /// The other methods hand out references while taking &self.
345+ /// As such, callers of this method must ensure no `&` and `&mut` are
346+ /// available and used at the same time.
326347 #[ allow( unused) ]
327348 pub unsafe fn take ( & mut self ) -> Option < T > {
328- ( * self . inner . get ( ) ) . take ( )
349+ // SAFETY: See doc comment for this method.
350+ unsafe { ( * self . inner . get ( ) ) . take ( ) }
329351 }
330352 }
331353}
@@ -356,10 +378,17 @@ pub mod statik {
356378 }
357379
358380 pub unsafe fn get ( & self , init : fn ( ) -> T ) -> Option < & ' static T > {
359- let value = match self . inner . get ( ) {
360- Some ( ref value) => value,
361- None => self . inner . initialize ( init) ,
381+ // SAFETY: The caller must ensure no reference is ever handed out to
382+ // the inner cell nor mutable reference to the Option<T> inside said
383+ // cell. This make it safe to hand a reference, though the lifetime
384+ // of 'static is itself unsafe, making the get method unsafe.
385+ let value = unsafe {
386+ match self . inner . get ( ) {
387+ Some ( ref value) => value,
388+ None => self . inner . initialize ( init) ,
389+ }
362390 } ;
391+
363392 Some ( value)
364393 }
365394 }
@@ -414,9 +443,18 @@ pub mod fast {
414443 }
415444
416445 pub unsafe fn get < F : FnOnce ( ) -> T > ( & self , init : F ) -> Option < & ' static T > {
417- match self . inner . get ( ) {
418- Some ( val) => Some ( val) ,
419- None => self . try_initialize ( init) ,
446+ // SAFETY: See the definitions of `LazyKeyInner::get` and
447+ // `try_initialize` for more informations.
448+ //
449+ // The caller must ensure no mutable references are ever active to
450+ // the inner cell or the inner T when this is called.
451+ // The `try_initialize` is dependant on the passed `init` function
452+ // for this.
453+ unsafe {
454+ match self . inner . get ( ) {
455+ Some ( val) => Some ( val) ,
456+ None => self . try_initialize ( init) ,
457+ }
420458 }
421459 }
422460
@@ -429,8 +467,10 @@ pub mod fast {
429467 // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
430468 #[ inline( never) ]
431469 unsafe fn try_initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> Option < & ' static T > {
432- if !mem:: needs_drop :: < T > ( ) || self . try_register_dtor ( ) {
433- Some ( self . inner . initialize ( init) )
470+ // SAFETY: See comment above (this function doc).
471+ if !mem:: needs_drop :: < T > ( ) || unsafe { self . try_register_dtor ( ) } {
472+ // SAFETY: See comment above (his function doc).
473+ Some ( unsafe { self . inner . initialize ( init) } )
434474 } else {
435475 None
436476 }
@@ -442,8 +482,12 @@ pub mod fast {
442482 unsafe fn try_register_dtor ( & self ) -> bool {
443483 match self . dtor_state . get ( ) {
444484 DtorState :: Unregistered => {
445- // dtor registration happens before initialization.
446- register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) ;
485+ // SAFETY: dtor registration happens before initialization.
486+ // Passing `self` as a pointer while using `destroy_value<T>`
487+ // is safe because the function will build a pointer to a
488+ // Key<T>, which is the type of self and so find the correct
489+ // size.
490+ unsafe { register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) } ;
447491 self . dtor_state . set ( DtorState :: Registered ) ;
448492 true
449493 }
@@ -459,13 +503,21 @@ pub mod fast {
459503 unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
460504 let ptr = ptr as * mut Key < T > ;
461505
506+ // SAFETY:
507+ //
508+ // The pointer `ptr` has been built just above and comes from
509+ // `try_register_dtor` where it is originally a Key<T> coming from `self`,
510+ // making it non-NUL and of the correct type.
511+ //
462512 // Right before we run the user destructor be sure to set the
463513 // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
464514 // causes future calls to `get` to run `try_initialize_drop` again,
465515 // which will now fail, and return `None`.
466- let value = ( * ptr) . inner . take ( ) ;
467- ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
468- drop ( value) ;
516+ unsafe {
517+ let value = ( * ptr) . inner . take ( ) ;
518+ ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
519+ drop ( value) ;
520+ }
469521 }
470522}
471523
@@ -503,21 +555,30 @@ pub mod os {
503555 Key { os : OsStaticKey :: new ( Some ( destroy_value :: < T > ) ) , marker : marker:: PhantomData }
504556 }
505557
558+ /// It is a requirement for the caller to ensure that no mutable
559+ /// reference is active when this method is called.
506560 pub unsafe fn get ( & ' static self , init : fn ( ) -> T ) -> Option < & ' static T > {
507- let ptr = self . os . get ( ) as * mut Value < T > ;
561+ // SAFETY: See the documentation for this method.
562+ let ptr = unsafe { self . os . get ( ) as * mut Value < T > } ;
508563 if ptr as usize > 1 {
509- if let Some ( ref value) = ( * ptr) . inner . get ( ) {
564+ // SAFETY: the check ensured the pointer is safe (its destructor
565+ // is not running) + it is coming from a trusted source (self).
566+ if let Some ( ref value) = unsafe { ( * ptr) . inner . get ( ) } {
510567 return Some ( value) ;
511568 }
512569 }
513- self . try_initialize ( init)
570+ // SAFETY: At this point we are sure we have no value and so
571+ // initializing (or trying to) is safe.
572+ unsafe { self . try_initialize ( init) }
514573 }
515574
516575 // `try_initialize` is only called once per os thread local variable,
517576 // except in corner cases where thread_local dtors reference other
518577 // thread_local's, or it is being recursively initialized.
519578 unsafe fn try_initialize ( & ' static self , init : fn ( ) -> T ) -> Option < & ' static T > {
520- let ptr = self . os . get ( ) as * mut Value < T > ;
579+ // SAFETY: No mutable references are ever handed out meaning getting
580+ // the value is ok.
581+ let ptr = unsafe { self . os . get ( ) as * mut Value < T > } ;
521582 if ptr as usize == 1 {
522583 // destructor is running
523584 return None ;
@@ -528,29 +589,39 @@ pub mod os {
528589 // local copy, so do that now.
529590 let ptr: Box < Value < T > > = box Value { inner : LazyKeyInner :: new ( ) , key : self } ;
530591 let ptr = Box :: into_raw ( ptr) ;
531- self . os . set ( ptr as * mut u8 ) ;
592+ // SAFETY: At this point we are sure there is no value inside
593+ // ptr so setting it will not affect anyone else.
594+ unsafe {
595+ self . os . set ( ptr as * mut u8 ) ;
596+ }
532597 ptr
533598 } else {
534599 // recursive initialization
535600 ptr
536601 } ;
537602
538- Some ( ( * ptr) . inner . initialize ( init) )
603+ // SAFETY: ptr has been ensured as non-NUL just above an so can be
604+ // dereferenced safely.
605+ unsafe { Some ( ( * ptr) . inner . initialize ( init) ) }
539606 }
540607 }
541608
542609 unsafe extern "C" fn destroy_value < T : ' static > ( ptr : * mut u8 ) {
610+ // SAFETY:
611+ //
543612 // The OS TLS ensures that this key contains a NULL value when this
544613 // destructor starts to run. We set it back to a sentinel value of 1 to
545614 // ensure that any future calls to `get` for this thread will return
546615 // `None`.
547616 //
548617 // Note that to prevent an infinite loop we reset it back to null right
549618 // before we return from the destructor ourselves.
550- let ptr = Box :: from_raw ( ptr as * mut Value < T > ) ;
551- let key = ptr. key ;
552- key. os . set ( 1 as * mut u8 ) ;
553- drop ( ptr) ;
554- key. os . set ( ptr:: null_mut ( ) ) ;
619+ unsafe {
620+ let ptr = Box :: from_raw ( ptr as * mut Value < T > ) ;
621+ let key = ptr. key ;
622+ key. os . set ( 1 as * mut u8 ) ;
623+ drop ( ptr) ;
624+ key. os . set ( ptr:: null_mut ( ) ) ;
625+ }
555626 }
556627}
0 commit comments