OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 * | |
10 */ | |
11 | |
12 // Borrowed from Chromium's src/base/numerics/safe_math.h. | |
13 // - Modified to work in WebRTC (paths, namespace, use of webrtc/base). | |
14 // Based on 'chromium_revision': 'ee311243eae6aef9c907543663754ff38f1f4f40'. | |
15 | |
16 #ifndef WEBRTC_BASE_NUMERICS_SAFE_MATH_H_ | |
17 #define WEBRTC_BASE_NUMERICS_SAFE_MATH_H_ | |
18 | |
19 #include <stddef.h> | |
20 #include <type_traits> | |
21 | |
22 #include "webrtc/base/checks.h" | |
23 #include "webrtc/base/numerics/safe_math_impl.h" | |
24 | |
25 namespace rtc { | |
26 | |
27 namespace internal { | |
28 | |
29 // CheckedNumeric implements all the logic and operators for detecting integer | |
30 // boundary conditions such as overflow, underflow, and invalid conversions. | |
31 // The CheckedNumeric type implicitly converts from floating point and integer | |
32 // data types, and contains overloads for basic arithmetic operations (i.e.: +, | |
33 // -, *, /, %). | |
34 // | |
35 // The following methods convert from CheckedNumeric to standard numeric values: | |
36 // IsValid() - Returns true if the underlying numeric value is valid (i.e. has | |
37 // has not wrapped and is not the result of an invalid conversion). | |
38 // ValueOrDie() - Returns the underlying value. If the state is not valid this | |
39 // call will crash on a RTC_CHECK. | |
40 // ValueOrDefault() - Returns the current value, or the supplied default if the | |
41 // state is not valid. | |
42 // ValueFloating() - Returns the underlying floating point value (valid only | |
43 // only for floating point CheckedNumeric types). | |
44 // | |
45 // Bitwise operations are explicitly not supported, because correct | |
46 // handling of some cases (e.g. sign manipulation) is ambiguous. Comparison | |
47 // operations are explicitly not supported because they could result in a crash | |
48 // on a RTC_CHECK condition. You should use patterns like the following for | |
49 // these operations: | |
50 // Bitwise operation: | |
51 // CheckedNumeric<int> checked_int = untrusted_input_value; | |
52 // int x = checked_int.ValueOrDefault(0) | kFlagValues; | |
53 // Comparison: | |
54 // CheckedNumeric<size_t> checked_size = untrusted_input_value; | |
55 // checked_size += HEADER LENGTH; | |
56 // if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) | |
57 // Do stuff... | |
58 template <typename T> | |
59 class CheckedNumeric { | |
60 public: | |
61 typedef T type; | |
62 | |
63 CheckedNumeric() {} | |
64 | |
65 // Copy constructor. | |
66 template <typename Src> | |
67 CheckedNumeric(const CheckedNumeric<Src>& rhs) | |
68 : state_(rhs.ValueUnsafe(), rhs.validity()) {} | |
69 | |
70 template <typename Src> | |
71 CheckedNumeric(Src value, RangeConstraint validity) | |
72 : state_(value, validity) {} | |
73 | |
74 // This is not an explicit constructor because we implicitly upgrade regular | |
75 // numerics to CheckedNumerics to make them easier to use. | |
76 template <typename Src> | |
77 CheckedNumeric(Src value) | |
78 : state_(value) { | |
79 static_assert(std::numeric_limits<Src>::is_specialized, | |
80 "Argument must be numeric."); | |
81 } | |
82 | |
83 // This is not an explicit constructor because we want a seamless conversion | |
84 // from StrictNumeric types. | |
85 template <typename Src> | |
86 CheckedNumeric(StrictNumeric<Src> value) | |
87 : state_(static_cast<Src>(value)) { | |
88 } | |
89 | |
90 // IsValid() is the public API to test if a CheckedNumeric is currently valid. | |
91 bool IsValid() const { return validity() == RANGE_VALID; } | |
92 | |
93 // ValueOrDie() The primary accessor for the underlying value. If the current | |
94 // state is not valid it will RTC_CHECK and crash. | |
95 T ValueOrDie() const { | |
96 RTC_CHECK(IsValid()); | |
97 return state_.value(); | |
98 } | |
99 | |
100 // ValueOrDefault(T default_value) A convenience method that returns the | |
101 // current value if the state is valid, and the supplied default_value for | |
102 // any other state. | |
103 T ValueOrDefault(T default_value) const { | |
104 return IsValid() ? state_.value() : default_value; | |
105 } | |
106 | |
107 // ValueFloating() - Since floating point values include their validity state, | |
108 // we provide an easy method for extracting them directly, without a risk of | |
109 // crashing on a RTC_CHECK. | |
110 T ValueFloating() const { | |
111 static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float."); | |
112 return CheckedNumeric<T>::cast(*this).ValueUnsafe(); | |
113 } | |
114 | |
115 // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for | |
116 // tests and to avoid a big matrix of friend operator overloads. But the | |
117 // values it returns are likely to change in the future. | |
118 // Returns: current validity state (i.e. valid, overflow, underflow, nan). | |
119 // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for | |
120 // saturation/wrapping so we can expose this state consistently and implement | |
121 // saturated arithmetic. | |
122 RangeConstraint validity() const { return state_.validity(); } | |
123 | |
124 // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now | |
125 // for tests and to avoid a big matrix of friend operator overloads. But the | |
126 // values it returns are likely to change in the future. | |
127 // Returns: the raw numeric value, regardless of the current state. | |
128 // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for | |
129 // saturation/wrapping so we can expose this state consistently and implement | |
130 // saturated arithmetic. | |
131 T ValueUnsafe() const { return state_.value(); } | |
132 | |
133 // Prototypes for the supported arithmetic operator overloads. | |
134 template <typename Src> CheckedNumeric& operator+=(Src rhs); | |
135 template <typename Src> CheckedNumeric& operator-=(Src rhs); | |
136 template <typename Src> CheckedNumeric& operator*=(Src rhs); | |
137 template <typename Src> CheckedNumeric& operator/=(Src rhs); | |
138 template <typename Src> CheckedNumeric& operator%=(Src rhs); | |
139 | |
140 CheckedNumeric operator-() const { | |
141 RangeConstraint validity; | |
142 T value = CheckedNeg(state_.value(), &validity); | |
143 // Negation is always valid for floating point. | |
144 if (std::numeric_limits<T>::is_iec559) | |
145 return CheckedNumeric<T>(value); | |
146 | |
147 validity = GetRangeConstraint(state_.validity() | validity); | |
148 return CheckedNumeric<T>(value, validity); | |
149 } | |
150 | |
151 CheckedNumeric Abs() const { | |
152 RangeConstraint validity; | |
153 T value = CheckedAbs(state_.value(), &validity); | |
154 // Absolute value is always valid for floating point. | |
155 if (std::numeric_limits<T>::is_iec559) | |
156 return CheckedNumeric<T>(value); | |
157 | |
158 validity = GetRangeConstraint(state_.validity() | validity); | |
159 return CheckedNumeric<T>(value, validity); | |
160 } | |
161 | |
162 // This function is available only for integral types. It returns an unsigned | |
163 // integer of the same width as the source type, containing the absolute value | |
164 // of the source, and properly handling signed min. | |
165 CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const { | |
166 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( | |
167 CheckedUnsignedAbs(state_.value()), state_.validity()); | |
168 } | |
169 | |
170 CheckedNumeric& operator++() { | |
171 *this += 1; | |
172 return *this; | |
173 } | |
174 | |
175 CheckedNumeric operator++(int) { | |
176 CheckedNumeric value = *this; | |
177 *this += 1; | |
178 return value; | |
179 } | |
180 | |
181 CheckedNumeric& operator--() { | |
182 *this -= 1; | |
183 return *this; | |
184 } | |
185 | |
186 CheckedNumeric operator--(int) { | |
187 CheckedNumeric value = *this; | |
188 *this -= 1; | |
189 return value; | |
190 } | |
191 | |
192 // These static methods behave like a convenience cast operator targeting | |
193 // the desired CheckedNumeric type. As an optimization, a reference is | |
194 // returned when Src is the same type as T. | |
195 template <typename Src> | |
196 static CheckedNumeric<T> cast( | |
197 Src u, | |
198 typename std::enable_if<std::numeric_limits<Src>::is_specialized, | |
199 int>::type = 0) { | |
200 return u; | |
201 } | |
202 | |
203 template <typename Src> | |
204 static CheckedNumeric<T> cast( | |
205 const CheckedNumeric<Src>& u, | |
206 typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) { | |
207 return u; | |
208 } | |
209 | |
210 static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; } | |
211 | |
212 private: | |
213 template <typename NumericType> | |
214 struct UnderlyingType { | |
215 using type = NumericType; | |
216 }; | |
217 | |
218 template <typename NumericType> | |
219 struct UnderlyingType<CheckedNumeric<NumericType>> { | |
220 using type = NumericType; | |
221 }; | |
222 | |
223 CheckedNumericState<T> state_; | |
224 }; | |
225 | |
226 // This is the boilerplate for the standard arithmetic operator overloads. A | |
227 // macro isn't the prettiest solution, but it beats rewriting these five times. | |
228 // Some details worth noting are: | |
229 // * We apply the standard arithmetic promotions. | |
230 // * We skip range checks for floating points. | |
231 // * We skip range checks for destination integers with sufficient range. | |
232 // TODO(jschuh): extract these out into templates. | |
233 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ | |
234 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ | |
235 template <typename T> \ | |
236 CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \ | |
237 const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) { \ | |
238 typedef typename ArithmeticPromotion<T>::type Promotion; \ | |
239 /* Floating point always takes the fast path */ \ | |
240 if (std::numeric_limits<T>::is_iec559) \ | |
241 return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ | |
242 if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ | |
243 return CheckedNumeric<Promotion>( \ | |
244 lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ | |
245 GetRangeConstraint(rhs.validity() | lhs.validity())); \ | |
246 RangeConstraint validity = RANGE_VALID; \ | |
247 T result = static_cast<T>(Checked##NAME( \ | |
248 static_cast<Promotion>(lhs.ValueUnsafe()), \ | |
249 static_cast<Promotion>(rhs.ValueUnsafe()), \ | |
250 &validity)); \ | |
251 return CheckedNumeric<Promotion>( \ | |
252 result, \ | |
253 GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \ | |
254 } \ | |
255 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ | |
256 template <typename T> \ | |
257 template <typename Src> \ | |
258 CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \ | |
259 *this = CheckedNumeric<T>::cast(*this) \ | |
260 OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \ | |
261 return *this; \ | |
262 } \ | |
263 /* Binary arithmetic operator for CheckedNumeric of different type. */ \ | |
264 template <typename T, typename Src> \ | |
265 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | |
266 const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) { \ | |
267 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | |
268 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | |
269 return CheckedNumeric<Promotion>( \ | |
270 lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ | |
271 GetRangeConstraint(rhs.validity() | lhs.validity())); \ | |
272 return CheckedNumeric<Promotion>::cast(lhs) \ | |
273 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
274 } \ | |
275 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ | |
276 template <typename T, typename Src> \ | |
277 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | |
278 const CheckedNumeric<T>& lhs, Src rhs) { \ | |
279 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | |
280 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | |
281 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs, \ | |
282 lhs.validity()); \ | |
283 return CheckedNumeric<Promotion>::cast(lhs) \ | |
284 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
285 } \ | |
286 /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \ | |
287 template <typename T, typename Src> \ | |
288 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | |
289 Src lhs, const CheckedNumeric<T>& rhs) { \ | |
290 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | |
291 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | |
292 return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \ | |
293 rhs.validity()); \ | |
294 return CheckedNumeric<Promotion>::cast(lhs) \ | |
295 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
296 } | |
297 | |
298 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) | |
299 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) | |
300 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) | |
301 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) | |
302 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) | |
303 | |
304 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS | |
305 | |
306 } // namespace internal | |
307 | |
308 using internal::CheckedNumeric; | |
309 | |
310 } // namespace rtc | |
311 | |
312 #endif // WEBRTC_BASE_NUMERICS_SAFE_MATH_H_ | |
OLD | NEW |