#
unsafe_libyaml/
ops.rs

    1pub(crate) trait ForceAdd: Sized {
    2    fn force_add(self, rhs: Self) -> Self;
    3}
    4
    5impl ForceAdd for u8 {
    6    fn force_add(self, rhs: Self) -> Self {
    7        self.checked_add(rhs).unwrap_or_else(die)
    8    }
    9}
    10
    11impl ForceAdd for i32 {
    12    fn force_add(self, rhs: Self) -> Self {
    13        self.checked_add(rhs).unwrap_or_else(die)
    14    }
    15}
    16
    17impl ForceAdd for u32 {
    18    fn force_add(self, rhs: Self) -> Self {
    19        self.checked_add(rhs).unwrap_or_else(die)
    20    }
    21}
    22
    23impl ForceAdd for u64 {
    24    fn force_add(self, rhs: Self) -> Self {
    25        self.checked_add(rhs).unwrap_or_else(die)
    26    }
    27}
    28
    29impl ForceAdd for usize {
    30    fn force_add(self, rhs: Self) -> Self {
    31        self.checked_add(rhs).unwrap_or_else(die)
    32    }
    33}
    34
    35pub(crate) trait ForceMul: Sized {
    36    fn force_mul(self, rhs: Self) -> Self;
    37}
    38
    39impl ForceMul for i32 {
    40    fn force_mul(self, rhs: Self) -> Self {
    41        self.checked_mul(rhs).unwrap_or_else(die)
    42    }
    43}
    44
    45impl ForceMul for i64 {
    46    fn force_mul(self, rhs: Self) -> Self {
    47        self.checked_mul(rhs).unwrap_or_else(die)
    48    }
    49}
    50
    51impl ForceMul for u64 {
    52    fn force_mul(self, rhs: Self) -> Self {
    53        self.checked_mul(rhs).unwrap_or_else(die)
    54    }
    55}
    56
    57pub(crate) trait ForceInto {
    58    fn force_into<U>(self) -> U
    59    where
    60        Self: TryInto<U>;
    61}
    62
    63impl<T> ForceInto for T {
    64    fn force_into<U>(self) -> U
    65    where
    66        Self: TryInto<U>,
    67    {
    68        <Self as TryInto<U>>::try_into(self)
    69            .ok()
    70            .unwrap_or_else(die)
    71    }
    72}
    73
    74// Deterministically abort on arithmetic overflow, instead of wrapping and
    75// continuing with invalid behavior.
    76//
    77// This is impossible or nearly impossible to hit as the arithmetic computations
    78// in libyaml are all related to either:
    79//
    80//  - small integer processing (ascii, hex digits)
    81//  - allocation sizing
    82//
    83// and the only allocations in libyaml are for fixed-sized objects and
    84// geometrically growing buffers with a growth factor of 2. So in order for an
    85// allocation computation to overflow usize, the previous allocation for that
    86// container must have been filled to a size of usize::MAX/2, which is an
    87// allocation that would have failed in the allocator. But we check for this to
    88// be pedantic and to find out if it ever does happen.
    89//
    90// No-std abort is implemented using a double panic. On most platforms the
    91// current mechanism for this is for core::intrinsics::abort to invoke an
    92// invalid instruction. On Unix, the process will probably terminate with a
    93// signal like SIGABRT, SIGILL, SIGTRAP, SIGSEGV or SIGBUS. The precise
    94// behaviour is not guaranteed and not stable, but is safe.
    95#[cold]
    96pub(crate) fn die<T>() -> T {
    97    struct PanicAgain;
    98
    99    impl Drop for PanicAgain {
    100        fn drop(&mut self) {
    101            panic!("arithmetic overflow");
    102        }
    103    }
    104
    105    fn do_die() -> ! {
    106        let _panic_again = PanicAgain;
    107        panic!("arithmetic overflow");
    108    }
    109
    110    do_die();
    111}