Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
safe_conversions_impl.h
Go to the documentation of this file.
1// Copyright 2024 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CORE_FXCRT_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
6#define CORE_FXCRT_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
7
8#include <stdint.h>
9
10#include <limits>
11#include <type_traits>
12
13#if defined(__GNUC__) || defined(__clang__)
14#define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1)
15#define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0)
16#else
17#define BASE_NUMERICS_LIKELY(x) (x)
18#define BASE_NUMERICS_UNLIKELY(x) (x)
19#endif
20
21namespace pdfium {
22namespace internal {
23
24// The std library doesn't provide a binary max_exponent for integers, however
25// we can compute an analog using std::numeric_limits<>::digits.
26template <typename NumericType>
28 static const int value = std::is_floating_point<NumericType>::value
29 ? std::numeric_limits<NumericType>::max_exponent
30 : std::numeric_limits<NumericType>::digits + 1;
31};
32
33// The number of bits (including the sign) in an integer. Eliminates sizeof
34// hacks.
35template <typename NumericType>
37 static const int value = std::numeric_limits<NumericType>::digits +
38 std::is_signed<NumericType>::value;
39};
40
41// Helper templates for integer manipulations.
42
43template <typename Integer>
45 static const size_t value = IntegerBitsPlusSign<Integer>::value - 1;
46};
47
48// Determines if a numeric value is negative without throwing compiler
49// warnings on: unsigned(value) < 0.
50template <typename T,
51 typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
52constexpr bool IsValueNegative(T value) {
53 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
54 return value < 0;
55}
56
57template <typename T,
58 typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
59constexpr bool IsValueNegative(T) {
60 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
61 return false;
62}
63
64// This performs a fast negation, returning a signed value. It works on unsigned
65// arguments, but probably doesn't do what you want for any unsigned value
66// larger than max / 2 + 1 (i.e. signed min cast to unsigned).
67template <typename T>
68constexpr typename std::make_signed<T>::type ConditionalNegate(
69 T x,
70 bool is_negative) {
71 static_assert(std::is_integral<T>::value, "Type must be integral");
72 using SignedT = typename std::make_signed<T>::type;
73 using UnsignedT = typename std::make_unsigned<T>::type;
74 return static_cast<SignedT>((static_cast<UnsignedT>(x) ^
75 static_cast<UnsignedT>(-SignedT(is_negative))) +
76 is_negative);
77}
78
79// This performs a safe, absolute value via unsigned overflow.
80template <typename T>
81constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
82 static_assert(std::is_integral<T>::value, "Type must be integral");
83 using UnsignedT = typename std::make_unsigned<T>::type;
84 return IsValueNegative(value)
85 ? static_cast<UnsignedT>(0u - static_cast<UnsignedT>(value))
86 : static_cast<UnsignedT>(value);
87}
88
89// TODO(jschuh): Switch to std::is_constant_evaluated() once C++20 is supported.
90// Alternately, the usage could be restructured for "consteval if" in C++23.
91#define IsConstantEvaluated() (__builtin_is_constant_evaluated())
92
93// TODO(jschuh): Debug builds don't reliably propagate constants, so we restrict
94// some accelerated runtime paths to release builds until this can be forced
95// with consteval support in C++20 or C++23.
96#if defined(NDEBUG)
97constexpr bool kEnableAsmCode = true;
98#else
99constexpr bool kEnableAsmCode = false;
100#endif
101
102// Forces a crash, like a CHECK(false). Used for numeric boundary errors.
103// Also used in a constexpr template to trigger a compilation failure on
104// an error condition.
106 template <typename T>
107 static T HandleFailure() {
108#if defined(_MSC_VER)
109 __debugbreak();
110#elif defined(__GNUC__) || defined(__clang__)
111 __builtin_trap();
112#else
113 ((void)(*(volatile char*)0 = 0));
114#endif
115 return T();
116 }
117};
118
123
124// A range for a given nunmeric Src type is contained for a given numeric Dst
125// type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
126// numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true.
127// We implement this as template specializations rather than simple static
128// comparisons to ensure type correctness in our comparisons.
133
134// Helper templates to statically determine if our destination type can contain
135// maximum and minimum values represented by the source type.
136
137template <typename Dst,
138 typename Src,
139 IntegerRepresentation DstSign = std::is_signed<Dst>::value
142 IntegerRepresentation SrcSign = std::is_signed<Src>::value
146
147// Same sign: Dst is guaranteed to contain Src only if its range is equal or
148// larger.
149template <typename Dst, typename Src, IntegerRepresentation Sign>
150struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
152 MaxExponent<Dst>::value >= MaxExponent<Src>::value
155};
156
157// Unsigned to signed: Dst is guaranteed to contain source only if its range is
158// larger.
159template <typename Dst, typename Src>
169
170// Signed to unsigned: Dst cannot be statically determined to contain Src.
171template <typename Dst, typename Src>
178
179// This class wraps the range constraints as separate booleans so the compiler
180// can identify constants and eliminate unused code paths.
182 public:
183 constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
184 : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
185 constexpr RangeCheck() : is_underflow_(false), is_overflow_(false) {}
186 constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
187 constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
188 constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
189 constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; }
190 constexpr bool IsOverflowFlagSet() const { return is_overflow_; }
191 constexpr bool IsUnderflowFlagSet() const { return is_underflow_; }
192 constexpr bool operator==(const RangeCheck rhs) const {
193 return is_underflow_ == rhs.is_underflow_ &&
194 is_overflow_ == rhs.is_overflow_;
195 }
196 constexpr bool operator!=(const RangeCheck rhs) const {
197 return !(*this == rhs);
198 }
199
200 private:
201 // Do not change the order of these member variables. The integral conversion
202 // optimization depends on this exact order.
203 const bool is_underflow_;
204 const bool is_overflow_;
205};
206
207// The following helper template addresses a corner case in range checks for
208// conversion from a floating-point type to an integral type of smaller range
209// but larger precision (e.g. float -> unsigned). The problem is as follows:
210// 1. Integral maximum is always one less than a power of two, so it must be
211// truncated to fit the mantissa of the floating point. The direction of
212// rounding is implementation defined, but by default it's always IEEE
213// floats, which round to nearest and thus result in a value of larger
214// magnitude than the integral value.
215// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
216// // is 4294967295u.
217// 2. If the floating point value is equal to the promoted integral maximum
218// value, a range check will erroneously pass.
219// Example: (4294967296f <= 4294967295u) // This is true due to a precision
220// // loss in rounding up to float.
221// 3. When the floating point value is then converted to an integral, the
222// resulting value is out of range for the target integral type and
223// thus is implementation defined.
224// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
225// To fix this bug we manually truncate the maximum value when the destination
226// type is an integral of larger precision than the source floating-point type,
227// such that the resulting maximum is represented exactly as a floating point.
228template <typename Dst, typename Src, template <typename> class Bounds>
230 using SrcLimits = std::numeric_limits<Src>;
231 using DstLimits = typename std::numeric_limits<Dst>;
232
233 // Computes the mask required to make an accurate comparison between types.
234 static const int kShift =
235 (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
236 SrcLimits::digits < DstLimits::digits)
237 ? (DstLimits::digits - SrcLimits::digits)
238 : 0;
239 template <
240 typename T,
241 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
242
243 // Masks out the integer bits that are beyond the precision of the
244 // intermediate type used for comparison.
245 static constexpr T Adjust(T value) {
246 static_assert(std::is_same<T, Dst>::value, "");
247 static_assert(kShift < DstLimits::digits, "");
248 using UnsignedDst = typename std::make_unsigned_t<T>;
249 return static_cast<T>(ConditionalNegate(
250 SafeUnsignedAbs(value) & ~((UnsignedDst{1} << kShift) - UnsignedDst{1}),
251 IsValueNegative(value)));
252 }
253
254 template <typename T,
255 typename std::enable_if<std::is_floating_point<T>::value>::type* =
256 nullptr>
257 static constexpr T Adjust(T value) {
258 static_assert(std::is_same<T, Dst>::value, "");
259 static_assert(kShift == 0, "");
260 return value;
261 }
262
263 static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); }
264 static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); }
265};
266
267template <typename Dst,
268 typename Src,
269 template <typename>
270 class Bounds,
280
281// The following templates are for ranges that must be verified at runtime. We
282// split it into checks based on signedness to avoid confusing casts and
283// compiler warnings on signed an unsigned comparisons.
284
285// Same sign narrowing: The range is contained for normal limits.
286template <typename Dst,
287 typename Src,
288 template <typename>
289 class Bounds,
293 Src,
294 Bounds,
295 DstSign,
296 SrcSign,
298 static constexpr RangeCheck Check(Src value) {
301 return RangeCheck(
302 static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() ||
303 static_cast<Dst>(value) >= DstLimits::lowest(),
304 static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() ||
305 static_cast<Dst>(value) <= DstLimits::max());
306 }
307};
308
309// Signed to signed narrowing: Both the upper and lower boundaries may be
310// exceeded for standard limits.
311template <typename Dst, typename Src, template <typename> class Bounds>
323
324// Unsigned to unsigned narrowing: Only the upper bound can be exceeded for
325// standard limits.
326template <typename Dst, typename Src, template <typename> class Bounds>
340
341// Unsigned to signed: Only the upper bound can be exceeded for standard limits.
342template <typename Dst, typename Src, template <typename> class Bounds>
344 Src,
345 Bounds,
349 static constexpr RangeCheck Check(Src value) {
351 using Promotion = decltype(Src() + Dst());
352 return RangeCheck(DstLimits::lowest() <= Dst(0) ||
353 static_cast<Promotion>(value) >=
354 static_cast<Promotion>(DstLimits::lowest()),
355 static_cast<Promotion>(value) <=
356 static_cast<Promotion>(DstLimits::max()));
357 }
358};
359
360// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
361// and any negative value exceeds the lower boundary for standard limits.
362template <typename Dst, typename Src, template <typename> class Bounds>
364 Src,
365 Bounds,
369 static constexpr RangeCheck Check(Src value) {
372 using Promotion = decltype(Src() + Dst());
373 bool ge_zero = false;
374 // Converting floating-point to integer will discard fractional part, so
375 // values in (-1.0, -0.0) will truncate to 0 and fit in Dst.
377 ge_zero = value > Src(-1);
378 } else {
379 ge_zero = value >= Src(0);
380 }
381 return RangeCheck(
382 ge_zero && (DstLimits::lowest() == 0 ||
383 static_cast<Dst>(value) >= DstLimits::lowest()),
384 static_cast<Promotion>(SrcLimits::max()) <=
385 static_cast<Promotion>(DstLimits::max()) ||
386 static_cast<Promotion>(value) <=
387 static_cast<Promotion>(DstLimits::max()));
388 }
389};
390
391// Simple wrapper for statically checking if a type's range is contained.
392template <typename Dst, typename Src>
397
398template <typename Dst,
399 template <typename> class Bounds = std::numeric_limits,
400 typename Src>
402 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
403 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
404 static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), "");
405 return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value);
406}
407
408// Integer promotion templates used by the portable checked integer arithmetic.
409template <size_t Size, bool IsSigned>
411
412#define INTEGER_FOR_DIGITS_AND_SIGN(I)
413 template <>
414 struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value,
415 std::is_signed<I>::value> {
416 using type = I;
417 }
418
427#undef INTEGER_FOR_DIGITS_AND_SIGN
428
429// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
430// support 128-bit math, then the ArithmeticPromotion template below will need
431// to be updated (or more likely replaced with a decltype expression).
432static_assert(IntegerBitsPlusSign<intmax_t>::value == 64,
433 "Max integer size not supported for this toolchain.");
434
435template <typename Integer, bool IsSigned = std::is_signed<Integer>::value>
437 using type =
438 typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2,
439 IsSigned>::type;
440};
441
443 LEFT_PROMOTION, // Use the type of the left-hand argument.
444 RIGHT_PROMOTION // Use the type of the right-hand argument.
445};
446
447// Determines the type that can represent the largest positive value.
448template <typename Lhs,
449 typename Rhs,
451 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
455
456template <typename Lhs, typename Rhs>
458 using type = Lhs;
459};
460
461template <typename Lhs, typename Rhs>
463 using type = Rhs;
464};
465
466// Determines the type that can represent the lowest arithmetic value.
467template <typename Lhs,
468 typename Rhs,
470 std::is_signed<Lhs>::value
471 ? (std::is_signed<Rhs>::value
472 ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value
476 : (std::is_signed<Rhs>::value
478 : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value
480 : RIGHT_PROMOTION))>
482
483template <typename Lhs, typename Rhs>
485 using type = Lhs;
486};
487
488template <typename Lhs, typename Rhs>
490 using type = Rhs;
491};
492
493// Determines the type that is best able to represent an arithmetic result.
494template <
495 typename Lhs,
496 typename Rhs = Lhs,
497 bool is_intmax_type =
501 bool is_max_exponent =
503 typename MaxExponentPromotion<Lhs, Rhs>::type,
504 Lhs>::value ==
506 typename MaxExponentPromotion<Lhs, Rhs>::type,
509
510// The side with the max exponent is big enough.
511template <typename Lhs, typename Rhs, bool is_intmax_type>
512struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
513 using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
514 static const bool is_contained = true;
515};
516
517// We can use a twice wider type to fit.
518template <typename Lhs, typename Rhs>
519struct BigEnoughPromotion<Lhs, Rhs, false, false> {
520 using type =
522 std::is_signed<Lhs>::value ||
524 static const bool is_contained = true;
525};
526
527// No type is large enough.
528template <typename Lhs, typename Rhs>
529struct BigEnoughPromotion<Lhs, Rhs, true, false> {
530 using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
531 static const bool is_contained = false;
532};
533
534// We can statically check if operations on the provided types can wrap, so we
535// can skip the checked operations if they're not needed. So, for an integer we
536// care if the destination type preserves the sign and is twice the width of
537// the source.
538template <typename T, typename Lhs, typename Rhs = Lhs>
540 static const bool value =
541 !std::is_floating_point<T>::value &&
542 !std::is_floating_point<Lhs>::value &&
543 !std::is_floating_point<Rhs>::value &&
544 std::is_signed<T>::value >= std::is_signed<Lhs>::value &&
545 IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) &&
546 std::is_signed<T>::value >= std::is_signed<Rhs>::value &&
547 IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value);
548};
549
550// Promotes to a type that can represent any possible result of a binary
551// arithmetic operation with the source types.
552template <typename Lhs,
553 typename Rhs,
554 bool is_promotion_possible = IsIntegerArithmeticSafe<
555 typename std::conditional<std::is_signed<Lhs>::value ||
557 intmax_t,
558 uintmax_t>::type,
559 typename MaxExponentPromotion<Lhs, Rhs>::type>::value>
561
562template <typename Lhs, typename Rhs>
563struct FastIntegerArithmeticPromotion<Lhs, Rhs, true> {
564 using type =
566 std::is_signed<Lhs>::value ||
568 static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, "");
569 static const bool is_contained = true;
570};
571
572template <typename Lhs, typename Rhs>
573struct FastIntegerArithmeticPromotion<Lhs, Rhs, false> {
574 using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
575 static const bool is_contained = false;
576};
577
578// Extracts the underlying type from an enum.
579template <typename T, bool is_enum = std::is_enum<T>::value>
581
582template <typename T>
584 using type = typename std::underlying_type<T>::type;
585 static const bool value = std::is_arithmetic<type>::value;
586};
587
588template <typename T>
590 using type = T;
591 static const bool value = std::is_arithmetic<type>::value;
592};
593
594// The following are helper templates used in the CheckedNumeric class.
595template <typename T>
596class CheckedNumeric;
597
598template <typename T>
599class ClampedNumeric;
600
601template <typename T>
602class StrictNumeric;
603
604// Used to treat CheckedNumeric and arithmetic underlying types the same.
605template <typename T>
608 static const bool is_numeric = std::is_arithmetic<type>::value;
609 static const bool is_checked = false;
610 static const bool is_clamped = false;
611 static const bool is_strict = false;
612};
613
614template <typename T>
616 using type = T;
617 static const bool is_numeric = true;
618 static const bool is_checked = true;
619 static const bool is_clamped = false;
620 static const bool is_strict = false;
621};
622
623template <typename T>
625 using type = T;
626 static const bool is_numeric = true;
627 static const bool is_checked = false;
628 static const bool is_clamped = true;
629 static const bool is_strict = false;
630};
631
632template <typename T>
634 using type = T;
635 static const bool is_numeric = true;
636 static const bool is_checked = false;
637 static const bool is_clamped = false;
638 static const bool is_strict = true;
639};
640
641template <typename L, typename R>
643 static const bool value =
644 UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
645 (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
646};
647
648template <typename L, typename R>
650 static const bool value =
651 UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
652 (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped) &&
653 !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
654};
655
656template <typename L, typename R>
658 static const bool value =
659 UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
660 (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict) &&
661 !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked) &&
662 !(UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped);
663};
664
665// as_signed<> returns the supplied integral value (or integral castable
666// Numeric template) cast as a signed integral of equivalent precision.
667// I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t)
668template <typename Src>
669constexpr typename std::make_signed<
670 typename internal::UnderlyingType<Src>::type>::type
671as_signed(const Src value) {
672 static_assert(std::is_integral<decltype(as_signed(value))>::value,
673 "Argument must be a signed or unsigned integer type.");
674 return static_cast<decltype(as_signed(value))>(value);
675}
676
677// as_unsigned<> returns the supplied integral value (or integral castable
678// Numeric template) cast as an unsigned integral of equivalent precision.
679// I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t)
680template <typename Src>
681constexpr typename std::make_unsigned<
682 typename internal::UnderlyingType<Src>::type>::type
683as_unsigned(const Src value) {
684 static_assert(std::is_integral<decltype(as_unsigned(value))>::value,
685 "Argument must be a signed or unsigned integer type.");
686 return static_cast<decltype(as_unsigned(value))>(value);
687}
688
689template <typename L, typename R>
690constexpr bool IsLessImpl(const L lhs,
691 const R rhs,
692 const RangeCheck l_range,
693 const RangeCheck r_range) {
694 return l_range.IsUnderflow() || r_range.IsOverflow() ||
695 (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <
696 static_cast<decltype(lhs + rhs)>(rhs));
697}
698
699template <typename L, typename R>
700struct IsLess {
701 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
702 "Types must be numeric.");
703 static constexpr bool Test(const L lhs, const R rhs) {
704 return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
705 DstRangeRelationToSrcRange<L>(rhs));
706 }
707};
708
709template <typename L, typename R>
710constexpr bool IsLessOrEqualImpl(const L lhs,
711 const R rhs,
712 const RangeCheck l_range,
713 const RangeCheck r_range) {
714 return l_range.IsUnderflow() || r_range.IsOverflow() ||
715 (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <=
716 static_cast<decltype(lhs + rhs)>(rhs));
717}
718
719template <typename L, typename R>
721 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
722 "Types must be numeric.");
723 static constexpr bool Test(const L lhs, const R rhs) {
724 return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
725 DstRangeRelationToSrcRange<L>(rhs));
726 }
727};
728
729template <typename L, typename R>
730constexpr bool IsGreaterImpl(const L lhs,
731 const R rhs,
732 const RangeCheck l_range,
733 const RangeCheck r_range) {
734 return l_range.IsOverflow() || r_range.IsUnderflow() ||
735 (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >
736 static_cast<decltype(lhs + rhs)>(rhs));
737}
738
739template <typename L, typename R>
740struct IsGreater {
741 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
742 "Types must be numeric.");
743 static constexpr bool Test(const L lhs, const R rhs) {
744 return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
745 DstRangeRelationToSrcRange<L>(rhs));
746 }
747};
748
749template <typename L, typename R>
750constexpr bool IsGreaterOrEqualImpl(const L lhs,
751 const R rhs,
752 const RangeCheck l_range,
753 const RangeCheck r_range) {
754 return l_range.IsOverflow() || r_range.IsUnderflow() ||
755 (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >=
756 static_cast<decltype(lhs + rhs)>(rhs));
757}
758
759template <typename L, typename R>
761 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
762 "Types must be numeric.");
763 static constexpr bool Test(const L lhs, const R rhs) {
764 return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
765 DstRangeRelationToSrcRange<L>(rhs));
766 }
767};
768
769template <typename L, typename R>
770struct IsEqual {
771 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
772 "Types must be numeric.");
773 static constexpr bool Test(const L lhs, const R rhs) {
774 return DstRangeRelationToSrcRange<R>(lhs) ==
775 DstRangeRelationToSrcRange<L>(rhs) &&
776 static_cast<decltype(lhs + rhs)>(lhs) ==
777 static_cast<decltype(lhs + rhs)>(rhs);
778 }
779};
780
781template <typename L, typename R>
783 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
784 "Types must be numeric.");
785 static constexpr bool Test(const L lhs, const R rhs) {
786 return DstRangeRelationToSrcRange<R>(lhs) !=
787 DstRangeRelationToSrcRange<L>(rhs) ||
788 static_cast<decltype(lhs + rhs)>(lhs) !=
789 static_cast<decltype(lhs + rhs)>(rhs);
790 }
791};
792
793// These perform the actual math operations on the CheckedNumerics.
794// Binary arithmetic operations.
795template <template <typename, typename> class C, typename L, typename R>
796constexpr bool SafeCompare(const L lhs, const R rhs) {
797 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
798 "Types must be numeric.");
799 using Promotion = BigEnoughPromotion<L, R>;
800 using BigType = typename Promotion::type;
801 return Promotion::is_contained
802 // Force to a larger type for speed if both are contained.
803 ? C<BigType, BigType>::Test(
804 static_cast<BigType>(static_cast<L>(lhs)),
805 static_cast<BigType>(static_cast<R>(rhs)))
806 // Let the template functions figure it out for mixed types.
807 : C<L, R>::Test(lhs, rhs);
808}
809
810template <typename Dst, typename Src>
812 return IsGreaterOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::max(),
813 std::numeric_limits<Src>::max());
814}
815
816template <typename Dst, typename Src>
818 return IsLessOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::lowest(),
819 std::numeric_limits<Src>::lowest());
820}
821
822template <typename Dst, typename Src>
823constexpr Dst CommonMax() {
824 return !IsMaxInRangeForNumericType<Dst, Src>()
825 ? Dst(std::numeric_limits<Dst>::max())
826 : Dst(std::numeric_limits<Src>::max());
827}
828
829template <typename Dst, typename Src>
830constexpr Dst CommonMin() {
831 return !IsMinInRangeForNumericType<Dst, Src>()
832 ? Dst(std::numeric_limits<Dst>::lowest())
833 : Dst(std::numeric_limits<Src>::lowest());
834}
835
836// This is a wrapper to generate return the max or min for a supplied type.
837// If the argument is false, the returned value is the maximum. If true the
838// returned value is the minimum.
839template <typename Dst, typename Src = Dst>
840constexpr Dst CommonMaxOrMin(bool is_min) {
841 return is_min ? CommonMin<Dst, Src>() : CommonMax<Dst, Src>();
842}
843
844} // namespace internal
845} // namespace pdfium
846
847#endif // CORE_FXCRT_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
#define FXCRT_BYTESWAPS_CONSTEXPR
Definition byteorder.h:27
#define DCHECK
Definition check.h:33
#define CHECK_GE(x, y)
Definition check_op.h:15
constexpr bool operator==(const RangeCheck rhs) const
constexpr bool IsOverflowFlagSet() const
constexpr bool operator!=(const RangeCheck rhs) const
constexpr bool IsUnderflowFlagSet() const
constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
constexpr StrictNumeric(const StrictNumeric< Src > &rhs)
T & reference
Definition span.h:195
constexpr span(T(&array)[N]) noexcept
Definition span.h:211
constexpr reverse_iterator rend() const noexcept
Definition span.h:348
span last() const
Definition span.h:283
constexpr reverse_iterator rbegin() const noexcept
Definition span.h:345
T * iterator
Definition span.h:196
constexpr const_reverse_iterator crend() const noexcept
Definition span.h:355
span first() const
Definition span.h:269
std::reverse_iterator< iterator > reverse_iterator
Definition span.h:198
const span first(size_t count) const
Definition span.h:276
typename std::remove_cv< T >::type value_type
Definition span.h:193
span & operator=(const span &other) noexcept
Definition span.h:258
constexpr const_iterator cbegin() const noexcept
Definition span.h:342
constexpr const_iterator cend() const noexcept
Definition span.h:343
constexpr const_reverse_iterator crbegin() const noexcept
Definition span.h:352
const span last(size_t count) const
Definition span.h:290
constexpr bool empty() const noexcept
Definition span.h:316
constexpr size_t size() const noexcept
Definition span.h:314
constexpr span(Container &container)
Definition span.h:238
friend constexpr span< U > make_span(U *data, size_t size) noexcept
span subspan() const
Definition span.h:297
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition span.h:199
const span subspan(size_t pos, size_t count=dynamic_extent) const
Definition span.h:305
constexpr iterator begin() const noexcept
Definition span.h:337
constexpr size_t size_bytes() const noexcept
Definition span.h:315
constexpr span() noexcept=default
span(const Container &container)
Definition span.h:245
constexpr span(std::array< T, N > &array) noexcept
Definition span.h:216
T * pointer
Definition span.h:194
constexpr T & back() const noexcept
Definition span.h:329
constexpr span(const std::array< std::remove_cv_t< T >, N > &array) noexcept
Definition span.h:221
constexpr T * data() const noexcept
Definition span.h:334
constexpr T & front() const noexcept
Definition span.h:324
constexpr span(const span &other) noexcept=default
UNSAFE_BUFFER_USAGE constexpr span(T *data, size_t size) noexcept
Definition span.h:204
constexpr span(const span< U, M, R > &other)
Definition span.h:255
T & operator[](size_t index) const noexcept
Definition span.h:319
constexpr iterator end() const noexcept
Definition span.h:338
const T * const_iterator
Definition span.h:197
~span() noexcept=default
#define NOINLINE
#define UNSAFE_BUFFERS(...)
#define GSL_POINTER
#define TRIVIAL_ABI
#define UNLIKELY(x)
#define HAS_ATTRIBUTE(x)
#define UNSAFE_BUFFER_USAGE
void CRYPT_MD5Finish(CRYPT_md5_context *context, pdfium::span< uint8_t, 16 > digest)
Definition fx_crypt.cpp:203
#define P(a, b, c, d, k, s, t)
void CRYPT_MD5Generate(pdfium::span< const uint8_t > data, pdfium::span< uint8_t, 16 > digest)
Definition fx_crypt.cpp:219
#define S(x, n)
void CRYPT_ArcFourCryptBlock(pdfium::span< uint8_t > data, pdfium::span< const uint8_t > key)
Definition fx_crypt.cpp:157
void CRYPT_ArcFourSetup(CRYPT_rc4_context *context, pdfium::span< const uint8_t > key)
Definition fx_crypt.cpp:131
void CRYPT_MD5Update(CRYPT_md5_context *context, pdfium::span< const uint8_t > data)
Definition fx_crypt.cpp:175
void CRYPT_ArcFourCrypt(CRYPT_rc4_context *context, pdfium::span< uint8_t > data)
Definition fx_crypt.cpp:146
CRYPT_md5_context CRYPT_MD5Start()
Definition fx_crypt.cpp:164
void CRYPT_AESEncrypt(CRYPT_aes_context *ctx, pdfium::span< uint8_t > dest, pdfium::span< const uint8_t > src)
void CRYPT_AESSetIV(CRYPT_aes_context *ctx, const uint8_t *iv)
void CRYPT_AESDecrypt(CRYPT_aes_context *ctx, uint8_t *dest, const uint8_t *src, uint32_t size)
void CRYPT_AESSetKey(CRYPT_aes_context *ctx, const uint8_t *key, uint32_t keylen)
void CRYPT_SHA512Update(CRYPT_sha2_context *context, pdfium::span< const uint8_t > data)
void CRYPT_SHA384Update(CRYPT_sha2_context *context, pdfium::span< const uint8_t > data)
DataVector< uint8_t > CRYPT_SHA256Generate(pdfium::span< const uint8_t > data)
void CRYPT_SHA1Finish(CRYPT_sha1_context *context, pdfium::span< uint8_t, 20 > digest)
void CRYPT_SHA1Update(CRYPT_sha1_context *context, pdfium::span< const uint8_t > data)
void CRYPT_SHA512Finish(CRYPT_sha2_context *context, pdfium::span< uint8_t, 64 > digest)
DataVector< uint8_t > CRYPT_SHA384Generate(pdfium::span< const uint8_t > data)
void CRYPT_SHA384Start(CRYPT_sha2_context *context)
void CRYPT_SHA384Finish(CRYPT_sha2_context *context, pdfium::span< uint8_t, 48 > digest)
void CRYPT_SHA512Start(CRYPT_sha2_context *context)
DataVector< uint8_t > CRYPT_SHA1Generate(pdfium::span< const uint8_t > data)
void CRYPT_SHA256Start(CRYPT_sha2_context *context)
DataVector< uint8_t > CRYPT_SHA512Generate(pdfium::span< const uint8_t > data)
void CRYPT_SHA1Start(CRYPT_sha1_context *context)
void CRYPT_SHA256Finish(CRYPT_sha2_context *context, pdfium::span< uint8_t, 32 > digest)
void CRYPT_SHA256Update(CRYPT_sha2_context *context, pdfium::span< const uint8_t > data)
NOINLINE void FX_OutOfMemoryTerminate(size_t size)
Definition fx_memory.cpp:82
void * FX_AlignedAlloc(size_t size, size_t alignment)
void FXMEM_DefaultFree(void *pointer)
Definition fx_memory.cpp:78
void * FXMEM_DefaultAlloc(size_t byte_size)
Definition fx_memory.cpp:66
void * FXMEM_DefaultCalloc(size_t num_elems, size_t byte_size)
Definition fx_memory.cpp:70
void * FXMEM_DefaultRealloc(void *pointer, size_t new_size)
Definition fx_memory.cpp:74
void * FX_ArrayBufferAllocate(size_t length)
void FX_DestroyMemoryAllocators()
void FX_InitializeMemoryAllocators()
void FX_ArrayBufferFree(void *data)
void * FX_ArrayBufferAllocateUninitialized(size_t length)
#define IMMEDIATE_CRASH_ALWAYS_INLINE
#define TRAP_SEQUENCE_()
FXCRT_BYTESWAPS_CONSTEXPR uint16_t ByteSwap(uint16_t x)
Definition byteorder.h:32
FXCRT_BYTESWAPS_CONSTEXPR uint32_t ByteSwap(uint32_t x)
Definition byteorder.h:40
uint32_t FromBE32(uint32_t x)
Definition byteorder.h:82
constexpr std::array< U, N > ToArrayImpl(const T(&data)[N], std::index_sequence< I... >)
Definition stl_util.h:76
uint16_t GetUInt16LSBFirst(pdfium::span< const uint8_t, 2 > span)
Definition byteorder.h:101
void PutUInt32MSBFirst(uint32_t value, pdfium::span< uint8_t, 4 > span)
Definition byteorder.h:116
ResultType CollectionSize(const Collection &collection)
Definition stl_util.h:37
FakeUniquePtr< T > MakeFakeUniquePtr(T *arg)
Definition stl_util.h:30
void PutUInt16LSBFirst(uint16_t value, pdfium::span< uint8_t, 2 > span)
Definition byteorder.h:123
uint16_t FromBE16(uint16_t x)
Definition byteorder.h:74
void PutUInt32LSBFirst(uint32_t value, pdfium::span< uint8_t, 4 > span)
Definition byteorder.h:128
uint16_t GetUInt16MSBFirst(pdfium::span< const uint8_t, 2 > span)
Definition byteorder.h:91
constexpr std::array< U, N > ToArray(const U(&data)[N])
Definition stl_util.h:83
uint32_t GetUInt32MSBFirst(pdfium::span< const uint8_t, 4 > span)
Definition byteorder.h:95
bool IndexInBounds(const Collection &collection, IndexType index)
Definition stl_util.h:44
void PutUInt16MSBFirst(uint16_t value, pdfium::span< uint8_t, 2 > span)
Definition byteorder.h:111
void Copy(const T &source_container, U &&dest_container)
Definition stl_util.h:57
void Fill(T &&container, const V &value)
Definition stl_util.h:50
uint32_t FromLE32(uint32_t x)
Definition byteorder.h:64
uint32_t GetUInt32LSBFirst(pdfium::span< const uint8_t, 4 > span)
Definition byteorder.h:105
uint16_t FromLE16(uint16_t x)
Definition byteorder.h:56
void * CallocOrDie2D(size_t w, size_t h, size_t member_size)
void * AllocOrDie2D(size_t w, size_t h, size_t member_size)
constexpr Dst saturated_cast(Src value)
constexpr bool kEnableAsmCode
std::is_integral< decltype(std::declval< Container >().size())> ContainerHasIntegralSize
Definition span.h:63
void * StringAllocOrDie(size_t num_members, size_t member_size)
constexpr std::make_signed< typenameinternal::UnderlyingType< Src >::type >::type as_signed(const Src value)
constexpr bool IsMinInRangeForNumericType()
constexpr Dst CommonMax()
void * Alloc(size_t num_members, size_t member_size)
IsSpanImpl< typename std::decay< T >::type > IsSpan
Definition span.h:43
constexpr bool IsMaxInRangeForNumericType()
void * StringAlloc(size_t num_members, size_t member_size)
void * ReallocOrDie(void *ptr, size_t num_members, size_t member_size)
std::is_convertible< From *, To * > IsLegalSpanConversion
Definition span.h:55
constexpr bool IsValueNegative(T value)
constexpr bool SafeCompare(const L lhs, const R rhs)
void * Realloc(void *ptr, size_t num_members, size_t member_size)
IsStdArrayImpl< typename std::decay< T >::type > IsStdArray
Definition span.h:52
void StringDealloc(void *ptr)
constexpr bool IsGreaterImpl(const L lhs, const R rhs, const RangeCheck l_range, const RangeCheck r_range)
constexpr Dst CommonMin()
constexpr bool IsValueInRangeForNumericType(Src value)
constexpr Dst CommonMaxOrMin(bool is_min)
void * AllocOrDie(size_t num_members, size_t member_size)
constexpr RangeCheck DstRangeRelationToSrcRange(Src value)
constexpr Dst checked_cast(Src value)
void * Alloc2D(size_t w, size_t h, size_t member_size)
constexpr std::make_unsigned< T >::type SafeUnsignedAbs(T value)
void * Calloc(size_t num_members, size_t member_size)
constexpr Dst strict_cast(Src value)
constexpr bool IsLessOrEqualImpl(const L lhs, const R rhs, const RangeCheck l_range, const RangeCheck r_range)
constexpr StrictNumeric< typename UnderlyingType< T >::type > MakeStrictNum(const T value)
constexpr std::make_unsigned< typenameinternal::UnderlyingType< Src >::type >::type as_unsigned(const Src value)
constexpr std::make_signed< T >::type ConditionalNegate(T x, bool is_negative)
void * CallocOrDie(size_t num_members, size_t member_size)
void Dealloc(void *ptr)
constexpr bool IsGreaterOrEqualImpl(const L lhs, const R rhs, const RangeCheck l_range, const RangeCheck r_range)
constexpr bool IsLessImpl(const L lhs, const R rhs, const RangeCheck l_range, const RangeCheck r_range)
constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint)
constexpr span< T > make_span(T(&array)[N]) noexcept
Definition span.h:374
span< char > as_writable_chars(span< T, N, P > s) noexcept
Definition span.h:427
span< const uint8_t > as_bytes(span< T, N, P > s) noexcept
Definition span.h:400
constexpr size_t dynamic_extent
Definition span.h:24
static constexpr span< T > span_from_ref(T &single_object) noexcept
Definition span.h:437
static constexpr span< const uint8_t > byte_span_from_ref(const T &single_object) noexcept
Definition span.h:446
Dst ClampRound(Src value)
UNSAFE_BUFFER_USAGE constexpr span< T > make_span(T *data, size_t size) noexcept
Definition span.h:369
span< const uint8_t > as_byte_span(T &&arg)
Definition span.h:465
span< const char > as_chars(span< T, N, P > s) noexcept
Definition span.h:417
span< const uint8_t > as_byte_span(const T &arg)
Definition span.h:461
UNOWNED_PTR_EXCLUSION T * DefaultSpanInternalPtr
Definition span.h:27
span< uint8_t > as_writable_bytes(span< T, N, P > s) noexcept
Definition span.h:410
constexpr span< T > make_span(std::array< T, N > &array) noexcept
Definition span.h:379
constexpr span< T > make_span(Container &container)
Definition span.h:386
constexpr span< uint8_t > as_writable_byte_span(T &&arg)
Definition span.h:475
Dst ClampCeil(Src value)
IMMEDIATE_CRASH_ALWAYS_INLINE void ImmediateCrash()
static constexpr span< uint8_t > byte_span_from_ref(T &single_object) noexcept
Definition span.h:451
Dst ClampFloor(Src value)
constexpr span< T > make_span(const Container &container)
Definition span.h:394
#define CHECK(cvref)
#define assert
#define __has_attribute(x)
#define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
#define BASE_NUMERIC_COMPARISON_OPERATORS(CLASS, NAME, OP)
#define INTEGER_FOR_DIGITS_AND_SIGN(I)
#define BASE_NUMERICS_LIKELY(x)
#define IsConstantEvaluated()
std::array< uint32_t, kMaxNb > iv
std::array< uint32_t, kSchedSize > invkeysched
static constexpr int kMaxNr
static constexpr int kSchedSize
static constexpr int kMaxNb
std::array< uint32_t, kSchedSize > keysched
uint8_t buffer[64]
Definition fx_crypt.h:28
std::array< uint32_t, 4 > state
Definition fx_crypt.h:27
std::array< uint32_t, 2 > total
Definition fx_crypt.h:26
std::array< int32_t, kPermutationLength > m
Definition fx_crypt.h:22
static constexpr int32_t kPermutationLength
Definition fx_crypt.h:18
std::array< uint32_t, 5 > h
std::array< uint8_t, 64 > block
std::array< uint64_t, 8 > state
uint8_t buffer[128]
void operator()(void *ptr) const
FxPartitionAllocAllocator< U, Alloc, Free > other
pointer allocate(size_type n, const void *hint=0)
void deallocate(pointer p, size_type n)
const_pointer address(const_reference x) const noexcept
FxPartitionAllocAllocator() noexcept=default
size_type max_size() const noexcept
~FxPartitionAllocAllocator()=default
pointer address(reference x) const noexcept
FxPartitionAllocAllocator(const FxPartitionAllocAllocator< U, Alloc, Free > &other) noexcept
bool operator!=(const FxPartitionAllocAllocator &that)
void construct(U *p, Args &&... args)
bool operator==(const FxPartitionAllocAllocator &that)
FxPartitionAllocAllocator(const FxPartitionAllocAllocator &other) noexcept=default
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Do(Src value)
static constexpr T Adjust(T value)
std::numeric_limits< Src > SrcLimits
typename std::numeric_limits< Dst > DstLimits
static constexpr Dst Do(Src value)
typename IntegerForDigitsAndSign< IntegerBitsPlusSign< Integer >::value *2, IsSigned >::type type
#define UNOWNED_PTR_EXCLUSION