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_BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
6 #define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ | 6 #define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 | 10 |
11 #include <climits> | 11 #include <climits> |
12 #include <cmath> | 12 #include <cmath> |
13 #include <cstdlib> | 13 #include <cstdlib> |
14 #include <limits> | 14 #include <limits> |
15 #include <type_traits> | 15 #include <type_traits> |
16 | 16 |
17 #include "safe_conversions.h" | |
18 #include "third_party/base/macros.h" | 17 #include "third_party/base/macros.h" |
| 18 #include "third_party/base/numerics/safe_conversions.h" |
19 | 19 |
20 namespace pdfium { | 20 namespace pdfium { |
21 namespace base { | 21 namespace base { |
22 namespace internal { | 22 namespace internal { |
23 | 23 |
24 // Everything from here up to the floating point operations is portable C++, | 24 // Everything from here up to the floating point operations is portable C++, |
25 // but it may not be fast. This code could be split based on | 25 // but it may not be fast. This code could be split based on |
26 // platform/architecture and replaced with potentially faster implementations. | 26 // platform/architecture and replaced with potentially faster implementations. |
27 | 27 |
28 // Integer promotion templates used by the portable checked integer arithmetic. | 28 // Integer promotion templates used by the portable checked integer arithmetic. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 std::numeric_limits<Integer>::is_signed>::type>::type type; | 88 std::numeric_limits<Integer>::is_signed>::type>::type type; |
89 }; | 89 }; |
90 | 90 |
91 template <typename Integer> | 91 template <typename Integer> |
92 struct PositionOfSignBit { | 92 struct PositionOfSignBit { |
93 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, |
94 size_t>::type value = | 94 size_t>::type value = |
95 CHAR_BIT * sizeof(Integer) - 1; | 95 CHAR_BIT * sizeof(Integer) - 1; |
96 }; | 96 }; |
97 | 97 |
| 98 // This is used for UnsignedAbs, where we need to support floating-point |
| 99 // template instantiations even though we don't actually support the operations. |
| 100 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, |
| 101 // so the float versions will not compile. |
| 102 template <typename Numeric, |
| 103 bool IsInteger = std::numeric_limits<Numeric>::is_integer, |
| 104 bool IsFloat = std::numeric_limits<Numeric>::is_iec559> |
| 105 struct UnsignedOrFloatForSize; |
| 106 |
| 107 template <typename Numeric> |
| 108 struct UnsignedOrFloatForSize<Numeric, true, false> { |
| 109 typedef typename UnsignedIntegerForSize<Numeric>::type type; |
| 110 }; |
| 111 |
| 112 template <typename Numeric> |
| 113 struct UnsignedOrFloatForSize<Numeric, false, true> { |
| 114 typedef Numeric type; |
| 115 }; |
| 116 |
98 // Helper templates for integer manipulations. | 117 // Helper templates for integer manipulations. |
99 | 118 |
100 template <typename T> | 119 template <typename T> |
101 constexpr bool HasSignBit(T x) { | 120 constexpr bool HasSignBit(T x) { |
102 // Cast to unsigned since right shift on signed is undefined. | 121 // Cast to unsigned since right shift on signed is undefined. |
103 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> | 122 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> |
104 PositionOfSignBit<T>::value); | 123 PositionOfSignBit<T>::value); |
105 } | 124 } |
106 | 125 |
107 // This wrapper undoes the standard integer promotions. | 126 // This wrapper undoes the standard integer promotions. |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 int>::type = 0) { | 250 int>::type = 0) { |
232 if (y == 0) { | 251 if (y == 0) { |
233 *validity = RANGE_INVALID; | 252 *validity = RANGE_INVALID; |
234 return static_cast<T>(0); | 253 return static_cast<T>(0); |
235 } | 254 } |
236 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && | 255 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && |
237 y == static_cast<T>(-1)) { | 256 y == static_cast<T>(-1)) { |
238 *validity = RANGE_OVERFLOW; | 257 *validity = RANGE_OVERFLOW; |
239 return std::numeric_limits<T>::min(); | 258 return std::numeric_limits<T>::min(); |
240 } | 259 } |
| 260 |
241 *validity = RANGE_VALID; | 261 *validity = RANGE_VALID; |
242 return static_cast<T>(x / y); | 262 return static_cast<T>(x / y); |
243 } | 263 } |
244 | 264 |
245 template <typename T> | 265 template <typename T> |
246 typename std::enable_if<std::numeric_limits<T>::is_integer && | 266 typename std::enable_if<std::numeric_limits<T>::is_integer && |
247 std::numeric_limits<T>::is_signed, | 267 std::numeric_limits<T>::is_signed, |
248 T>::type | 268 T>::type |
249 CheckedMod(T x, T y, RangeConstraint* validity) { | 269 CheckedMod(T x, T y, RangeConstraint* validity) { |
250 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 270 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; |
(...skipping 10 matching lines...) Expand all Loading... |
261 } | 281 } |
262 | 282 |
263 template <typename T> | 283 template <typename T> |
264 typename std::enable_if<std::numeric_limits<T>::is_integer && | 284 typename std::enable_if<std::numeric_limits<T>::is_integer && |
265 std::numeric_limits<T>::is_signed, | 285 std::numeric_limits<T>::is_signed, |
266 T>::type | 286 T>::type |
267 CheckedNeg(T value, RangeConstraint* validity) { | 287 CheckedNeg(T value, RangeConstraint* validity) { |
268 *validity = | 288 *validity = |
269 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 289 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
270 // The negation of signed min is min, so catch that one. | 290 // The negation of signed min is min, so catch that one. |
271 return -value; | 291 return static_cast<T>(*validity == RANGE_VALID ? -value : 0); |
272 } | 292 } |
273 | 293 |
274 template <typename T> | 294 template <typename T> |
275 typename std::enable_if<std::numeric_limits<T>::is_integer && | 295 typename std::enable_if<std::numeric_limits<T>::is_integer && |
276 !std::numeric_limits<T>::is_signed, | 296 !std::numeric_limits<T>::is_signed, |
277 T>::type | 297 T>::type |
278 CheckedNeg(T value, RangeConstraint* validity) { | 298 CheckedNeg(T value, RangeConstraint* validity) { |
279 // The only legal unsigned negation is zero. | 299 // The only legal unsigned negation is zero. |
280 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; | 300 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; |
281 return static_cast<T>( | 301 return static_cast<T>( |
282 -static_cast<typename SignedIntegerForSize<T>::type>(value)); | 302 *validity == RANGE_VALID |
| 303 ? -static_cast<typename SignedIntegerForSize<T>::type>(value) |
| 304 : 0); |
283 } | 305 } |
284 | 306 |
285 template <typename T> | 307 template <typename T> |
286 typename std::enable_if<std::numeric_limits<T>::is_integer && | 308 typename std::enable_if<std::numeric_limits<T>::is_integer && |
287 std::numeric_limits<T>::is_signed, | 309 std::numeric_limits<T>::is_signed, |
288 T>::type | 310 T>::type |
289 CheckedAbs(T value, RangeConstraint* validity) { | 311 CheckedAbs(T value, RangeConstraint* validity) { |
290 *validity = | 312 *validity = |
291 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 313 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
292 return std::abs(value); | 314 return static_cast<T>(*validity == RANGE_VALID ? std::abs(value) : 0); |
293 } | 315 } |
294 | 316 |
295 template <typename T> | 317 template <typename T> |
296 typename std::enable_if<std::numeric_limits<T>::is_integer && | 318 typename std::enable_if<std::numeric_limits<T>::is_integer && |
297 !std::numeric_limits<T>::is_signed, | 319 !std::numeric_limits<T>::is_signed, |
298 T>::type | 320 T>::type |
299 CheckedAbs(T value, RangeConstraint* validity) { | 321 CheckedAbs(T value, RangeConstraint* validity) { |
300 // Absolute value of a positive is just its identiy. | 322 // T is unsigned, so |value| must already be positive. |
301 *validity = RANGE_VALID; | 323 *validity = RANGE_VALID; |
302 return value; | 324 return value; |
303 } | 325 } |
304 | 326 |
| 327 template <typename T> |
| 328 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 329 std::numeric_limits<T>::is_signed, |
| 330 typename UnsignedIntegerForSize<T>::type>::type |
| 331 CheckedUnsignedAbs(T value) { |
| 332 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; |
| 333 return value == std::numeric_limits<T>::min() |
| 334 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 |
| 335 : static_cast<UnsignedT>(std::abs(value)); |
| 336 } |
| 337 |
| 338 template <typename T> |
| 339 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 340 !std::numeric_limits<T>::is_signed, |
| 341 T>::type |
| 342 CheckedUnsignedAbs(T value) { |
| 343 // T is unsigned, so |value| must already be positive. |
| 344 return static_cast<T>(value); |
| 345 } |
| 346 |
305 // These are the floating point stubs that the compiler needs to see. Only the | 347 // These are the floating point stubs that the compiler needs to see. Only the |
306 // negation operation is ever called. | 348 // negation operation is ever called. |
307 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 349 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
308 template <typename T> \ | 350 template <typename T> \ |
309 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 351 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ |
310 Checked##NAME(T, T, RangeConstraint*) { \ | 352 Checked##NAME(T, T, RangeConstraint*) { \ |
311 NOTREACHED(); \ | 353 NOTREACHED(); \ |
312 return static_cast<T>(0); \ | 354 return static_cast<T>(0); \ |
313 } | 355 } |
314 | 356 |
315 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 357 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
316 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 358 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
317 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 359 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
318 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 360 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
319 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 361 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
320 | 362 |
321 #undef BASE_FLOAT_ARITHMETIC_STUBS | 363 #undef BASE_FLOAT_ARITHMETIC_STUBS |
322 | 364 |
323 template <typename T> | 365 template <typename T> |
324 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( | 366 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( |
325 T value, | 367 T value, |
326 RangeConstraint*) { | 368 RangeConstraint*) { |
327 return -value; | 369 return static_cast<T>(-value); |
328 } | 370 } |
329 | 371 |
330 template <typename T> | 372 template <typename T> |
331 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( | 373 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( |
332 T value, | 374 T value, |
333 RangeConstraint*) { | 375 RangeConstraint*) { |
334 return std::abs(value); | 376 return static_cast<T>(std::abs(value)); |
335 } | 377 } |
336 | 378 |
337 // Floats carry around their validity state with them, but integers do not. So, | 379 // Floats carry around their validity state with them, but integers do not. So, |
338 // we wrap the underlying value in a specialization in order to hide that detail | 380 // we wrap the underlying value in a specialization in order to hide that detail |
339 // and expose an interface via accessors. | 381 // and expose an interface via accessors. |
340 enum NumericRepresentation { | 382 enum NumericRepresentation { |
341 NUMERIC_INTEGER, | 383 NUMERIC_INTEGER, |
342 NUMERIC_FLOATING, | 384 NUMERIC_FLOATING, |
343 NUMERIC_UNKNOWN | 385 NUMERIC_UNKNOWN |
344 }; | 386 }; |
345 | 387 |
346 template <typename NumericType> | 388 template <typename NumericType> |
347 struct GetNumericRepresentation { | 389 struct GetNumericRepresentation { |
348 static const NumericRepresentation value = | 390 static const NumericRepresentation value = |
349 std::numeric_limits<NumericType>::is_integer | 391 std::numeric_limits<NumericType>::is_integer |
350 ? NUMERIC_INTEGER | 392 ? NUMERIC_INTEGER |
351 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING | 393 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING |
352 : NUMERIC_UNKNOWN); | 394 : NUMERIC_UNKNOWN); |
353 }; | 395 }; |
354 | 396 |
355 template <typename T, NumericRepresentation type = | 397 template <typename T, NumericRepresentation type = |
356 GetNumericRepresentation<T>::value> | 398 GetNumericRepresentation<T>::value> |
357 class CheckedNumericState {}; | 399 class CheckedNumericState {}; |
358 | 400 |
359 // Integrals require quite a bit of additional housekeeping to manage state. | 401 // Integrals require quite a bit of additional housekeeping to manage state. |
360 template <typename T> | 402 template <typename T> |
361 class CheckedNumericState<T, NUMERIC_INTEGER> { | 403 class CheckedNumericState<T, NUMERIC_INTEGER> { |
362 private: | 404 private: |
363 T value_; | 405 T value_; |
364 RangeConstraint validity_; | 406 RangeConstraint validity_ : CHAR_BIT; // Actually requires only two bits. |
365 | 407 |
366 public: | 408 public: |
367 template <typename Src, NumericRepresentation type> | 409 template <typename Src, NumericRepresentation type> |
368 friend class CheckedNumericState; | 410 friend class CheckedNumericState; |
369 | 411 |
370 CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} | 412 CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} |
371 | 413 |
372 template <typename Src> | 414 template <typename Src> |
373 CheckedNumericState(Src value, RangeConstraint validity) | 415 CheckedNumericState(Src value, RangeConstraint validity) |
374 : value_(value), | 416 : value_(static_cast<T>(value)), |
375 validity_(GetRangeConstraint(validity | | 417 validity_(GetRangeConstraint(validity | |
376 DstRangeRelationToSrcRange<T>(value))) { | 418 DstRangeRelationToSrcRange<T>(value))) { |
377 COMPILE_ASSERT(std::numeric_limits<Src>::is_specialized, | 419 static_assert(std::numeric_limits<Src>::is_specialized, |
378 argument_must_be_numeric); | 420 "Argument must be numeric."); |
379 } | 421 } |
380 | 422 |
381 // Copy constructor. | 423 // Copy constructor. |
382 template <typename Src> | 424 template <typename Src> |
383 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 425 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
384 : value_(static_cast<T>(rhs.value())), | 426 : value_(static_cast<T>(rhs.value())), |
385 validity_(GetRangeConstraint( | 427 validity_(GetRangeConstraint( |
386 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} | 428 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} |
387 | 429 |
388 template <typename Src> | 430 template <typename Src> |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 491 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
450 : value_(static_cast<T>(rhs.value())) {} | 492 : value_(static_cast<T>(rhs.value())) {} |
451 | 493 |
452 RangeConstraint validity() const { | 494 RangeConstraint validity() const { |
453 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), | 495 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), |
454 value_ >= -std::numeric_limits<T>::max()); | 496 value_ >= -std::numeric_limits<T>::max()); |
455 } | 497 } |
456 T value() const { return value_; } | 498 T value() const { return value_; } |
457 }; | 499 }; |
458 | 500 |
459 // For integers less than 128-bit and floats 32-bit or larger, we can distil | 501 // For integers less than 128-bit and floats 32-bit or larger, we have the type |
460 // C/C++ arithmetic promotions down to two simple rules: | 502 // with the larger maximum exponent take precedence. |
461 // 1. The type with the larger maximum exponent always takes precedence. | 503 enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION }; |
462 // 2. The resulting type must be promoted to at least an int. | |
463 // The following template specializations implement that promotion logic. | |
464 enum ArithmeticPromotionCategory { | |
465 LEFT_PROMOTION, | |
466 RIGHT_PROMOTION, | |
467 DEFAULT_PROMOTION | |
468 }; | |
469 | 504 |
470 template <typename Lhs, | 505 template <typename Lhs, |
471 typename Rhs = Lhs, | 506 typename Rhs = Lhs, |
472 ArithmeticPromotionCategory Promotion = | 507 ArithmeticPromotionCategory Promotion = |
473 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) | 508 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) |
474 ? (MaxExponent<Lhs>::value > MaxExponent<int>::value | 509 ? LEFT_PROMOTION |
475 ? LEFT_PROMOTION | 510 : RIGHT_PROMOTION> |
476 : DEFAULT_PROMOTION) | |
477 : (MaxExponent<Rhs>::value > MaxExponent<int>::value | |
478 ? RIGHT_PROMOTION | |
479 : DEFAULT_PROMOTION) > | |
480 struct ArithmeticPromotion; | 511 struct ArithmeticPromotion; |
481 | 512 |
482 template <typename Lhs, typename Rhs> | 513 template <typename Lhs, typename Rhs> |
483 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { | 514 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { |
484 typedef Lhs type; | 515 typedef Lhs type; |
485 }; | 516 }; |
486 | 517 |
487 template <typename Lhs, typename Rhs> | 518 template <typename Lhs, typename Rhs> |
488 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { | 519 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { |
489 typedef Rhs type; | 520 typedef Rhs type; |
490 }; | 521 }; |
491 | 522 |
492 template <typename Lhs, typename Rhs> | |
493 struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> { | |
494 typedef int type; | |
495 }; | |
496 | |
497 // We can statically check if operations on the provided types can wrap, so we | 523 // We can statically check if operations on the provided types can wrap, so we |
498 // can skip the checked operations if they're not needed. So, for an integer we | 524 // can skip the checked operations if they're not needed. So, for an integer we |
499 // care if the destination type preserves the sign and is twice the width of | 525 // care if the destination type preserves the sign and is twice the width of |
500 // the source. | 526 // the source. |
501 template <typename T, typename Lhs, typename Rhs> | 527 template <typename T, typename Lhs, typename Rhs> |
502 struct IsIntegerArithmeticSafe { | 528 struct IsIntegerArithmeticSafe { |
503 static const bool value = !std::numeric_limits<T>::is_iec559 && | 529 static const bool value = !std::numeric_limits<T>::is_iec559 && |
504 StaticDstRangeRelationToSrcRange<T, Lhs>::value == | 530 StaticDstRangeRelationToSrcRange<T, Lhs>::value == |
505 NUMERIC_RANGE_CONTAINED && | 531 NUMERIC_RANGE_CONTAINED && |
506 sizeof(T) >= (2 * sizeof(Lhs)) && | 532 sizeof(T) >= (2 * sizeof(Lhs)) && |
507 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 533 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
508 NUMERIC_RANGE_CONTAINED && | 534 NUMERIC_RANGE_CONTAINED && |
509 sizeof(T) >= (2 * sizeof(Rhs)); | 535 sizeof(T) >= (2 * sizeof(Rhs)); |
510 }; | 536 }; |
511 | 537 |
512 } // namespace internal | 538 } // namespace internal |
513 } // namespace base | 539 } // namespace base |
514 } // namespace pdfium | 540 } // namespace pdfium |
515 | 541 |
516 #endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ | 542 #endif // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
OLD | NEW |