@@ -289,15 +289,23 @@ mod lazy {
289
289
}
290
290
291
291
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 ( ) }
293
297
}
294
298
299
+ /// The caller must ensure that no reference is active: this method
300
+ /// needs unique access.
295
301
pub unsafe fn initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> & ' static T {
296
302
// Execute the initialization up front, *then* move it into our slot,
297
303
// just in case initialization fails.
298
304
let value = init ( ) ;
299
305
let ptr = self . inner . get ( ) ;
300
306
307
+ // SAFETY:
308
+ //
301
309
// note that this can in theory just be `*ptr = Some(value)`, but due to
302
310
// the compiler will currently codegen that pattern with something like:
303
311
//
@@ -310,22 +318,36 @@ mod lazy {
310
318
// value (an aliasing violation). To avoid setting the "I'm running a
311
319
// destructor" flag we just use `mem::replace` which should sequence the
312
320
// 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
+ }
323
341
}
324
342
}
325
343
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.
326
347
#[ allow( unused) ]
327
348
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 ( ) }
329
351
}
330
352
}
331
353
}
@@ -356,10 +378,17 @@ pub mod statik {
356
378
}
357
379
358
380
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
+ }
362
390
} ;
391
+
363
392
Some ( value)
364
393
}
365
394
}
@@ -414,9 +443,18 @@ pub mod fast {
414
443
}
415
444
416
445
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
+ }
420
458
}
421
459
}
422
460
@@ -429,8 +467,10 @@ pub mod fast {
429
467
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
430
468
#[ inline( never) ]
431
469
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) } )
434
474
} else {
435
475
None
436
476
}
@@ -442,8 +482,12 @@ pub mod fast {
442
482
unsafe fn try_register_dtor ( & self ) -> bool {
443
483
match self . dtor_state . get ( ) {
444
484
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 > ) } ;
447
491
self . dtor_state . set ( DtorState :: Registered ) ;
448
492
true
449
493
}
@@ -459,13 +503,21 @@ pub mod fast {
459
503
unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
460
504
let ptr = ptr as * mut Key < T > ;
461
505
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
+ //
462
512
// Right before we run the user destructor be sure to set the
463
513
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
464
514
// causes future calls to `get` to run `try_initialize_drop` again,
465
515
// 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
+ }
469
521
}
470
522
}
471
523
@@ -503,21 +555,30 @@ pub mod os {
503
555
Key { os : OsStaticKey :: new ( Some ( destroy_value :: < T > ) ) , marker : marker:: PhantomData }
504
556
}
505
557
558
+ /// It is a requirement for the caller to ensure that no mutable
559
+ /// reference is active when this method is called.
506
560
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 > } ;
508
563
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 ( ) } {
510
567
return Some ( value) ;
511
568
}
512
569
}
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) }
514
573
}
515
574
516
575
// `try_initialize` is only called once per os thread local variable,
517
576
// except in corner cases where thread_local dtors reference other
518
577
// thread_local's, or it is being recursively initialized.
519
578
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 > } ;
521
582
if ptr as usize == 1 {
522
583
// destructor is running
523
584
return None ;
@@ -528,29 +589,39 @@ pub mod os {
528
589
// local copy, so do that now.
529
590
let ptr: Box < Value < T > > = box Value { inner : LazyKeyInner :: new ( ) , key : self } ;
530
591
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
+ }
532
597
ptr
533
598
} else {
534
599
// recursive initialization
535
600
ptr
536
601
} ;
537
602
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) ) }
539
606
}
540
607
}
541
608
542
609
unsafe extern "C" fn destroy_value < T : ' static > ( ptr : * mut u8 ) {
610
+ // SAFETY:
611
+ //
543
612
// The OS TLS ensures that this key contains a NULL value when this
544
613
// destructor starts to run. We set it back to a sentinel value of 1 to
545
614
// ensure that any future calls to `get` for this thread will return
546
615
// `None`.
547
616
//
548
617
// Note that to prevent an infinite loop we reset it back to null right
549
618
// 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
+ }
555
626
}
556
627
}
0 commit comments