1 pub(crate) trait ForceAdd: Sized {
force_add(self, rhs: Self) -> Self2 fn force_add(self, rhs: Self) -> Self;
3 }
4
5 impl ForceAdd for u8 {
force_add(self, rhs: Self) -> Self6 fn force_add(self, rhs: Self) -> Self {
7 self.checked_add(rhs).unwrap_or_else(die)
8 }
9 }
10
11 impl ForceAdd for i32 {
force_add(self, rhs: Self) -> Self12 fn force_add(self, rhs: Self) -> Self {
13 self.checked_add(rhs).unwrap_or_else(die)
14 }
15 }
16
17 impl ForceAdd for u32 {
force_add(self, rhs: Self) -> Self18 fn force_add(self, rhs: Self) -> Self {
19 self.checked_add(rhs).unwrap_or_else(die)
20 }
21 }
22
23 impl ForceAdd for u64 {
force_add(self, rhs: Self) -> Self24 fn force_add(self, rhs: Self) -> Self {
25 self.checked_add(rhs).unwrap_or_else(die)
26 }
27 }
28
29 impl ForceAdd for usize {
force_add(self, rhs: Self) -> Self30 fn force_add(self, rhs: Self) -> Self {
31 self.checked_add(rhs).unwrap_or_else(die)
32 }
33 }
34
35 pub(crate) trait ForceMul: Sized {
force_mul(self, rhs: Self) -> Self36 fn force_mul(self, rhs: Self) -> Self;
37 }
38
39 impl ForceMul for i32 {
force_mul(self, rhs: Self) -> Self40 fn force_mul(self, rhs: Self) -> Self {
41 self.checked_mul(rhs).unwrap_or_else(die)
42 }
43 }
44
45 impl ForceMul for i64 {
force_mul(self, rhs: Self) -> Self46 fn force_mul(self, rhs: Self) -> Self {
47 self.checked_mul(rhs).unwrap_or_else(die)
48 }
49 }
50
51 impl ForceMul for u64 {
force_mul(self, rhs: Self) -> Self52 fn force_mul(self, rhs: Self) -> Self {
53 self.checked_mul(rhs).unwrap_or_else(die)
54 }
55 }
56
57 pub(crate) trait ForceInto {
force_into<U>(self) -> U where Self: TryInto<U>58 fn force_into<U>(self) -> U
59 where
60 Self: TryInto<U>;
61 }
62
63 impl<T> ForceInto for T {
force_into<U>(self) -> U where Self: TryInto<U>,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]
die<T>() -> T96 pub(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 }
112