OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ | 5 #ifndef PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ |
6 #define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ | 6 #define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ |
7 | 7 |
| 8 #include <stddef.h> |
8 #include <stdint.h> | 9 #include <stdint.h> |
9 | 10 |
| 11 #include <climits> |
10 #include <cmath> | 12 #include <cmath> |
11 #include <cstdlib> | 13 #include <cstdlib> |
12 #include <limits> | 14 #include <limits> |
13 #include <type_traits> | 15 #include <type_traits> |
14 | 16 |
15 #include "safe_conversions.h" | 17 #include "safe_conversions.h" |
16 #include "third_party/base/macros.h" | 18 #include "third_party/base/macros.h" |
17 | 19 |
18 namespace pdfium { | 20 namespace pdfium { |
19 namespace base { | 21 namespace base { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 std::numeric_limits<Integer>::is_integer, | 85 std::numeric_limits<Integer>::is_integer, |
84 typename IntegerForSizeAndSign< | 86 typename IntegerForSizeAndSign< |
85 sizeof(Integer) * 2, | 87 sizeof(Integer) * 2, |
86 std::numeric_limits<Integer>::is_signed>::type>::type type; | 88 std::numeric_limits<Integer>::is_signed>::type>::type type; |
87 }; | 89 }; |
88 | 90 |
89 template <typename Integer> | 91 template <typename Integer> |
90 struct PositionOfSignBit { | 92 struct PositionOfSignBit { |
91 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, | 93 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, |
92 size_t>::type value = | 94 size_t>::type value = |
93 8 * sizeof(Integer) - 1; | 95 CHAR_BIT * sizeof(Integer) - 1; |
94 }; | 96 }; |
95 | 97 |
96 // Helper templates for integer manipulations. | 98 // Helper templates for integer manipulations. |
97 | 99 |
98 template <typename T> | 100 template <typename T> |
99 bool HasSignBit(T x) { | 101 constexpr bool HasSignBit(T x) { |
100 // Cast to unsigned since right shift on signed is undefined. | 102 // Cast to unsigned since right shift on signed is undefined. |
101 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> | 103 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> |
102 PositionOfSignBit<T>::value); | 104 PositionOfSignBit<T>::value); |
103 } | 105 } |
104 | 106 |
105 // This wrapper undoes the standard integer promotions. | 107 // This wrapper undoes the standard integer promotions. |
106 template <typename T> | 108 template <typename T> |
107 T BinaryComplement(T x) { | 109 constexpr T BinaryComplement(T x) { |
108 return ~x; | 110 return static_cast<T>(~x); |
109 } | 111 } |
110 | 112 |
111 // Here are the actual portable checked integer math implementations. | 113 // Here are the actual portable checked integer math implementations. |
112 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean | 114 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean |
113 // way to coalesce things into the CheckedNumericState specializations below. | 115 // way to coalesce things into the CheckedNumericState specializations below. |
114 | 116 |
115 template <typename T> | 117 template <typename T> |
116 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type | 118 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
117 CheckedAdd(T x, T y, RangeConstraint* validity) { | 119 CheckedAdd(T x, T y, RangeConstraint* validity) { |
118 // Since the value of x+y is undefined if we have a signed type, we compute | 120 // Since the value of x+y is undefined if we have a signed type, we compute |
119 // it using the unsigned type of the same size. | 121 // it using the unsigned type of the same size. |
120 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 122 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
121 UnsignedDst ux = static_cast<UnsignedDst>(x); | 123 UnsignedDst ux = static_cast<UnsignedDst>(x); |
122 UnsignedDst uy = static_cast<UnsignedDst>(y); | 124 UnsignedDst uy = static_cast<UnsignedDst>(y); |
123 UnsignedDst uresult = ux + uy; | 125 UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); |
124 // Addition is valid if the sign of (x + y) is equal to either that of x or | 126 // Addition is valid if the sign of (x + y) is equal to either that of x or |
125 // that of y. | 127 // that of y. |
126 if (std::numeric_limits<T>::is_signed) { | 128 if (std::numeric_limits<T>::is_signed) { |
127 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) | 129 if (HasSignBit(BinaryComplement( |
| 130 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy))))) { |
128 *validity = RANGE_VALID; | 131 *validity = RANGE_VALID; |
129 else // Direction of wrap is inverse of result sign. | 132 } else { // Direction of wrap is inverse of result sign. |
130 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | 133 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; |
131 | 134 } |
132 } else { // Unsigned is either valid or overflow. | 135 } else { // Unsigned is either valid or overflow. |
133 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; | 136 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; |
134 } | 137 } |
135 return static_cast<T>(uresult); | 138 return static_cast<T>(uresult); |
136 } | 139 } |
137 | 140 |
138 template <typename T> | 141 template <typename T> |
139 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type | 142 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
140 CheckedSub(T x, T y, RangeConstraint* validity) { | 143 CheckedSub(T x, T y, RangeConstraint* validity) { |
141 // Since the value of x+y is undefined if we have a signed type, we compute | 144 // Since the value of x+y is undefined if we have a signed type, we compute |
142 // it using the unsigned type of the same size. | 145 // it using the unsigned type of the same size. |
143 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 146 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
144 UnsignedDst ux = static_cast<UnsignedDst>(x); | 147 UnsignedDst ux = static_cast<UnsignedDst>(x); |
145 UnsignedDst uy = static_cast<UnsignedDst>(y); | 148 UnsignedDst uy = static_cast<UnsignedDst>(y); |
146 UnsignedDst uresult = ux - uy; | 149 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); |
147 // Subtraction is valid if either x and y have same sign, or (x-y) and x have | 150 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
148 // the same sign. | 151 // the same sign. |
149 if (std::numeric_limits<T>::is_signed) { | 152 if (std::numeric_limits<T>::is_signed) { |
150 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) | 153 if (HasSignBit(BinaryComplement( |
| 154 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy))))) { |
151 *validity = RANGE_VALID; | 155 *validity = RANGE_VALID; |
152 else // Direction of wrap is inverse of result sign. | 156 } else { // Direction of wrap is inverse of result sign. |
153 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | 157 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; |
154 | 158 } |
155 } else { // Unsigned is either valid or underflow. | 159 } else { // Unsigned is either valid or underflow. |
156 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; | 160 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; |
157 } | 161 } |
158 return static_cast<T>(uresult); | 162 return static_cast<T>(uresult); |
159 } | 163 } |
160 | 164 |
161 // Integer multiplication is a bit complicated. In the fast case we just | 165 // Integer multiplication is a bit complicated. In the fast case we just |
162 // we just promote to a twice wider type, and range check the result. In the | 166 // we just promote to a twice wider type, and range check the result. In the |
163 // slow case we need to manually check that the result won't be truncated by | 167 // slow case we need to manually check that the result won't be truncated by |
164 // checking with division against the appropriate bound. | 168 // checking with division against the appropriate bound. |
(...skipping 10 matching lines...) Expand all Loading... |
175 } | 179 } |
176 | 180 |
177 template <typename T> | 181 template <typename T> |
178 typename std::enable_if<std::numeric_limits<T>::is_integer && | 182 typename std::enable_if<std::numeric_limits<T>::is_integer && |
179 std::numeric_limits<T>::is_signed && | 183 std::numeric_limits<T>::is_signed && |
180 (sizeof(T) * 2 > sizeof(uintmax_t)), | 184 (sizeof(T) * 2 > sizeof(uintmax_t)), |
181 T>::type | 185 T>::type |
182 CheckedMul(T x, T y, RangeConstraint* validity) { | 186 CheckedMul(T x, T y, RangeConstraint* validity) { |
183 // If either side is zero then the result will be zero. | 187 // If either side is zero then the result will be zero. |
184 if (!x || !y) { | 188 if (!x || !y) { |
185 return RANGE_VALID; | 189 *validity = RANGE_VALID; |
186 | 190 return static_cast<T>(0); |
187 } else if (x > 0) { | 191 } |
188 if (y > 0) | 192 if (x > 0) { |
| 193 if (y > 0) { |
189 *validity = | 194 *validity = |
190 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; | 195 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; |
191 else | 196 } else { |
192 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID | 197 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID |
193 : RANGE_UNDERFLOW; | 198 : RANGE_UNDERFLOW; |
194 | 199 } |
195 } else { | 200 } else { |
196 if (y > 0) | 201 if (y > 0) { |
197 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID | 202 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID |
198 : RANGE_UNDERFLOW; | 203 : RANGE_UNDERFLOW; |
199 else | 204 } else { |
200 *validity = | 205 *validity = |
201 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; | 206 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; |
| 207 } |
202 } | 208 } |
203 | 209 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0); |
204 return x * y; | |
205 } | 210 } |
206 | 211 |
207 template <typename T> | 212 template <typename T> |
208 typename std::enable_if<std::numeric_limits<T>::is_integer && | 213 typename std::enable_if<std::numeric_limits<T>::is_integer && |
209 !std::numeric_limits<T>::is_signed && | 214 !std::numeric_limits<T>::is_signed && |
210 (sizeof(T) * 2 > sizeof(uintmax_t)), | 215 (sizeof(T) * 2 > sizeof(uintmax_t)), |
211 T>::type | 216 T>::type |
212 CheckedMul(T x, T y, RangeConstraint* validity) { | 217 CheckedMul(T x, T y, RangeConstraint* validity) { |
213 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) | 218 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) |
214 ? RANGE_VALID | 219 ? RANGE_VALID |
215 : RANGE_OVERFLOW; | 220 : RANGE_OVERFLOW; |
216 return x * y; | 221 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0); |
217 } | 222 } |
218 | 223 |
219 // Division just requires a check for an invalid negation on signed min/-1. | 224 // Division just requires a check for a zero denominator or an invalid negation |
| 225 // on signed min/-1. |
220 template <typename T> | 226 template <typename T> |
221 T CheckedDiv(T x, | 227 T CheckedDiv(T x, |
222 T y, | 228 T y, |
223 RangeConstraint* validity, | 229 RangeConstraint* validity, |
224 typename std::enable_if<std::numeric_limits<T>::is_integer, | 230 typename std::enable_if<std::numeric_limits<T>::is_integer, |
225 int>::type = 0) { | 231 int>::type = 0) { |
| 232 if (y == 0) { |
| 233 *validity = RANGE_INVALID; |
| 234 return static_cast<T>(0); |
| 235 } |
226 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && | 236 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && |
227 y == static_cast<T>(-1)) { | 237 y == static_cast<T>(-1)) { |
228 *validity = RANGE_OVERFLOW; | 238 *validity = RANGE_OVERFLOW; |
229 return std::numeric_limits<T>::min(); | 239 return std::numeric_limits<T>::min(); |
230 } | 240 } |
231 | |
232 *validity = RANGE_VALID; | 241 *validity = RANGE_VALID; |
233 return x / y; | 242 return static_cast<T>(x / y); |
234 } | 243 } |
235 | 244 |
236 template <typename T> | 245 template <typename T> |
237 typename std::enable_if<std::numeric_limits<T>::is_integer && | 246 typename std::enable_if<std::numeric_limits<T>::is_integer && |
238 std::numeric_limits<T>::is_signed, | 247 std::numeric_limits<T>::is_signed, |
239 T>::type | 248 T>::type |
240 CheckedMod(T x, T y, RangeConstraint* validity) { | 249 CheckedMod(T x, T y, RangeConstraint* validity) { |
241 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 250 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; |
242 return x % y; | 251 return static_cast<T>(*validity == RANGE_VALID ? x % y : 0); |
243 } | 252 } |
244 | 253 |
245 template <typename T> | 254 template <typename T> |
246 typename std::enable_if<std::numeric_limits<T>::is_integer && | 255 typename std::enable_if<std::numeric_limits<T>::is_integer && |
247 !std::numeric_limits<T>::is_signed, | 256 !std::numeric_limits<T>::is_signed, |
248 T>::type | 257 T>::type |
249 CheckedMod(T x, T y, RangeConstraint* validity) { | 258 CheckedMod(T x, T y, RangeConstraint* validity) { |
250 *validity = RANGE_VALID; | 259 *validity = y != 0 ? RANGE_VALID : RANGE_INVALID; |
251 return x % y; | 260 return static_cast<T>(*validity == RANGE_VALID ? x % y : 0); |
252 } | 261 } |
253 | 262 |
254 template <typename T> | 263 template <typename T> |
255 typename std::enable_if<std::numeric_limits<T>::is_integer && | 264 typename std::enable_if<std::numeric_limits<T>::is_integer && |
256 std::numeric_limits<T>::is_signed, | 265 std::numeric_limits<T>::is_signed, |
257 T>::type | 266 T>::type |
258 CheckedNeg(T value, RangeConstraint* validity) { | 267 CheckedNeg(T value, RangeConstraint* validity) { |
259 *validity = | 268 *validity = |
260 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 269 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
261 // The negation of signed min is min, so catch that one. | 270 // The negation of signed min is min, so catch that one. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 return value; | 302 return value; |
294 } | 303 } |
295 | 304 |
296 // These are the floating point stubs that the compiler needs to see. Only the | 305 // These are the floating point stubs that the compiler needs to see. Only the |
297 // negation operation is ever called. | 306 // negation operation is ever called. |
298 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 307 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
299 template <typename T> \ | 308 template <typename T> \ |
300 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 309 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ |
301 Checked##NAME(T, T, RangeConstraint*) { \ | 310 Checked##NAME(T, T, RangeConstraint*) { \ |
302 NOTREACHED(); \ | 311 NOTREACHED(); \ |
303 return 0; \ | 312 return static_cast<T>(0); \ |
304 } | 313 } |
305 | 314 |
306 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 315 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
307 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 316 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
308 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 317 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
309 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 318 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
310 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 319 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
311 | 320 |
312 #undef BASE_FLOAT_ARITHMETIC_STUBS | 321 #undef BASE_FLOAT_ARITHMETIC_STUBS |
313 | 322 |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 507 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
499 NUMERIC_RANGE_CONTAINED && | 508 NUMERIC_RANGE_CONTAINED && |
500 sizeof(T) >= (2 * sizeof(Rhs)); | 509 sizeof(T) >= (2 * sizeof(Rhs)); |
501 }; | 510 }; |
502 | 511 |
503 } // namespace internal | 512 } // namespace internal |
504 } // namespace base | 513 } // namespace base |
505 } // namespace pdfium | 514 } // namespace pdfium |
506 | 515 |
507 #endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ | 516 #endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ |
OLD | NEW |