1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /* Provides checked integers, detecting integer overflow and divide-by-0. */
8 // Necessary modifications are made to the original CheckedInt.h file when
9 // incorporating it into WebKit:
10 // 1) Comment out #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
11 // 2) Comment out #include "mozilla/StandardInteger.h"
12 // 3) Define MOZ_DELETE
13 // 4) Change namespace mozilla to namespace blink
15 #ifndef mozilla_CheckedInt_h_
16 #define mozilla_CheckedInt_h_
19 * Build options. Comment out these #defines to disable the corresponding
20 * optional feature. Disabling features may be useful for code using
21 * CheckedInt outside of Mozilla (e.g. WebKit)
24 // Enable usage of MOZ_STATIC_ASSERT to check for unsupported types.
25 // If disabled, static asserts are replaced by regular assert().
26 // #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
29 * End of build options
32 #ifdef MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
33 # include "mozilla/Assertions.h"
35 # ifndef MOZ_STATIC_ASSERT
37 # define MOZ_STATIC_ASSERT(cond, reason) assert((cond) && reason)
38 # define MOZ_ASSERT(cond, reason) assert((cond) && reason)
42 // #include "mozilla/StandardInteger.h"
55 * Step 1: manually record supported types
57 * What's nontrivial here is that there are different families of integer
58 * types: basic integer types and stdint types. It is merrily undefined which
59 * types from one family may be just typedefs for a type from another family.
61 * For example, on GCC 4.6, aside from the basic integer types, the only other
62 * type that isn't just a typedef for some of them, is int8_t.
65 struct UnsupportedType
{};
67 template<typename IntegerType
>
68 struct IsSupportedPass2
70 static const bool value
= false;
73 template<typename IntegerType
>
76 static const bool value
= IsSupportedPass2
<IntegerType
>::value
;
80 struct IsSupported
<int8_t>
81 { static const bool value
= true; };
84 struct IsSupported
<uint8_t>
85 { static const bool value
= true; };
88 struct IsSupported
<int16_t>
89 { static const bool value
= true; };
92 struct IsSupported
<uint16_t>
93 { static const bool value
= true; };
96 struct IsSupported
<int32_t>
97 { static const bool value
= true; };
100 struct IsSupported
<uint32_t>
101 { static const bool value
= true; };
104 struct IsSupported
<int64_t>
105 { static const bool value
= true; };
108 struct IsSupported
<uint64_t>
109 { static const bool value
= true; };
113 struct IsSupportedPass2
<char>
114 { static const bool value
= true; };
117 struct IsSupportedPass2
<unsigned char>
118 { static const bool value
= true; };
121 struct IsSupportedPass2
<short>
122 { static const bool value
= true; };
125 struct IsSupportedPass2
<unsigned short>
126 { static const bool value
= true; };
129 struct IsSupportedPass2
<int>
130 { static const bool value
= true; };
133 struct IsSupportedPass2
<unsigned>
134 { static const bool value
= true; };
137 struct IsSupportedPass2
<long>
138 { static const bool value
= true; };
141 struct IsSupportedPass2
<unsigned long>
142 { static const bool value
= true; };
146 * Step 2: some integer-traits kind of stuff.
149 template<size_t Size
, bool Signedness
>
150 struct StdintTypeForSizeAndSignedness
154 struct StdintTypeForSizeAndSignedness
<1, true>
155 { typedef int8_t Type
; };
158 struct StdintTypeForSizeAndSignedness
<1, false>
159 { typedef uint8_t Type
; };
162 struct StdintTypeForSizeAndSignedness
<2, true>
163 { typedef int16_t Type
; };
166 struct StdintTypeForSizeAndSignedness
<2, false>
167 { typedef uint16_t Type
; };
170 struct StdintTypeForSizeAndSignedness
<4, true>
171 { typedef int32_t Type
; };
174 struct StdintTypeForSizeAndSignedness
<4, false>
175 { typedef uint32_t Type
; };
178 struct StdintTypeForSizeAndSignedness
<8, true>
179 { typedef int64_t Type
; };
182 struct StdintTypeForSizeAndSignedness
<8, false>
183 { typedef uint64_t Type
; };
185 template<typename IntegerType
>
188 typedef typename StdintTypeForSizeAndSignedness
<sizeof(IntegerType
),
192 template<typename IntegerType
>
195 static const bool value
= IntegerType(-1) <= IntegerType(0);
198 template<typename IntegerType
, size_t Size
= sizeof(IntegerType
)>
199 struct TwiceBiggerType
201 typedef typename StdintTypeForSizeAndSignedness
<
202 sizeof(IntegerType
) * 2,
203 IsSigned
<IntegerType
>::value
207 template<typename IntegerType
>
208 struct TwiceBiggerType
<IntegerType
, 8>
210 typedef UnsupportedType Type
;
213 template<typename IntegerType
>
214 struct PositionOfSignBit
216 static const size_t value
= CHAR_BIT
* sizeof(IntegerType
) - 1;
219 template<typename IntegerType
>
223 typedef typename UnsignedType
<IntegerType
>::Type UnsignedIntegerType
;
224 static const size_t PosOfSignBit
= PositionOfSignBit
<IntegerType
>::value
;
227 // Bitwise ops may return a larger type, that's why we cast explicitly.
228 // In C++, left bit shifts on signed values is undefined by the standard
229 // unless the shifted value is representable.
230 // Notice that signed-to-unsigned conversions are always well-defined in
231 // the standard as the value congruent to 2**n, as expected. By contrast,
232 // unsigned-to-signed is only well-defined if the value is representable.
233 static const IntegerType value
=
234 IsSigned
<IntegerType
>::value
235 ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit
)
239 template<typename IntegerType
>
242 // Tricksy, but covered by the unit test.
243 // Relies heavily on the type of MinValue<IntegerType>::value
244 // being IntegerType.
245 static const IntegerType value
= ~MinValue
<IntegerType
>::value
;
249 * Step 3: Implement the actual validity checks.
251 * Ideas taken from IntegerLib, code different.
258 // In C++, right bit shifts on negative values is undefined by the standard.
259 // Notice that signed-to-unsigned conversions are always well-defined in the
260 // standard, as the value congruent modulo 2**n as expected. By contrast,
261 // unsigned-to-signed is only well-defined if the value is representable.
262 return bool(typename UnsignedType
<T
>::Type(x
)
263 >> PositionOfSignBit
<T
>::value
);
266 // Bitwise ops may return a larger type, so it's good to use this inline
267 // helper guaranteeing that the result is really of type T.
270 BinaryComplement(T x
)
277 bool IsTSigned
= IsSigned
<T
>::value
,
278 bool IsUSigned
= IsSigned
<U
>::value
>
279 struct DoesRangeContainRange
283 template<typename T
, typename U
, bool Signedness
>
284 struct DoesRangeContainRange
<T
, U
, Signedness
, Signedness
>
286 static const bool value
= sizeof(T
) >= sizeof(U
);
289 template<typename T
, typename U
>
290 struct DoesRangeContainRange
<T
, U
, true, false>
292 static const bool value
= sizeof(T
) > sizeof(U
);
295 template<typename T
, typename U
>
296 struct DoesRangeContainRange
<T
, U
, false, true>
298 static const bool value
= false;
303 bool IsTSigned
= IsSigned
<T
>::value
,
304 bool IsUSigned
= IsSigned
<U
>::value
,
305 bool DoesTRangeContainURange
= DoesRangeContainRange
<T
, U
>::value
>
306 struct IsInRangeImpl
{};
308 template<typename T
, typename U
, bool IsTSigned
, bool IsUSigned
>
309 struct IsInRangeImpl
<T
, U
, IsTSigned
, IsUSigned
, true>
317 template<typename T
, typename U
>
318 struct IsInRangeImpl
<T
, U
, true, true, false>
322 return x
<= MaxValue
<T
>::value
&& x
>= MinValue
<T
>::value
;
326 template<typename T
, typename U
>
327 struct IsInRangeImpl
<T
, U
, false, false, false>
331 return x
<= MaxValue
<T
>::value
;
335 template<typename T
, typename U
>
336 struct IsInRangeImpl
<T
, U
, true, false, false>
340 return sizeof(T
) > sizeof(U
) || x
<= U(MaxValue
<T
>::value
);
344 template<typename T
, typename U
>
345 struct IsInRangeImpl
<T
, U
, false, true, false>
349 return sizeof(T
) >= sizeof(U
)
351 : x
>= 0 && x
<= U(MaxValue
<T
>::value
);
355 template<typename T
, typename U
>
359 return IsInRangeImpl
<T
, U
>::run(x
);
366 // Addition is valid if the sign of x+y is equal to either that of x or that
367 // of y. Since the value of x+y is undefined if we have a signed type, we
368 // compute it using the unsigned type of the same size.
369 // Beware! These bitwise operations can return a larger integer type,
370 // if T was a small type like int8_t, so we explicitly cast to T.
372 typename UnsignedType
<T
>::Type ux
= x
;
373 typename UnsignedType
<T
>::Type uy
= y
;
374 typename UnsignedType
<T
>::Type result
= ux
+ uy
;
375 return IsSigned
<T
>::value
376 ? HasSignBit(BinaryComplement(T((result
^ x
) & (result
^ y
))))
377 : BinaryComplement(x
) >= y
;
384 // Subtraction is valid if either x and y have same sign, or x-y and x have
385 // same sign. Since the value of x-y is undefined if we have a signed type,
386 // we compute it using the unsigned type of the same size.
387 typename UnsignedType
<T
>::Type ux
= x
;
388 typename UnsignedType
<T
>::Type uy
= y
;
389 typename UnsignedType
<T
>::Type result
= ux
- uy
;
391 return IsSigned
<T
>::value
392 ? HasSignBit(BinaryComplement(T((result
^ x
) & (x
^ y
))))
397 bool IsSigned
= IsSigned
<T
>::value
,
398 bool TwiceBiggerTypeIsSupported
=
399 IsSupported
<typename TwiceBiggerType
<T
>::Type
>::value
>
400 struct IsMulValidImpl
{};
402 template<typename T
, bool IsSigned
>
403 struct IsMulValidImpl
<T
, IsSigned
, true>
405 static bool run(T x
, T y
)
407 typedef typename TwiceBiggerType
<T
>::Type TwiceBiggerType
;
408 TwiceBiggerType product
= TwiceBiggerType(x
) * TwiceBiggerType(y
);
409 return IsInRange
<T
>(product
);
414 struct IsMulValidImpl
<T
, true, false>
416 static bool run(T x
, T y
)
418 const T max
= MaxValue
<T
>::value
;
419 const T min
= MinValue
<T
>::value
;
421 if (x
== 0 || y
== 0)
430 // If we reach this point, we know that x < 0.
438 struct IsMulValidImpl
<T
, false, false>
440 static bool run(T x
, T y
)
442 return y
== 0 || x
<= MaxValue
<T
>::value
/ y
;
450 return IsMulValidImpl
<T
>::run(x
, y
);
457 // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
459 !(IsSigned
<T
>::value
&& x
== MinValue
<T
>::value
&& y
== T(-1));
462 // This is just to shut up msvc warnings about negating unsigned ints.
463 template<typename T
, bool IsSigned
= IsSigned
<T
>::value
>
464 struct OppositeIfSignedImpl
466 static T
run(T x
) { return -x
; }
469 struct OppositeIfSignedImpl
<T
, false>
471 static T
run(T x
) { return x
; }
475 OppositeIfSigned(T x
)
477 return OppositeIfSignedImpl
<T
>::run(x
);
480 } // namespace detail
484 * Step 4: Now define the CheckedInt class.
489 * @brief Integer wrapper class checking for integer overflow and other errors
490 * @param T the integer type to wrap. Can be any type among the following:
491 * - any basic integer type such as |int|
492 * - any stdint type such as |int8_t|
494 * This class implements guarded integer arithmetic. Do a computation, check
495 * that isValid() returns true, you then have a guarantee that no problem, such
496 * as integer overflow, happened during this computation, and you can call
497 * value() to get the plain integer value.
499 * The arithmetic operators in this class are guaranteed not to raise a signal
500 * (e.g. in case of a division by zero).
502 * For example, suppose that you want to implement a function that computes
503 * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by
504 * zero or integer overflow). You could code it as follows:
506 bool computeXPlusYOverZ(int x, int y, int z, int *result)
508 CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z;
509 if (checkedResult.isValid()) {
510 *result = checkedResult.value();
518 * Implicit conversion from plain integers to checked integers is allowed. The
519 * plain integer is checked to be in range before being casted to the
520 * destination type. This means that the following lines all compile, and the
521 * resulting CheckedInts are correctly detected as valid or invalid:
523 // 1 is of type int, is found to be in range for uint8_t, x is valid
524 CheckedInt<uint8_t> x(1);
525 // -1 is of type int, is found not to be in range for uint8_t, x is invalid
526 CheckedInt<uint8_t> x(-1);
527 // -1 is of type int, is found to be in range for int8_t, x is valid
528 CheckedInt<int8_t> x(-1);
529 // 1000 is of type int16_t, is found not to be in range for int8_t,
531 CheckedInt<int8_t> x(int16_t(1000));
532 // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
534 CheckedInt<int32_t> x(uint32_t(3123456789));
536 * Implicit conversion from
537 * checked integers to plain integers is not allowed. As shown in the
538 * above example, to get the value of a checked integer as a normal integer,
541 * Arithmetic operations between checked and plain integers is allowed; the
542 * result type is the type of the checked integer.
544 * Checked integers of different types cannot be used in the same arithmetic
547 * There are convenience typedefs for all stdint types, of the following form
548 * (these are just 2 examples):
550 typedef CheckedInt<int32_t> CheckedInt32;
551 typedef CheckedInt<uint16_t> CheckedUint16;
562 CheckedInt(U value
, bool isValid
) : mValue(value
), mIsValid(isValid
)
564 MOZ_STATIC_ASSERT(detail::IsSupported
<T
>::value
,
565 "This type is not supported by CheckedInt");
570 * Constructs a checked integer with given @a value. The checked integer is
571 * initialized as valid or invalid depending on whether the @a value
574 * This constructor is not explicit. Instead, the type of its argument is a
575 * separate template parameter, ensuring that no conversion is performed
576 * before this constructor is actually called. As explained in the above
577 * documentation for class CheckedInt, this constructor checks that its
583 mIsValid(detail::IsInRange
<T
>(value
))
585 MOZ_STATIC_ASSERT(detail::IsSupported
<T
>::value
,
586 "This type is not supported by CheckedInt");
589 /** Constructs a valid checked integer with initial value 0 */
590 CheckedInt() : mValue(0), mIsValid(true)
592 MOZ_STATIC_ASSERT(detail::IsSupported
<T
>::value
,
593 "This type is not supported by CheckedInt");
596 /** @returns the actual value */
599 MOZ_ASSERT(mIsValid
, "Invalid checked integer (division by zero or integer overflow)");
604 * @returns true if the checked integer is valid, i.e. is not the result
605 * of an invalid operation or of an operation involving an invalid checked
614 friend CheckedInt
<U
> operator +(const CheckedInt
<U
>& lhs
,
615 const CheckedInt
<U
>& rhs
);
617 CheckedInt
& operator +=(U rhs
);
619 friend CheckedInt
<U
> operator -(const CheckedInt
<U
>& lhs
,
620 const CheckedInt
<U
> &rhs
);
622 CheckedInt
& operator -=(U rhs
);
624 friend CheckedInt
<U
> operator *(const CheckedInt
<U
>& lhs
,
625 const CheckedInt
<U
> &rhs
);
627 CheckedInt
& operator *=(U rhs
);
629 friend CheckedInt
<U
> operator /(const CheckedInt
<U
>& lhs
,
630 const CheckedInt
<U
> &rhs
);
632 CheckedInt
& operator /=(U rhs
);
634 CheckedInt
operator -() const
636 // Circumvent msvc warning about - applied to unsigned int.
637 // if we're unsigned, the only valid case anyway is 0
638 // in which case - is a no-op.
639 T result
= detail::OppositeIfSigned(mValue
);
640 /* Help the compiler perform RVO (return value optimization). */
641 return CheckedInt(result
,
642 mIsValid
&& detail::IsSubValid(T(0),
647 * @returns true if the left and right hand sides are valid
648 * and have the same value.
650 * Note that these semantics are the reason why we don't offer
651 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
652 * but that would mean that whenever a or b is invalid, a!=b
653 * is always true, which would be very confusing.
655 * For similar reasons, operators <, >, <=, >= would be very tricky to
656 * specify, so we just avoid offering them.
658 * Notice that these == semantics are made more reasonable by these facts:
659 * 1. a==b implies equality at the raw data level
660 * (the converse is false, as a==b is never true among invalids)
661 * 2. This is similar to the behavior of IEEE floats, where a==b
662 * means that a and b have the same value *and* neither is NaN.
664 bool operator ==(const CheckedInt
& other
) const
666 return mIsValid
&& other
.mIsValid
&& mValue
== other
.mValue
;
670 CheckedInt
& operator++()
677 CheckedInt
operator++(int)
679 CheckedInt tmp
= *this;
685 CheckedInt
& operator--()
692 CheckedInt
operator--(int)
694 CheckedInt tmp
= *this;
701 * The !=, <, <=, >, >= operators are disabled:
702 * see the comment on operator==.
705 bool operator !=(U other
) const MOZ_DELETE
;
707 bool operator <(U other
) const MOZ_DELETE
;
709 bool operator <=(U other
) const MOZ_DELETE
;
711 bool operator >(U other
) const MOZ_DELETE
;
713 bool operator >=(U other
) const MOZ_DELETE
;
716 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
717 template<typename T> \
718 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \
719 const CheckedInt<T> &rhs) \
721 if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \
722 return CheckedInt<T>(0, false); \
724 return CheckedInt<T>(lhs.mValue OP rhs.mValue, \
725 lhs.mIsValid && rhs.mIsValid); \
728 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add
, +)
729 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub
, -)
730 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul
, *)
731 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div
, /)
733 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
735 // Implement castToCheckedInt<T>(x), making sure that
736 // - it allows x to be either a CheckedInt<T> or any integer type
737 // that can be casted to T
738 // - if x is already a CheckedInt<T>, we just return a reference to it,
739 // instead of copying it (optimization)
743 template<typename T
, typename U
>
744 struct CastToCheckedIntImpl
746 typedef CheckedInt
<T
> ReturnType
;
747 static CheckedInt
<T
> run(U u
) { return u
; }
751 struct CastToCheckedIntImpl
<T
, CheckedInt
<T
>>
753 typedef const CheckedInt
<T
>& ReturnType
;
754 static const CheckedInt
<T
>& run(const CheckedInt
<T
>& u
) { return u
; }
757 } // namespace detail
759 template<typename T
, typename U
>
760 inline typename
detail::CastToCheckedIntImpl
<T
, U
>::ReturnType
761 castToCheckedInt(U u
)
763 return detail::CastToCheckedIntImpl
<T
, U
>::run(u
);
766 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
767 template<typename T> \
768 template<typename U> \
769 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \
771 *this = *this OP castToCheckedInt<T>(rhs); \
774 template<typename T, typename U> \
775 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
777 return lhs OP castToCheckedInt<T>(rhs); \
779 template<typename T, typename U> \
780 inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
782 return castToCheckedInt<T>(lhs) OP rhs; \
785 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
786 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
787 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
788 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
790 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
792 template<typename T
, typename U
>
794 operator ==(const CheckedInt
<T
> &lhs
, U rhs
)
796 return lhs
== castToCheckedInt
<T
>(rhs
);
799 template<typename T
, typename U
>
801 operator ==(U lhs
, const CheckedInt
<T
> &rhs
)
803 return castToCheckedInt
<T
>(lhs
) == rhs
;
806 // Convenience typedefs.
807 typedef CheckedInt
<int8_t> CheckedInt8
;
808 typedef CheckedInt
<uint8_t> CheckedUint8
;
809 typedef CheckedInt
<int16_t> CheckedInt16
;
810 typedef CheckedInt
<uint16_t> CheckedUint16
;
811 typedef CheckedInt
<int32_t> CheckedInt32
;
812 typedef CheckedInt
<uint32_t> CheckedUint32
;
813 typedef CheckedInt
<int64_t> CheckedInt64
;
814 typedef CheckedInt
<uint64_t> CheckedUint64
;
818 #endif /* mozilla_CheckedInt_h_ */