Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Provides checked integers, detecting integer overflow and divide-by-0. */
9 #ifndef mozilla_CheckedInt_h
10 #define mozilla_CheckedInt_h
12 #include <stdint.h>
13 #include "mozilla/Assertions.h"
14 #include "mozilla/IntegerTypeTraits.h"
16 namespace mozilla {
18 template<typename T> class CheckedInt;
20 namespace detail {
22 /*
23 * Step 1: manually record supported types
24 *
25 * What's nontrivial here is that there are different families of integer
26 * types: basic integer types and stdint types. It is merrily undefined which
27 * types from one family may be just typedefs for a type from another family.
28 *
29 * For example, on GCC 4.6, aside from the basic integer types, the only other
30 * type that isn't just a typedef for some of them, is int8_t.
31 */
33 struct UnsupportedType {};
35 template<typename IntegerType>
36 struct IsSupportedPass2
37 {
38 static const bool value = false;
39 };
41 template<typename IntegerType>
42 struct IsSupported
43 {
44 static const bool value = IsSupportedPass2<IntegerType>::value;
45 };
47 template<>
48 struct IsSupported<int8_t>
49 { static const bool value = true; };
51 template<>
52 struct IsSupported<uint8_t>
53 { static const bool value = true; };
55 template<>
56 struct IsSupported<int16_t>
57 { static const bool value = true; };
59 template<>
60 struct IsSupported<uint16_t>
61 { static const bool value = true; };
63 template<>
64 struct IsSupported<int32_t>
65 { static const bool value = true; };
67 template<>
68 struct IsSupported<uint32_t>
69 { static const bool value = true; };
71 template<>
72 struct IsSupported<int64_t>
73 { static const bool value = true; };
75 template<>
76 struct IsSupported<uint64_t>
77 { static const bool value = true; };
80 template<>
81 struct IsSupportedPass2<char>
82 { static const bool value = true; };
84 template<>
85 struct IsSupportedPass2<signed char>
86 { static const bool value = true; };
88 template<>
89 struct IsSupportedPass2<unsigned char>
90 { static const bool value = true; };
92 template<>
93 struct IsSupportedPass2<short>
94 { static const bool value = true; };
96 template<>
97 struct IsSupportedPass2<unsigned short>
98 { static const bool value = true; };
100 template<>
101 struct IsSupportedPass2<int>
102 { static const bool value = true; };
104 template<>
105 struct IsSupportedPass2<unsigned int>
106 { static const bool value = true; };
108 template<>
109 struct IsSupportedPass2<long>
110 { static const bool value = true; };
112 template<>
113 struct IsSupportedPass2<unsigned long>
114 { static const bool value = true; };
116 template<>
117 struct IsSupportedPass2<long long>
118 { static const bool value = true; };
120 template<>
121 struct IsSupportedPass2<unsigned long long>
122 { static const bool value = true; };
124 /*
125 * Step 2: Implement the actual validity checks.
126 *
127 * Ideas taken from IntegerLib, code different.
128 */
130 template<typename IntegerType, size_t Size = sizeof(IntegerType)>
131 struct TwiceBiggerType
132 {
133 typedef typename detail::StdintTypeForSizeAndSignedness<
134 sizeof(IntegerType) * 2,
135 IsSigned<IntegerType>::value
136 >::Type Type;
137 };
139 template<typename IntegerType>
140 struct TwiceBiggerType<IntegerType, 8>
141 {
142 typedef UnsupportedType Type;
143 };
145 template<typename T>
146 inline bool
147 HasSignBit(T x)
148 {
149 // In C++, right bit shifts on negative values is undefined by the standard.
150 // Notice that signed-to-unsigned conversions are always well-defined in the
151 // standard, as the value congruent modulo 2**n as expected. By contrast,
152 // unsigned-to-signed is only well-defined if the value is representable.
153 return bool(typename MakeUnsigned<T>::Type(x) >> PositionOfSignBit<T>::value);
154 }
156 // Bitwise ops may return a larger type, so it's good to use this inline
157 // helper guaranteeing that the result is really of type T.
158 template<typename T>
159 inline T
160 BinaryComplement(T x)
161 {
162 return ~x;
163 }
165 template<typename T,
166 typename U,
167 bool IsTSigned = IsSigned<T>::value,
168 bool IsUSigned = IsSigned<U>::value>
169 struct DoesRangeContainRange
170 {
171 };
173 template<typename T, typename U, bool Signedness>
174 struct DoesRangeContainRange<T, U, Signedness, Signedness>
175 {
176 static const bool value = sizeof(T) >= sizeof(U);
177 };
179 template<typename T, typename U>
180 struct DoesRangeContainRange<T, U, true, false>
181 {
182 static const bool value = sizeof(T) > sizeof(U);
183 };
185 template<typename T, typename U>
186 struct DoesRangeContainRange<T, U, false, true>
187 {
188 static const bool value = false;
189 };
191 template<typename T,
192 typename U,
193 bool IsTSigned = IsSigned<T>::value,
194 bool IsUSigned = IsSigned<U>::value,
195 bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
196 struct IsInRangeImpl {};
198 template<typename T, typename U, bool IsTSigned, bool IsUSigned>
199 struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
200 {
201 static bool run(U)
202 {
203 return true;
204 }
205 };
207 template<typename T, typename U>
208 struct IsInRangeImpl<T, U, true, true, false>
209 {
210 static bool run(U x)
211 {
212 return x <= MaxValue<T>::value && x >= MinValue<T>::value;
213 }
214 };
216 template<typename T, typename U>
217 struct IsInRangeImpl<T, U, false, false, false>
218 {
219 static bool run(U x)
220 {
221 return x <= MaxValue<T>::value;
222 }
223 };
225 template<typename T, typename U>
226 struct IsInRangeImpl<T, U, true, false, false>
227 {
228 static bool run(U x)
229 {
230 return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value);
231 }
232 };
234 template<typename T, typename U>
235 struct IsInRangeImpl<T, U, false, true, false>
236 {
237 static bool run(U x)
238 {
239 return sizeof(T) >= sizeof(U)
240 ? x >= 0
241 : x >= 0 && x <= U(MaxValue<T>::value);
242 }
243 };
245 template<typename T, typename U>
246 inline bool
247 IsInRange(U x)
248 {
249 return IsInRangeImpl<T, U>::run(x);
250 }
252 template<typename T>
253 inline bool
254 IsAddValid(T x, T y)
255 {
256 // Addition is valid if the sign of x+y is equal to either that of x or that
257 // of y. Since the value of x+y is undefined if we have a signed type, we
258 // compute it using the unsigned type of the same size.
259 // Beware! These bitwise operations can return a larger integer type,
260 // if T was a small type like int8_t, so we explicitly cast to T.
262 typename MakeUnsigned<T>::Type ux = x;
263 typename MakeUnsigned<T>::Type uy = y;
264 typename MakeUnsigned<T>::Type result = ux + uy;
265 return IsSigned<T>::value
266 ? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y))))
267 : BinaryComplement(x) >= y;
268 }
270 template<typename T>
271 inline bool
272 IsSubValid(T x, T y)
273 {
274 // Subtraction is valid if either x and y have same sign, or x-y and x have
275 // same sign. Since the value of x-y is undefined if we have a signed type,
276 // we compute it using the unsigned type of the same size.
277 typename MakeUnsigned<T>::Type ux = x;
278 typename MakeUnsigned<T>::Type uy = y;
279 typename MakeUnsigned<T>::Type result = ux - uy;
281 return IsSigned<T>::value
282 ? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y))))
283 : x >= y;
284 }
286 template<typename T,
287 bool IsTSigned = IsSigned<T>::value,
288 bool TwiceBiggerTypeIsSupported =
289 IsSupported<typename TwiceBiggerType<T>::Type>::value>
290 struct IsMulValidImpl {};
292 template<typename T, bool IsTSigned>
293 struct IsMulValidImpl<T, IsTSigned, true>
294 {
295 static bool run(T x, T y)
296 {
297 typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
298 TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
299 return IsInRange<T>(product);
300 }
301 };
303 template<typename T>
304 struct IsMulValidImpl<T, true, false>
305 {
306 static bool run(T x, T y)
307 {
308 const T max = MaxValue<T>::value;
309 const T min = MinValue<T>::value;
311 if (x == 0 || y == 0)
312 return true;
314 if (x > 0) {
315 return y > 0
316 ? x <= max / y
317 : y >= min / x;
318 }
320 // If we reach this point, we know that x < 0.
321 return y > 0
322 ? x >= min / y
323 : y >= max / x;
324 }
325 };
327 template<typename T>
328 struct IsMulValidImpl<T, false, false>
329 {
330 static bool run(T x, T y)
331 {
332 return y == 0 || x <= MaxValue<T>::value / y;
333 }
334 };
336 template<typename T>
337 inline bool
338 IsMulValid(T x, T y)
339 {
340 return IsMulValidImpl<T>::run(x, y);
341 }
343 template<typename T>
344 inline bool
345 IsDivValid(T x, T y)
346 {
347 // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
348 return y != 0 &&
349 !(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1));
350 }
352 template<typename T, bool IsTSigned = IsSigned<T>::value>
353 struct IsModValidImpl;
355 template<typename T>
356 inline bool
357 IsModValid(T x, T y)
358 {
359 return IsModValidImpl<T>::run(x, y);
360 }
362 /*
363 * Mod is pretty simple.
364 * For now, let's just use the ANSI C definition:
365 * If x or y are negative, the results are implementation defined.
366 * Consider these invalid.
367 * Undefined for y=0.
368 * The result will never exceed either x or y.
369 *
370 * Checking that x>=0 is a warning when T is unsigned.
371 */
373 template<typename T>
374 struct IsModValidImpl<T, false> {
375 static inline bool run(T x, T y) {
376 return y >= 1;
377 }
378 };
380 template<typename T>
381 struct IsModValidImpl<T, true> {
382 static inline bool run(T x, T y) {
383 if (x < 0)
384 return false;
386 return y >= 1;
387 }
388 };
390 template<typename T, bool IsSigned = IsSigned<T>::value>
391 struct NegateImpl;
393 template<typename T>
394 struct NegateImpl<T, false>
395 {
396 static CheckedInt<T> negate(const CheckedInt<T>& val)
397 {
398 // Handle negation separately for signed/unsigned, for simpler code and to
399 // avoid an MSVC warning negating an unsigned value.
400 return CheckedInt<T>(0, val.isValid() && val.mValue == 0);
401 }
402 };
404 template<typename T>
405 struct NegateImpl<T, true>
406 {
407 static CheckedInt<T> negate(const CheckedInt<T>& val)
408 {
409 // Watch out for the min-value, which (with twos-complement) can't be
410 // negated as -min-value is then (max-value + 1).
411 if (!val.isValid() || val.mValue == MinValue<T>::value)
412 return CheckedInt<T>(val.mValue, false);
413 return CheckedInt<T>(-val.mValue, true);
414 }
415 };
417 } // namespace detail
420 /*
421 * Step 3: Now define the CheckedInt class.
422 */
424 /**
425 * @class CheckedInt
426 * @brief Integer wrapper class checking for integer overflow and other errors
427 * @param T the integer type to wrap. Can be any type among the following:
428 * - any basic integer type such as |int|
429 * - any stdint type such as |int8_t|
430 *
431 * This class implements guarded integer arithmetic. Do a computation, check
432 * that isValid() returns true, you then have a guarantee that no problem, such
433 * as integer overflow, happened during this computation, and you can call
434 * value() to get the plain integer value.
435 *
436 * The arithmetic operators in this class are guaranteed not to raise a signal
437 * (e.g. in case of a division by zero).
438 *
439 * For example, suppose that you want to implement a function that computes
440 * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by
441 * zero or integer overflow). You could code it as follows:
442 @code
443 bool computeXPlusYOverZ(int x, int y, int z, int *result)
444 {
445 CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z;
446 if (checkedResult.isValid()) {
447 *result = checkedResult.value();
448 return true;
449 } else {
450 return false;
451 }
452 }
453 @endcode
454 *
455 * Implicit conversion from plain integers to checked integers is allowed. The
456 * plain integer is checked to be in range before being casted to the
457 * destination type. This means that the following lines all compile, and the
458 * resulting CheckedInts are correctly detected as valid or invalid:
459 * @code
460 // 1 is of type int, is found to be in range for uint8_t, x is valid
461 CheckedInt<uint8_t> x(1);
462 // -1 is of type int, is found not to be in range for uint8_t, x is invalid
463 CheckedInt<uint8_t> x(-1);
464 // -1 is of type int, is found to be in range for int8_t, x is valid
465 CheckedInt<int8_t> x(-1);
466 // 1000 is of type int16_t, is found not to be in range for int8_t,
467 // x is invalid
468 CheckedInt<int8_t> x(int16_t(1000));
469 // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
470 // x is invalid
471 CheckedInt<int32_t> x(uint32_t(3123456789));
472 * @endcode
473 * Implicit conversion from
474 * checked integers to plain integers is not allowed. As shown in the
475 * above example, to get the value of a checked integer as a normal integer,
476 * call value().
477 *
478 * Arithmetic operations between checked and plain integers is allowed; the
479 * result type is the type of the checked integer.
480 *
481 * Checked integers of different types cannot be used in the same arithmetic
482 * expression.
483 *
484 * There are convenience typedefs for all stdint types, of the following form
485 * (these are just 2 examples):
486 @code
487 typedef CheckedInt<int32_t> CheckedInt32;
488 typedef CheckedInt<uint16_t> CheckedUint16;
489 @endcode
490 */
491 template<typename T>
492 class CheckedInt
493 {
494 protected:
495 T mValue;
496 bool mIsValid;
498 template<typename U>
499 CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
500 {
501 static_assert(detail::IsSupported<T>::value &&
502 detail::IsSupported<U>::value,
503 "This type is not supported by CheckedInt");
504 }
506 friend struct detail::NegateImpl<T>;
508 public:
509 /**
510 * Constructs a checked integer with given @a value. The checked integer is
511 * initialized as valid or invalid depending on whether the @a value
512 * is in range.
513 *
514 * This constructor is not explicit. Instead, the type of its argument is a
515 * separate template parameter, ensuring that no conversion is performed
516 * before this constructor is actually called. As explained in the above
517 * documentation for class CheckedInt, this constructor checks that its
518 * argument is valid.
519 */
520 template<typename U>
521 CheckedInt(U aValue)
522 : mValue(T(aValue)),
523 mIsValid(detail::IsInRange<T>(aValue))
524 {
525 static_assert(detail::IsSupported<T>::value &&
526 detail::IsSupported<U>::value,
527 "This type is not supported by CheckedInt");
528 }
530 template<typename U>
531 friend class CheckedInt;
533 template<typename U>
534 CheckedInt<U> toChecked() const
535 {
536 CheckedInt<U> ret(mValue);
537 ret.mIsValid = ret.mIsValid && mIsValid;
538 return ret;
539 }
541 /** Constructs a valid checked integer with initial value 0 */
542 CheckedInt() : mValue(0), mIsValid(true)
543 {
544 static_assert(detail::IsSupported<T>::value,
545 "This type is not supported by CheckedInt");
546 }
548 /** @returns the actual value */
549 T value() const
550 {
551 MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
552 return mValue;
553 }
555 /**
556 * @returns true if the checked integer is valid, i.e. is not the result
557 * of an invalid operation or of an operation involving an invalid checked
558 * integer
559 */
560 bool isValid() const
561 {
562 return mIsValid;
563 }
565 template<typename U>
566 friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
567 const CheckedInt<U>& rhs);
568 template<typename U>
569 CheckedInt& operator +=(U rhs);
571 template<typename U>
572 friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
573 const CheckedInt<U>& rhs);
574 template<typename U>
575 CheckedInt& operator -=(U rhs);
577 template<typename U>
578 friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
579 const CheckedInt<U>& rhs);
580 template<typename U>
581 CheckedInt& operator *=(U rhs);
583 template<typename U>
584 friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
585 const CheckedInt<U>& rhs);
586 template<typename U>
587 CheckedInt& operator /=(U rhs);
589 template<typename U>
590 friend CheckedInt<U> operator %(const CheckedInt<U>& lhs,
591 const CheckedInt<U>& rhs);
592 template<typename U>
593 CheckedInt& operator %=(U rhs);
595 CheckedInt operator -() const
596 {
597 return detail::NegateImpl<T>::negate(*this);
598 }
600 /**
601 * @returns true if the left and right hand sides are valid
602 * and have the same value.
603 *
604 * Note that these semantics are the reason why we don't offer
605 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
606 * but that would mean that whenever a or b is invalid, a!=b
607 * is always true, which would be very confusing.
608 *
609 * For similar reasons, operators <, >, <=, >= would be very tricky to
610 * specify, so we just avoid offering them.
611 *
612 * Notice that these == semantics are made more reasonable by these facts:
613 * 1. a==b implies equality at the raw data level
614 * (the converse is false, as a==b is never true among invalids)
615 * 2. This is similar to the behavior of IEEE floats, where a==b
616 * means that a and b have the same value *and* neither is NaN.
617 */
618 bool operator ==(const CheckedInt& other) const
619 {
620 return mIsValid && other.mIsValid && mValue == other.mValue;
621 }
623 /** prefix ++ */
624 CheckedInt& operator++()
625 {
626 *this += 1;
627 return *this;
628 }
630 /** postfix ++ */
631 CheckedInt operator++(int)
632 {
633 CheckedInt tmp = *this;
634 *this += 1;
635 return tmp;
636 }
638 /** prefix -- */
639 CheckedInt& operator--()
640 {
641 *this -= 1;
642 return *this;
643 }
645 /** postfix -- */
646 CheckedInt operator--(int)
647 {
648 CheckedInt tmp = *this;
649 *this -= 1;
650 return tmp;
651 }
653 private:
654 /**
655 * The !=, <, <=, >, >= operators are disabled:
656 * see the comment on operator==.
657 */
658 template<typename U>
659 bool operator !=(U other) const MOZ_DELETE;
660 template<typename U>
661 bool operator <(U other) const MOZ_DELETE;
662 template<typename U>
663 bool operator <=(U other) const MOZ_DELETE;
664 template<typename U>
665 bool operator >(U other) const MOZ_DELETE;
666 template<typename U>
667 bool operator >=(U other) const MOZ_DELETE;
668 };
670 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
671 template<typename T> \
672 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \
673 const CheckedInt<T> &rhs) \
674 { \
675 if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \
676 return CheckedInt<T>(0, false); \
677 \
678 return CheckedInt<T>(lhs.mValue OP rhs.mValue, \
679 lhs.mIsValid && rhs.mIsValid); \
680 }
682 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
683 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
684 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
685 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
686 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %)
688 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
690 // Implement castToCheckedInt<T>(x), making sure that
691 // - it allows x to be either a CheckedInt<T> or any integer type
692 // that can be casted to T
693 // - if x is already a CheckedInt<T>, we just return a reference to it,
694 // instead of copying it (optimization)
696 namespace detail {
698 template<typename T, typename U>
699 struct CastToCheckedIntImpl
700 {
701 typedef CheckedInt<T> ReturnType;
702 static CheckedInt<T> run(U u) { return u; }
703 };
705 template<typename T>
706 struct CastToCheckedIntImpl<T, CheckedInt<T> >
707 {
708 typedef const CheckedInt<T>& ReturnType;
709 static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
710 };
712 } // namespace detail
714 template<typename T, typename U>
715 inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
716 castToCheckedInt(U u)
717 {
718 static_assert(detail::IsSupported<T>::value &&
719 detail::IsSupported<U>::value,
720 "This type is not supported by CheckedInt");
721 return detail::CastToCheckedIntImpl<T, U>::run(u);
722 }
724 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
725 template<typename T> \
726 template<typename U> \
727 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \
728 { \
729 *this = *this OP castToCheckedInt<T>(rhs); \
730 return *this; \
731 } \
732 template<typename T, typename U> \
733 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
734 { \
735 return lhs OP castToCheckedInt<T>(rhs); \
736 } \
737 template<typename T, typename U> \
738 inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
739 { \
740 return castToCheckedInt<T>(lhs) OP rhs; \
741 }
743 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
744 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
745 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
746 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
747 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
749 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
751 template<typename T, typename U>
752 inline bool
753 operator ==(const CheckedInt<T> &lhs, U rhs)
754 {
755 return lhs == castToCheckedInt<T>(rhs);
756 }
758 template<typename T, typename U>
759 inline bool
760 operator ==(U lhs, const CheckedInt<T> &rhs)
761 {
762 return castToCheckedInt<T>(lhs) == rhs;
763 }
765 // Convenience typedefs.
766 typedef CheckedInt<int8_t> CheckedInt8;
767 typedef CheckedInt<uint8_t> CheckedUint8;
768 typedef CheckedInt<int16_t> CheckedInt16;
769 typedef CheckedInt<uint16_t> CheckedUint16;
770 typedef CheckedInt<int32_t> CheckedInt32;
771 typedef CheckedInt<uint32_t> CheckedUint32;
772 typedef CheckedInt<int64_t> CheckedInt64;
773 typedef CheckedInt<uint64_t> CheckedUint64;
775 } // namespace mozilla
777 #endif /* mozilla_CheckedInt_h */