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