@@ -288,7 +288,11 @@ mod lazy {
288
288
}
289
289
290
290
pub unsafe fn get ( & self ) -> Option < & ' static T > {
291
- ( * self . inner . get ( ) ) . as_ref ( )
291
+ // SAFETY: No reference is ever handed out to the inner cell nor
292
+ // mutable reference to the Option<T> inside said cell. This make it
293
+ // safe to hand a reference, though the lifetime of 'static
294
+ // is itself unsafe, making the get method unsafe.
295
+ unsafe { ( * self . inner . get ( ) ) . as_ref ( ) }
292
296
}
293
297
294
298
pub unsafe fn initialize < F : FnOnce ( ) -> T > ( & self , init : F ) -> & ' static T {
@@ -297,6 +301,8 @@ mod lazy {
297
301
let value = init ( ) ;
298
302
let ptr = self . inner . get ( ) ;
299
303
304
+ // SAFETY:
305
+ //
300
306
// note that this can in theory just be `*ptr = Some(value)`, but due to
301
307
// the compiler will currently codegen that pattern with something like:
302
308
//
@@ -309,22 +315,31 @@ mod lazy {
309
315
// value (an aliasing violation). To avoid setting the "I'm running a
310
316
// destructor" flag we just use `mem::replace` which should sequence the
311
317
// 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 ( ) ,
318
+ unsafe {
319
+ let _ = mem:: replace ( & mut * ptr, Some ( value) ) ;
320
+ }
321
+
322
+ // SAFETY: the *ptr operation is made safe by the `mem::replace`
323
+ // call above that made sure a valid value is present behind it.
324
+ unsafe {
325
+ // After storing `Some` we want to get a reference to the contents of
326
+ // what we just stored. While we could use `unwrap` here and it should
327
+ // always work it empirically doesn't seem to always get optimized away,
328
+ // which means that using something like `try_with` can pull in
329
+ // panicking code and cause a large size bloat.
330
+ match * ptr {
331
+ Some ( ref x) => x,
332
+ None => hint:: unreachable_unchecked ( ) ,
333
+ }
322
334
}
323
335
}
324
336
325
337
#[ allow( unused) ]
326
338
pub unsafe fn take ( & mut self ) -> Option < T > {
327
- ( * self . inner . get ( ) ) . take ( )
339
+ // SAFETY: The other methods hand out references while taking &self.
340
+ // As such, calling this method when such references are still alive
341
+ // will fail because it takes a &mut self, conflicting with them.
342
+ unsafe { ( * self . inner . get ( ) ) . take ( ) }
328
343
}
329
344
}
330
345
}
@@ -413,9 +428,17 @@ pub mod fast {
413
428
}
414
429
415
430
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) ,
431
+ // SAFETY: See the definitions of `LazyKeyInner::get` and
432
+ // `try_initialize` for more informations.
433
+ //
434
+ // The call to `get` is made safe because no mutable references are
435
+ // ever handed out and the `try_initialize` is dependant on the
436
+ // passed `init` function.
437
+ unsafe {
438
+ match self . inner . get ( ) {
439
+ Some ( val) => Some ( val) ,
440
+ None => self . try_initialize ( init) ,
441
+ }
419
442
}
420
443
}
421
444
@@ -428,8 +451,10 @@ pub mod fast {
428
451
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
429
452
#[ inline( never) ]
430
453
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) )
454
+ // SAFETY: See comment above.
455
+ if !mem:: needs_drop :: < T > ( ) || unsafe { self . try_register_dtor ( ) } {
456
+ // SAFETY: See comment above.
457
+ Some ( unsafe { self . inner . initialize ( init) } )
433
458
} else {
434
459
None
435
460
}
@@ -441,8 +466,12 @@ pub mod fast {
441
466
unsafe fn try_register_dtor ( & self ) -> bool {
442
467
match self . dtor_state . get ( ) {
443
468
DtorState :: Unregistered => {
444
- // dtor registration happens before initialization.
445
- register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) ;
469
+ // SAFETY: dtor registration happens before initialization.
470
+ // Passing `self` as a pointer while using `destroy_value<T>`
471
+ // is safe because the function will build a pointer to a
472
+ // Key<T>, which is the type of self and so find the correct
473
+ // size.
474
+ unsafe { register_dtor ( self as * const _ as * mut u8 , destroy_value :: < T > ) } ;
446
475
self . dtor_state . set ( DtorState :: Registered ) ;
447
476
true
448
477
}
@@ -458,13 +487,21 @@ pub mod fast {
458
487
unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
459
488
let ptr = ptr as * mut Key < T > ;
460
489
490
+ // SAFETY:
491
+ //
492
+ // The pointer `ptr` has been built just above and comes from
493
+ // `try_register_dtor` where it is originally a Key<T> coming from `self`,
494
+ // making it non-NUL and of the correct type.
495
+ //
461
496
// Right before we run the user destructor be sure to set the
462
497
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
463
498
// causes future calls to `get` to run `try_initialize_drop` again,
464
499
// which will now fail, and return `None`.
465
- let value = ( * ptr) . inner . take ( ) ;
466
- ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
467
- drop ( value) ;
500
+ unsafe {
501
+ let value = ( * ptr) . inner . take ( ) ;
502
+ ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
503
+ drop ( value) ;
504
+ }
468
505
}
469
506
}
470
507
@@ -533,22 +570,28 @@ pub mod os {
533
570
ptr
534
571
} ;
535
572
536
- Some ( ( * ptr) . inner . initialize ( init) )
573
+ // SAFETY: ptr has been ensured as non-NUL just above an so can be
574
+ // dereferenced safely.
575
+ unsafe { Some ( ( * ptr) . inner . initialize ( init) ) }
537
576
}
538
577
}
539
578
540
579
unsafe extern "C" fn destroy_value < T : ' static > ( ptr : * mut u8 ) {
580
+ // SAFETY:
581
+ //
541
582
// The OS TLS ensures that this key contains a NULL value when this
542
583
// destructor starts to run. We set it back to a sentinel value of 1 to
543
584
// ensure that any future calls to `get` for this thread will return
544
585
// `None`.
545
586
//
546
587
// Note that to prevent an infinite loop we reset it back to null right
547
588
// 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 ( ) ) ;
589
+ unsafe {
590
+ let ptr = Box :: from_raw ( ptr as * mut Value < T > ) ;
591
+ let key = ptr. key ;
592
+ key. os . set ( 1 as * mut u8 ) ;
593
+ drop ( ptr) ;
594
+ key. os . set ( ptr:: null_mut ( ) ) ;
595
+ }
553
596
}
554
597
}
0 commit comments