@@ -288,15 +288,23 @@ mod lazy {
288
288
}
289
289
290
290
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 ( ) }
292
296
}
293
297
298
+ /// The caller must ensure that no reference is active: this method
299
+ /// needs unique access.
294
300
pub unsafe fn initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> & ' static T {
295
301
// Execute the initialization up front, *then* move it into our slot,
296
302
// just in case initialization fails.
297
303
let value = init ( ) ;
298
304
let ptr = self . inner . get ( ) ;
299
305
306
+ // SAFETY:
307
+ //
300
308
// note that this can in theory just be `*ptr = Some(value)`, but due to
301
309
// the compiler will currently codegen that pattern with something like:
302
310
//
@@ -309,22 +317,36 @@ mod lazy {
309
317
// value (an aliasing violation). To avoid setting the "I'm running a
310
318
// destructor" flag we just use `mem::replace` which should sequence the
311
319
// 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
+ }
322
340
}
323
341
}
324
342
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.
325
346
#[ allow( unused) ]
326
347
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 ( ) }
328
350
}
329
351
}
330
352
}
@@ -413,9 +435,18 @@ pub mod fast {
413
435
}
414
436
415
437
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
+ }
419
450
}
420
451
}
421
452
@@ -428,8 +459,10 @@ pub mod fast {
428
459
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
429
460
#[ inline( never) ]
430
461
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) } )
433
466
} else {
434
467
None
435
468
}
@@ -441,8 +474,12 @@ pub mod fast {
441
474
unsafe fn try_register_dtor ( & self ) -> bool {
442
475
match self . dtor_state . get ( ) {
443
476
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 > ) } ;
446
483
self . dtor_state . set ( DtorState :: Registered ) ;
447
484
true
448
485
}
@@ -458,13 +495,21 @@ pub mod fast {
458
495
unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
459
496
let ptr = ptr as * mut Key < T > ;
460
497
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
+ //
461
504
// Right before we run the user destructor be sure to set the
462
505
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
463
506
// causes future calls to `get` to run `try_initialize_drop` again,
464
507
// 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
+ }
468
513
}
469
514
}
470
515
@@ -501,21 +546,30 @@ pub mod os {
501
546
Key { os : OsStaticKey :: new ( Some ( destroy_value :: < T > ) ) , marker : marker:: PhantomData }
502
547
}
503
548
549
+ /// It is a requirement for the caller to ensure that no mutable
550
+ /// reference is active when this method is called.
504
551
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 > } ;
506
554
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 ( ) } {
508
558
return Some ( value) ;
509
559
}
510
560
}
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) }
512
564
}
513
565
514
566
// `try_initialize` is only called once per os thread local variable,
515
567
// except in corner cases where thread_local dtors reference other
516
568
// thread_local's, or it is being recursively initialized.
517
569
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 > } ;
519
573
if ptr as usize == 1 {
520
574
// destructor is running
521
575
return None ;
@@ -526,29 +580,39 @@ pub mod os {
526
580
// local copy, so do that now.
527
581
let ptr: Box < Value < T > > = box Value { inner : LazyKeyInner :: new ( ) , key : self } ;
528
582
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
+ }
530
588
ptr
531
589
} else {
532
590
// recursive initialization
533
591
ptr
534
592
} ;
535
593
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) ) }
537
597
}
538
598
}
539
599
540
600
unsafe extern "C" fn destroy_value < T : ' static > ( ptr : * mut u8 ) {
601
+ // SAFETY:
602
+ //
541
603
// The OS TLS ensures that this key contains a NULL value when this
542
604
// destructor starts to run. We set it back to a sentinel value of 1 to
543
605
// ensure that any future calls to `get` for this thread will return
544
606
// `None`.
545
607
//
546
608
// Note that to prevent an infinite loop we reset it back to null right
547
609
// 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
+ }
553
617
}
554
618
}
0 commit comments