Bug 835381 - Unit tests for the MediaSniffer to make sure Matroska files are not...
[gecko.git] / mfbt / CheckedInt.h
blobb56ac42b19c0ff8b80aa3cabeba8de3b4e42900e
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 #ifndef mozilla_CheckedInt_h_
9 #define mozilla_CheckedInt_h_
12 * Build options. Comment out these #defines to disable the corresponding
13 * optional feature. Disabling features may be useful for code using
14 * CheckedInt outside of Mozilla (e.g. WebKit)
17 // Enable usage of MOZ_STATIC_ASSERT to check for unsupported types.
18 // If disabled, static asserts are replaced by regular assert().
19 #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
22 * End of build options
26 #ifdef MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
27 # include "mozilla/Assertions.h"
28 #else
29 # ifndef MOZ_STATIC_ASSERT
30 # include <cassert>
31 # define MOZ_STATIC_ASSERT(cond, reason) assert((cond) && reason)
32 # define MOZ_ASSERT(cond, reason) assert((cond) && reason)
33 # endif
34 #endif
36 #include "mozilla/StandardInteger.h"
38 #include <climits>
39 #include <cstddef>
41 namespace mozilla {
43 namespace detail {
46 * Step 1: manually record supported types
48 * What's nontrivial here is that there are different families of integer
49 * types: basic integer types and stdint types. It is merrily undefined which
50 * types from one family may be just typedefs for a type from another family.
52 * For example, on GCC 4.6, aside from the basic integer types, the only other
53 * type that isn't just a typedef for some of them, is int8_t.
56 struct UnsupportedType {};
58 template<typename IntegerType>
59 struct IsSupportedPass2
61 static const bool value = false;
64 template<typename IntegerType>
65 struct IsSupported
67 static const bool value = IsSupportedPass2<IntegerType>::value;
70 template<>
71 struct IsSupported<int8_t>
72 { static const bool value = true; };
74 template<>
75 struct IsSupported<uint8_t>
76 { static const bool value = true; };
78 template<>
79 struct IsSupported<int16_t>
80 { static const bool value = true; };
82 template<>
83 struct IsSupported<uint16_t>
84 { static const bool value = true; };
86 template<>
87 struct IsSupported<int32_t>
88 { static const bool value = true; };
90 template<>
91 struct IsSupported<uint32_t>
92 { static const bool value = true; };
94 template<>
95 struct IsSupported<int64_t>
96 { static const bool value = true; };
98 template<>
99 struct IsSupported<uint64_t>
100 { static const bool value = true; };
103 template<>
104 struct IsSupportedPass2<char>
105 { static const bool value = true; };
107 template<>
108 struct IsSupportedPass2<unsigned char>
109 { static const bool value = true; };
111 template<>
112 struct IsSupportedPass2<short>
113 { static const bool value = true; };
115 template<>
116 struct IsSupportedPass2<unsigned short>
117 { static const bool value = true; };
119 template<>
120 struct IsSupportedPass2<int>
121 { static const bool value = true; };
123 template<>
124 struct IsSupportedPass2<unsigned int>
125 { static const bool value = true; };
127 template<>
128 struct IsSupportedPass2<long>
129 { static const bool value = true; };
131 template<>
132 struct IsSupportedPass2<unsigned long>
133 { static const bool value = true; };
137 * Step 2: some integer-traits kind of stuff.
140 template<size_t Size, bool Signedness>
141 struct StdintTypeForSizeAndSignedness
144 template<>
145 struct StdintTypeForSizeAndSignedness<1, true>
146 { typedef int8_t Type; };
148 template<>
149 struct StdintTypeForSizeAndSignedness<1, false>
150 { typedef uint8_t Type; };
152 template<>
153 struct StdintTypeForSizeAndSignedness<2, true>
154 { typedef int16_t Type; };
156 template<>
157 struct StdintTypeForSizeAndSignedness<2, false>
158 { typedef uint16_t Type; };
160 template<>
161 struct StdintTypeForSizeAndSignedness<4, true>
162 { typedef int32_t Type; };
164 template<>
165 struct StdintTypeForSizeAndSignedness<4, false>
166 { typedef uint32_t Type; };
168 template<>
169 struct StdintTypeForSizeAndSignedness<8, true>
170 { typedef int64_t Type; };
172 template<>
173 struct StdintTypeForSizeAndSignedness<8, false>
174 { typedef uint64_t Type; };
176 template<typename IntegerType>
177 struct UnsignedType
179 typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType),
180 false>::Type Type;
183 template<typename IntegerType>
184 struct IsSigned
186 static const bool value = IntegerType(-1) <= IntegerType(0);
189 template<typename IntegerType, size_t Size = sizeof(IntegerType)>
190 struct TwiceBiggerType
192 typedef typename StdintTypeForSizeAndSignedness<
193 sizeof(IntegerType) * 2,
194 IsSigned<IntegerType>::value
195 >::Type Type;
198 template<typename IntegerType>
199 struct TwiceBiggerType<IntegerType, 8>
201 typedef UnsupportedType Type;
204 template<typename IntegerType>
205 struct PositionOfSignBit
207 static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1;
210 template<typename IntegerType>
211 struct MinValue
213 private:
214 typedef typename UnsignedType<IntegerType>::Type UnsignedIntegerType;
215 static const size_t PosOfSignBit = PositionOfSignBit<IntegerType>::value;
217 public:
218 // Bitwise ops may return a larger type, that's why we cast explicitly.
219 // In C++, left bit shifts on signed values is undefined by the standard
220 // unless the shifted value is representable.
221 // Notice that signed-to-unsigned conversions are always well-defined in
222 // the standard as the value congruent to 2**n, as expected. By contrast,
223 // unsigned-to-signed is only well-defined if the value is representable.
224 static const IntegerType value =
225 IsSigned<IntegerType>::value
226 ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit)
227 : IntegerType(0);
230 template<typename IntegerType>
231 struct MaxValue
233 // Tricksy, but covered by the unit test.
234 // Relies heavily on the type of MinValue<IntegerType>::value
235 // being IntegerType.
236 static const IntegerType value = ~MinValue<IntegerType>::value;
240 * Step 3: Implement the actual validity checks.
242 * Ideas taken from IntegerLib, code different.
245 template<typename T>
246 inline bool
247 HasSignBit(T x)
249 // In C++, right bit shifts on negative values is undefined by the standard.
250 // Notice that signed-to-unsigned conversions are always well-defined in the
251 // standard, as the value congruent modulo 2**n as expected. By contrast,
252 // unsigned-to-signed is only well-defined if the value is representable.
253 return bool(typename UnsignedType<T>::Type(x)
254 >> PositionOfSignBit<T>::value);
257 // Bitwise ops may return a larger type, so it's good to use this inline
258 // helper guaranteeing that the result is really of type T.
259 template<typename T>
260 inline T
261 BinaryComplement(T x)
263 return ~x;
266 template<typename T,
267 typename U,
268 bool IsTSigned = IsSigned<T>::value,
269 bool IsUSigned = IsSigned<U>::value>
270 struct DoesRangeContainRange
274 template<typename T, typename U, bool Signedness>
275 struct DoesRangeContainRange<T, U, Signedness, Signedness>
277 static const bool value = sizeof(T) >= sizeof(U);
280 template<typename T, typename U>
281 struct DoesRangeContainRange<T, U, true, false>
283 static const bool value = sizeof(T) > sizeof(U);
286 template<typename T, typename U>
287 struct DoesRangeContainRange<T, U, false, true>
289 static const bool value = false;
292 template<typename T,
293 typename U,
294 bool IsTSigned = IsSigned<T>::value,
295 bool IsUSigned = IsSigned<U>::value,
296 bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
297 struct IsInRangeImpl {};
299 template<typename T, typename U, bool IsTSigned, bool IsUSigned>
300 struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
302 static bool run(U)
304 return true;
308 template<typename T, typename U>
309 struct IsInRangeImpl<T, U, true, true, false>
311 static bool run(U x)
313 return x <= MaxValue<T>::value && x >= MinValue<T>::value;
317 template<typename T, typename U>
318 struct IsInRangeImpl<T, U, false, false, false>
320 static bool run(U x)
322 return x <= MaxValue<T>::value;
326 template<typename T, typename U>
327 struct IsInRangeImpl<T, U, true, false, false>
329 static bool run(U x)
331 return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value);
335 template<typename T, typename U>
336 struct IsInRangeImpl<T, U, false, true, false>
338 static bool run(U x)
340 return sizeof(T) >= sizeof(U)
341 ? x >= 0
342 : x >= 0 && x <= U(MaxValue<T>::value);
346 template<typename T, typename U>
347 inline bool
348 IsInRange(U x)
350 return IsInRangeImpl<T, U>::run(x);
353 template<typename T>
354 inline bool
355 IsAddValid(T x, T y)
357 // Addition is valid if the sign of x+y is equal to either that of x or that
358 // of y. Since the value of x+y is undefined if we have a signed type, we
359 // compute it using the unsigned type of the same size.
360 // Beware! These bitwise operations can return a larger integer type,
361 // if T was a small type like int8_t, so we explicitly cast to T.
363 typename UnsignedType<T>::Type ux = x;
364 typename UnsignedType<T>::Type uy = y;
365 typename UnsignedType<T>::Type result = ux + uy;
366 return IsSigned<T>::value
367 ? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y))))
368 : BinaryComplement(x) >= y;
371 template<typename T>
372 inline bool
373 IsSubValid(T x, T y)
375 // Subtraction is valid if either x and y have same sign, or x-y and x have
376 // same sign. Since the value of x-y is undefined if we have a signed type,
377 // we compute it using the unsigned type of the same size.
378 typename UnsignedType<T>::Type ux = x;
379 typename UnsignedType<T>::Type uy = y;
380 typename UnsignedType<T>::Type result = ux - uy;
382 return IsSigned<T>::value
383 ? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y))))
384 : x >= y;
387 template<typename T,
388 bool IsTSigned = IsSigned<T>::value,
389 bool TwiceBiggerTypeIsSupported =
390 IsSupported<typename TwiceBiggerType<T>::Type>::value>
391 struct IsMulValidImpl {};
393 template<typename T, bool IsTSigned>
394 struct IsMulValidImpl<T, IsTSigned, true>
396 static bool run(T x, T y)
398 typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
399 TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
400 return IsInRange<T>(product);
404 template<typename T>
405 struct IsMulValidImpl<T, true, false>
407 static bool run(T x, T y)
409 const T max = MaxValue<T>::value;
410 const T min = MinValue<T>::value;
412 if (x == 0 || y == 0)
413 return true;
415 if (x > 0) {
416 return y > 0
417 ? x <= max / y
418 : y >= min / x;
421 // If we reach this point, we know that x < 0.
422 return y > 0
423 ? x >= min / y
424 : y >= max / x;
428 template<typename T>
429 struct IsMulValidImpl<T, false, false>
431 static bool run(T x, T y)
433 return y == 0 || x <= MaxValue<T>::value / y;
437 template<typename T>
438 inline bool
439 IsMulValid(T x, T y)
441 return IsMulValidImpl<T>::run(x, y);
444 template<typename T>
445 inline bool
446 IsDivValid(T x, T y)
448 // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
449 return y != 0 &&
450 !(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1));
453 // This is just to shut up msvc warnings about negating unsigned ints.
454 template<typename T, bool IsTSigned = IsSigned<T>::value>
455 struct OppositeIfSignedImpl
457 static T run(T x) { return -x; }
459 template<typename T>
460 struct OppositeIfSignedImpl<T, false>
462 static T run(T x) { return x; }
464 template<typename T>
465 inline T
466 OppositeIfSigned(T x)
468 return OppositeIfSignedImpl<T>::run(x);
471 } // namespace detail
475 * Step 4: Now define the CheckedInt class.
479 * @class CheckedInt
480 * @brief Integer wrapper class checking for integer overflow and other errors
481 * @param T the integer type to wrap. Can be any type among the following:
482 * - any basic integer type such as |int|
483 * - any stdint type such as |int8_t|
485 * This class implements guarded integer arithmetic. Do a computation, check
486 * that isValid() returns true, you then have a guarantee that no problem, such
487 * as integer overflow, happened during this computation, and you can call
488 * value() to get the plain integer value.
490 * The arithmetic operators in this class are guaranteed not to raise a signal
491 * (e.g. in case of a division by zero).
493 * For example, suppose that you want to implement a function that computes
494 * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by
495 * zero or integer overflow). You could code it as follows:
496 @code
497 bool computeXPlusYOverZ(int x, int y, int z, int *result)
499 CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z;
500 if (checkedResult.isValid()) {
501 *result = checkedResult.value();
502 return true;
503 } else {
504 return false;
507 @endcode
509 * Implicit conversion from plain integers to checked integers is allowed. The
510 * plain integer is checked to be in range before being casted to the
511 * destination type. This means that the following lines all compile, and the
512 * resulting CheckedInts are correctly detected as valid or invalid:
513 * @code
514 // 1 is of type int, is found to be in range for uint8_t, x is valid
515 CheckedInt<uint8_t> x(1);
516 // -1 is of type int, is found not to be in range for uint8_t, x is invalid
517 CheckedInt<uint8_t> x(-1);
518 // -1 is of type int, is found to be in range for int8_t, x is valid
519 CheckedInt<int8_t> x(-1);
520 // 1000 is of type int16_t, is found not to be in range for int8_t,
521 // x is invalid
522 CheckedInt<int8_t> x(int16_t(1000));
523 // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
524 // x is invalid
525 CheckedInt<int32_t> x(uint32_t(3123456789));
526 * @endcode
527 * Implicit conversion from
528 * checked integers to plain integers is not allowed. As shown in the
529 * above example, to get the value of a checked integer as a normal integer,
530 * call value().
532 * Arithmetic operations between checked and plain integers is allowed; the
533 * result type is the type of the checked integer.
535 * Checked integers of different types cannot be used in the same arithmetic
536 * expression.
538 * There are convenience typedefs for all stdint types, of the following form
539 * (these are just 2 examples):
540 @code
541 typedef CheckedInt<int32_t> CheckedInt32;
542 typedef CheckedInt<uint16_t> CheckedUint16;
543 @endcode
545 template<typename T>
546 class CheckedInt
548 protected:
549 T mValue;
550 bool mIsValid;
552 template<typename U>
553 CheckedInt(U value, bool isValid) : mValue(value), mIsValid(isValid)
555 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
556 "This type is not supported by CheckedInt");
559 public:
561 * Constructs a checked integer with given @a value. The checked integer is
562 * initialized as valid or invalid depending on whether the @a value
563 * is in range.
565 * This constructor is not explicit. Instead, the type of its argument is a
566 * separate template parameter, ensuring that no conversion is performed
567 * before this constructor is actually called. As explained in the above
568 * documentation for class CheckedInt, this constructor checks that its
569 * argument is valid.
571 template<typename U>
572 CheckedInt(U value)
573 : mValue(T(value)),
574 mIsValid(detail::IsInRange<T>(value))
576 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
577 "This type is not supported by CheckedInt");
580 /** Constructs a valid checked integer with initial value 0 */
581 CheckedInt() : mValue(0), mIsValid(true)
583 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
584 "This type is not supported by CheckedInt");
587 /** @returns the actual value */
588 T value() const
590 MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
591 return mValue;
595 * @returns true if the checked integer is valid, i.e. is not the result
596 * of an invalid operation or of an operation involving an invalid checked
597 * integer
599 bool isValid() const
601 return mIsValid;
604 template<typename U>
605 friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
606 const CheckedInt<U>& rhs);
607 template<typename U>
608 CheckedInt& operator +=(U rhs);
609 template<typename U>
610 friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
611 const CheckedInt<U> &rhs);
612 template<typename U>
613 CheckedInt& operator -=(U rhs);
614 template<typename U>
615 friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
616 const CheckedInt<U> &rhs);
617 template<typename U>
618 CheckedInt& operator *=(U rhs);
619 template<typename U>
620 friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
621 const CheckedInt<U> &rhs);
622 template<typename U>
623 CheckedInt& operator /=(U rhs);
625 CheckedInt operator -() const
627 // Circumvent msvc warning about - applied to unsigned int.
628 // if we're unsigned, the only valid case anyway is 0
629 // in which case - is a no-op.
630 T result = detail::OppositeIfSigned(mValue);
631 /* Help the compiler perform RVO (return value optimization). */
632 return CheckedInt(result,
633 mIsValid && detail::IsSubValid(T(0),
634 mValue));
638 * @returns true if the left and right hand sides are valid
639 * and have the same value.
641 * Note that these semantics are the reason why we don't offer
642 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
643 * but that would mean that whenever a or b is invalid, a!=b
644 * is always true, which would be very confusing.
646 * For similar reasons, operators <, >, <=, >= would be very tricky to
647 * specify, so we just avoid offering them.
649 * Notice that these == semantics are made more reasonable by these facts:
650 * 1. a==b implies equality at the raw data level
651 * (the converse is false, as a==b is never true among invalids)
652 * 2. This is similar to the behavior of IEEE floats, where a==b
653 * means that a and b have the same value *and* neither is NaN.
655 bool operator ==(const CheckedInt& other) const
657 return mIsValid && other.mIsValid && mValue == other.mValue;
660 /** prefix ++ */
661 CheckedInt& operator++()
663 *this += 1;
664 return *this;
667 /** postfix ++ */
668 CheckedInt operator++(int)
670 CheckedInt tmp = *this;
671 *this += 1;
672 return tmp;
675 /** prefix -- */
676 CheckedInt& operator--()
678 *this -= 1;
679 return *this;
682 /** postfix -- */
683 CheckedInt operator--(int)
685 CheckedInt tmp = *this;
686 *this -= 1;
687 return tmp;
690 private:
692 * The !=, <, <=, >, >= operators are disabled:
693 * see the comment on operator==.
695 template<typename U>
696 bool operator !=(U other) const MOZ_DELETE;
697 template<typename U>
698 bool operator <(U other) const MOZ_DELETE;
699 template<typename U>
700 bool operator <=(U other) const MOZ_DELETE;
701 template<typename U>
702 bool operator >(U other) const MOZ_DELETE;
703 template<typename U>
704 bool operator >=(U other) const MOZ_DELETE;
707 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
708 template<typename T> \
709 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \
710 const CheckedInt<T> &rhs) \
712 if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \
713 return CheckedInt<T>(0, false); \
715 return CheckedInt<T>(lhs.mValue OP rhs.mValue, \
716 lhs.mIsValid && rhs.mIsValid); \
719 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
720 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
721 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
722 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
724 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
726 // Implement castToCheckedInt<T>(x), making sure that
727 // - it allows x to be either a CheckedInt<T> or any integer type
728 // that can be casted to T
729 // - if x is already a CheckedInt<T>, we just return a reference to it,
730 // instead of copying it (optimization)
732 namespace detail {
734 template<typename T, typename U>
735 struct CastToCheckedIntImpl
737 typedef CheckedInt<T> ReturnType;
738 static CheckedInt<T> run(U u) { return u; }
741 template<typename T>
742 struct CastToCheckedIntImpl<T, CheckedInt<T> >
744 typedef const CheckedInt<T>& ReturnType;
745 static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
748 } // namespace detail
750 template<typename T, typename U>
751 inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
752 castToCheckedInt(U u)
754 return detail::CastToCheckedIntImpl<T, U>::run(u);
757 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
758 template<typename T> \
759 template<typename U> \
760 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \
762 *this = *this OP castToCheckedInt<T>(rhs); \
763 return *this; \
765 template<typename T, typename U> \
766 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
768 return lhs OP castToCheckedInt<T>(rhs); \
770 template<typename T, typename U> \
771 inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
773 return castToCheckedInt<T>(lhs) OP rhs; \
776 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
777 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
778 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
779 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
781 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
783 template<typename T, typename U>
784 inline bool
785 operator ==(const CheckedInt<T> &lhs, U rhs)
787 return lhs == castToCheckedInt<T>(rhs);
790 template<typename T, typename U>
791 inline bool
792 operator ==(U lhs, const CheckedInt<T> &rhs)
794 return castToCheckedInt<T>(lhs) == rhs;
797 // Convenience typedefs.
798 typedef CheckedInt<int8_t> CheckedInt8;
799 typedef CheckedInt<uint8_t> CheckedUint8;
800 typedef CheckedInt<int16_t> CheckedInt16;
801 typedef CheckedInt<uint16_t> CheckedUint16;
802 typedef CheckedInt<int32_t> CheckedInt32;
803 typedef CheckedInt<uint32_t> CheckedUint32;
804 typedef CheckedInt<int64_t> CheckedInt64;
805 typedef CheckedInt<uint64_t> CheckedUint64;
807 } // namespace mozilla
809 #endif /* mozilla_CheckedInt_h_ */