| 1 | // This file is part of ICU4X. For terms of use, please see the file |
| 2 | // called LICENSE at the top level of the ICU4X source tree |
| 3 | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
| 4 | |
| 5 | use core::mem::{ManuallyDrop, MaybeUninit}; |
| 6 | use core::ops::{Deref, DerefMut}; |
| 7 | |
| 8 | /// This type is intended to be similar to the type `MaybeDangling<T>` |
| 9 | /// proposed in [RFC 3336]. |
| 10 | /// |
| 11 | /// The effect of this is that in Rust's safety model, types inside here are not |
| 12 | /// expected to have any memory dependent validity properties (`dereferenceable`, `noalias`). |
| 13 | /// |
| 14 | /// See [#3696] for a testcase where `Yoke` fails under miri's field-retagging mode if not using |
| 15 | /// KindaSortaDangling. |
| 16 | /// |
| 17 | /// This has `T: 'static` since we don't need anything |
| 18 | /// else and we don't want to have to think (more) about variance over lifetimes or dropck. |
| 19 | /// |
| 20 | /// After [RFC 3336] lands we can use `MaybeDangling` instead. |
| 21 | /// |
| 22 | /// Note that a version of this type also exists publicly as the [`maybe_dangling`] |
| 23 | /// crate; which also exports a patched `ManuallyDrop` with similar semantics and |
| 24 | /// does not require `T: 'static`. Consider using this if you need something more general |
| 25 | /// and are okay with adding dependencies. |
| 26 | /// |
| 27 | /// [RFC 3336]: https://github.com/rust-lang/rfcs/pull/3336 |
| 28 | /// [#3696]: https://github.com/unicode-org/icu4x/issues/3696 |
| 29 | /// [`maybe_dangling`](https://docs.rs/maybe-dangling/0.1.0/maybe_dangling/struct.MaybeDangling.html) |
| 30 | #[repr (transparent)] |
| 31 | pub(crate) struct KindaSortaDangling<T: 'static> { |
| 32 | /// Safety invariant: This is always an initialized T, never uninit or other |
| 33 | /// invalid bit patterns. Its drop glue will execute during Drop::drop rather than |
| 34 | /// during the drop glue for KindaSortaDangling, which means that we have to be careful about |
| 35 | /// not touching the values as initialized during `drop` after that, but that's a short period of time. |
| 36 | dangle: MaybeUninit<T>, |
| 37 | } |
| 38 | |
| 39 | impl<T: 'static> KindaSortaDangling<T> { |
| 40 | #[inline ] |
| 41 | pub(crate) const fn new(dangle: T) -> Self { |
| 42 | KindaSortaDangling { |
| 43 | dangle: MaybeUninit::new(val:dangle), |
| 44 | } |
| 45 | } |
| 46 | #[inline ] |
| 47 | pub(crate) fn into_inner(self) -> T { |
| 48 | // Self has a destructor, we want to avoid having it be called |
| 49 | let manual: ManuallyDrop> = ManuallyDrop::new(self); |
| 50 | // Safety: |
| 51 | // We can call assume_init_read() due to the library invariant on this type, |
| 52 | // however since it is a read() we must be careful about data duplication. |
| 53 | // The only code using `self` after this is the drop glue, which we have disabled via |
| 54 | // the ManuallyDrop. |
| 55 | unsafe { manual.dangle.assume_init_read() } |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | impl<T: 'static> Deref for KindaSortaDangling<T> { |
| 60 | type Target = T; |
| 61 | #[inline ] |
| 62 | fn deref(&self) -> &T { |
| 63 | // Safety: Due to the safety invariant on `dangle`, it is guaranteed to be always |
| 64 | // initialized as deref is never called during drop. |
| 65 | unsafe { self.dangle.assume_init_ref() } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | impl<T: 'static> DerefMut for KindaSortaDangling<T> { |
| 70 | #[inline ] |
| 71 | fn deref_mut(&mut self) -> &mut T { |
| 72 | // Safety: Due to the safety invariant on `dangle`, it is guaranteed to be always |
| 73 | // initialized as deref_mut is never called during drop. |
| 74 | unsafe { self.dangle.assume_init_mut() } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | impl<T: 'static> Drop for KindaSortaDangling<T> { |
| 79 | #[inline ] |
| 80 | fn drop(&mut self) { |
| 81 | // Safety: We are reading and dropping a valid initialized T. |
| 82 | // |
| 83 | // As `drop_in_place()` is a `read()`-like duplication operation we must be careful that the original value isn't |
| 84 | // used afterwards. It won't be because this is drop and the only |
| 85 | // code that will run after this is `self`'s drop glue, and that drop glue is empty |
| 86 | // because MaybeUninit has no drop. |
| 87 | // |
| 88 | // We use `drop_in_place()` instead of `let _ = ... .assume_init_read()` to avoid creating a move |
| 89 | // of the inner `T` (without `KindaSortaDangling` protection!) type into a local -- we don't want to |
| 90 | // assert any of `T`'s memory-related validity properties here. |
| 91 | unsafe { |
| 92 | self.dangle.as_mut_ptr().drop_in_place(); |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | |