Bug 805121 - Be more careful checking math to avoid incorrect behaviors. r=terrence, a=akeybl
authorJeff Walden <jwalden@mit.edu>
Wed, 31 Oct 2012 15:07:59 -0700
changeset 82098 68c7adb5a15d5ce3fd381dcc235dfe85aab97466
parent 82097 9c034c148d8a89a400affa3451b416ad9074feb3
child 82099 33e4424595d6d95c06d9767519b9abfc8bd51a8e
push id349
push userryanvm@gmail.com
push dateWed, 12 Dec 2012 22:11:02 +0000
reviewersterrence, akeybl
bugs805121
milestone10.0.11esrpre
Bug 805121 - Be more careful checking math to avoid incorrect behaviors. r=terrence, a=akeybl
js/src/Makefile.in
js/src/jsstr.cpp
mfbt/Attributes.h
mfbt/CheckedInt.h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -277,16 +277,18 @@ EXPORTS_js = \
 #
 VPATH		+= \
 		$(srcdir)/../../mfbt \
 		$(NULL)
 
 EXPORTS_NAMESPACES += mozilla
 
 EXPORTS_mozilla = \
+		Attributes.h \
+		CheckedInt.h \
 		FloatingPoint.h \
 		NullPtr.h \
 		RangedPtr.h \
 		RefPtr.h \
 		Types.h	\
 		TypeTraits.h	\
 		Util.h \
 		WeakPtr.h \
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -43,16 +43,19 @@
  *
  * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
  * native methods store strings (possibly newborn) converted from their 'this'
  * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
  * conversions at their index (argv[0], argv[1]).  This is a legitimate method
  * of rooting things that might lose their newborn root due to subsequent GC
  * allocations in the same native method.
  */
+
+#include "mozilla/CheckedInt.h"
+
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
@@ -84,16 +87,18 @@
 #include "vm/StringObject-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 using namespace js::unicode;
 
+using mozilla::CheckedInt;
+
 #ifdef JS_TRACER
 
 JSBool JS_FASTCALL
 js_FlattenOnTrace(JSContext *cx, JSString* str)
 {
     return !!str->ensureLinear(cx);
 }
 JS_DEFINE_CALLINFO_2(extern, BOOL, js_FlattenOnTrace, CONTEXT, STRING, 0, nanojit::ACCSET_STORE_ANY)
@@ -1792,29 +1797,38 @@ FindReplaceLength(JSContext *cx, RegExpS
         rdata.repstr = repstr->ensureLinear(cx);
         if (!rdata.repstr)
             return false;
         *sizep = rdata.repstr->length();
         return true;
     }
 
     JSString *repstr = rdata.repstr;
-    size_t replen = repstr->length();
+    CheckedInt<uint32_t> replen = repstr->length();
     for (const jschar *dp = rdata.dollar, *ep = rdata.dollarEnd; dp;
          dp = js_strchr_limit(dp, '$', ep)) {
         JSSubString sub;
         size_t skip;
         if (InterpretDollar(cx, res, dp, ep, rdata, &sub, &skip)) {
-            replen += sub.length - skip;
+            if (sub.length > skip)
+                replen += sub.length - skip;
+            else
+                replen -= skip - sub.length;
             dp += skip;
         } else {
             dp++;
         }
     }
-    *sizep = replen;
+
+    if (!replen.isValid()) {
+        js_ReportAllocationOverflow(cx);
+        return false;
+    }
+
+    *sizep = replen.value();
     return true;
 }
 
 /* 
  * Precondition: |rdata.sb| already has necessary growth space reserved (as
  * derived from FindReplaceLength).
  */
 static void
@@ -1857,18 +1871,24 @@ ReplaceRegExpCallback(JSContext *cx, Reg
     const jschar *left = str.chars() + leftoff;
     size_t leftlen = res->matchStart() - leftoff;
     rdata.leftIndex = res->matchLimit();
 
     size_t replen = 0;  /* silence 'unused' warning */
     if (!FindReplaceLength(cx, res, rdata, &replen))
         return false;
 
-    size_t growth = leftlen + replen;
-    if (!rdata.sb.reserve(rdata.sb.length() + growth))
+    CheckedInt<uint32_t> newlen(rdata.sb.length());
+    newlen += leftlen;
+    newlen += replen;
+    if (!newlen.isValid()) {
+        js_ReportAllocationOverflow(cx);
+        return false;
+    }
+    if (!rdata.sb.reserve(newlen.value()))
         return false;
     rdata.sb.infallibleAppend(left, leftlen); /* skipped-over portion of the search value */
     DoReplace(cx, res, rdata);
     return true;
 }
 
 static bool
 BuildFlatReplacement(JSContext *cx, JSString *textstr, JSString *repstr,
new file mode 100644
--- /dev/null
+++ b/mfbt/Attributes.h
@@ -0,0 +1,493 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Implementations of various class and method modifier attributes. */
+
+#ifndef mozilla_Attributes_h_
+#define mozilla_Attributes_h_
+
+/*
+ * This header does not include any other headers so that it can be included by
+ * code that is (only currently) mfbt-incompatible.
+ */
+
+/*
+ * MOZ_INLINE is a macro which expands to tell the compiler that the method
+ * decorated with it should be inlined.  This macro is usable from C and C++
+ * code, even though C89 does not support the |inline| keyword.  The compiler
+ * may ignore this directive if it chooses.
+ */
+#if defined(__cplusplus)
+#  define MOZ_INLINE            inline
+#elif defined(_MSC_VER)
+#  define MOZ_INLINE            __inline
+#elif defined(__GNUC__)
+#  define MOZ_INLINE            __inline__
+#else
+#  define MOZ_INLINE            inline
+#endif
+
+/*
+ * MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the
+ * method decorated with it must be inlined, even if the compiler thinks
+ * otherwise.  This is only a (much) stronger version of the MOZ_INLINE hint:
+ * compilers are not guaranteed to respect it (although they're much more likely
+ * to do so).
+ */
+#if defined(DEBUG)
+#  define MOZ_ALWAYS_INLINE     MOZ_INLINE
+#elif defined(_MSC_VER)
+#  define MOZ_ALWAYS_INLINE     __forceinline
+#elif defined(__GNUC__)
+#  define MOZ_ALWAYS_INLINE     __attribute__((always_inline)) MOZ_INLINE
+#else
+#  define MOZ_ALWAYS_INLINE     MOZ_INLINE
+#endif
+
+/*
+ * g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality
+ * without warnings (functionality used by the macros below).  These modes are
+ * detectable by checking whether __GXX_EXPERIMENTAL_CXX0X__ is defined or, more
+ * standardly, by checking whether __cplusplus has a C++11 or greater value.
+ * Current versions of g++ do not correctly set __cplusplus, so we check both
+ * for forward compatibility.
+ */
+#if defined(__clang__)
+   /*
+    * Per Clang documentation, "Note that marketing version numbers should not
+    * be used to check for language features, as different vendors use different
+    * numbering schemes. Instead, use the feature checking macros."
+    */
+#  ifndef __has_extension
+#    define __has_extension __has_feature /* compatibility, for older versions of clang */
+#  endif
+#  if __has_extension(cxx_deleted_functions)
+#    define MOZ_HAVE_CXX11_DELETE
+#  endif
+#  if __has_extension(cxx_override_control)
+#    define MOZ_HAVE_CXX11_OVERRIDE
+#    define MOZ_HAVE_CXX11_FINAL         final
+#  endif
+#  if __has_extension(cxx_strong_enums)
+#    define MOZ_HAVE_CXX11_ENUM_TYPE
+#    define MOZ_HAVE_CXX11_STRONG_ENUMS
+#  endif
+#  if __has_attribute(noinline)
+#    define MOZ_HAVE_NEVER_INLINE        __attribute__((noinline))
+#  endif
+#  if __has_attribute(noreturn)
+#    define MOZ_HAVE_NORETURN            __attribute__((noreturn))
+#  endif
+#elif defined(__GNUC__)
+#  if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
+#    if __GNUC__ > 4
+#      define MOZ_HAVE_CXX11_DELETE
+#      define MOZ_HAVE_CXX11_OVERRIDE
+#      define MOZ_HAVE_CXX11_FINAL       final
+#    elif __GNUC__ == 4
+#      if __GNUC_MINOR__ >= 7
+#        define MOZ_HAVE_CXX11_OVERRIDE
+#        define MOZ_HAVE_CXX11_FINAL     final
+#      endif
+#      if __GNUC_MINOR__ >= 4
+#        define MOZ_HAVE_CXX11_DELETE
+#        define MOZ_HAVE_CXX11_ENUM_TYPE
+#        define MOZ_HAVE_CXX11_STRONG_ENUMS
+#      endif
+#    endif
+#  else
+     /* __final is a non-C++11 GCC synonym for 'final', per GCC r176655. */
+#    if __GNUC__ > 4
+#      define MOZ_HAVE_CXX11_FINAL       __final
+#    elif __GNUC__ == 4
+#      if __GNUC_MINOR__ >= 7
+#        define MOZ_HAVE_CXX11_FINAL     __final
+#      endif
+#    endif
+#  endif
+#  define MOZ_HAVE_NEVER_INLINE          __attribute__((noinline))
+#  define MOZ_HAVE_NORETURN              __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#  if _MSC_VER >= 1400
+#    define MOZ_HAVE_CXX11_OVERRIDE
+     /* MSVC currently spells "final" as "sealed". */
+#    define MOZ_HAVE_CXX11_FINAL         sealed
+#    define MOZ_HAVE_CXX11_ENUM_TYPE
+#  endif
+#  if _MSC_VER >= 1700
+#    define MOZ_HAVE_CXX11_STRONG_ENUMS
+#  endif
+#  define MOZ_HAVE_NEVER_INLINE          __declspec(noinline)
+#  define MOZ_HAVE_NORETURN              __declspec(noreturn)
+#endif
+
+/*
+ * MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the
+ * method decorated with it must never be inlined, even if the compiler would
+ * otherwise choose to inline the method.  Compilers aren't absolutely
+ * guaranteed to support this, but most do.
+ */
+#if defined(MOZ_HAVE_NEVER_INLINE)
+#  define MOZ_NEVER_INLINE      MOZ_HAVE_NEVER_INLINE
+#else
+#  define MOZ_NEVER_INLINE      /* no support */
+#endif
+
+/*
+ * MOZ_NORETURN, specified at the start of a function declaration, indicates
+ * that the given function does not return.  (The function definition does not
+ * need to be annotated.)
+ *
+ *   MOZ_NORETURN void abort(const char* msg);
+ *
+ * This modifier permits the compiler to optimize code assuming a call to such a
+ * function will never return.  It also enables the compiler to avoid spurious
+ * warnings about not initializing variables, or about any other seemingly-dodgy
+ * operations performed after the function returns.
+ *
+ * This modifier does not affect the corresponding function's linking behavior.
+ */
+#if defined(MOZ_HAVE_NORETURN)
+#  define MOZ_NORETURN          MOZ_HAVE_NORETURN
+#else
+#  define MOZ_NORETURN          /* no support */
+#endif
+
+/*
+ * MOZ_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time
+ * instrumentation shipped with Clang) to not instrument the annotated function.
+ * Furthermore, it will prevent the compiler from inlining the function because
+ * inlining currently breaks the blacklisting mechanism of AddressSanitizer.
+ */
+#if defined(MOZ_ASAN)
+#  define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_address_safety_analysis))
+# else
+#  define MOZ_ASAN_BLACKLIST
+#endif
+
+
+#ifdef __cplusplus
+
+/*
+ * MOZ_DELETE, specified immediately prior to the ';' terminating an undefined-
+ * method declaration, attempts to delete that method from the corresponding
+ * class.  An attempt to use the method will always produce an error *at compile
+ * time* (instead of sometimes as late as link time) when this macro can be
+ * implemented.  For example, you can use MOZ_DELETE to produce classes with no
+ * implicit copy constructor or assignment operator:
+ *
+ *   struct NonCopyable
+ *   {
+ *     private:
+ *       NonCopyable(const NonCopyable& other) MOZ_DELETE;
+ *       void operator=(const NonCopyable& other) MOZ_DELETE;
+ *   };
+ *
+ * If MOZ_DELETE can't be implemented for the current compiler, use of the
+ * annotated method will still cause an error, but the error might occur at link
+ * time in some cases rather than at compile time.
+ *
+ * MOZ_DELETE relies on C++11 functionality not universally implemented.  As a
+ * backstop, method declarations using MOZ_DELETE should be private.
+ */
+#if defined(MOZ_HAVE_CXX11_DELETE)
+#  define MOZ_DELETE            = delete
+#else
+#  define MOZ_DELETE            /* no support */
+#endif
+
+/*
+ * MOZ_OVERRIDE explicitly indicates that a virtual member function in a class
+ * overrides a member function of a base class, rather than potentially being a
+ * new member function.  MOZ_OVERRIDE should be placed immediately before the
+ * ';' terminating the member function's declaration, or before '= 0;' if the
+ * member function is pure.  If the member function is defined in the class
+ * definition, it should appear before the opening brace of the function body.
+ *
+ *   class Base
+ *   {
+ *     public:
+ *       virtual void f() = 0;
+ *   };
+ *   class Derived1 : public Base
+ *   {
+ *     public:
+ *       virtual void f() MOZ_OVERRIDE;
+ *   };
+ *   class Derived2 : public Base
+ *   {
+ *     public:
+ *       virtual void f() MOZ_OVERRIDE = 0;
+ *   };
+ *   class Derived3 : public Base
+ *   {
+ *     public:
+ *       virtual void f() MOZ_OVERRIDE { }
+ *   };
+ *
+ * In compilers supporting C++11 override controls, MOZ_OVERRIDE *requires* that
+ * the function marked with it override a member function of a base class: it
+ * is a compile error if it does not.  Otherwise MOZ_OVERRIDE does not affect
+ * semantics and merely documents the override relationship to the reader (but
+ * of course must still be used correctly to not break C++11 compilers).
+ */
+#if defined(MOZ_HAVE_CXX11_OVERRIDE)
+#  define MOZ_OVERRIDE          override
+#else
+#  define MOZ_OVERRIDE          /* no support */
+#endif
+
+/*
+ * MOZ_FINAL indicates that some functionality cannot be overridden through
+ * inheritance.  It can be used to annotate either classes/structs or virtual
+ * member functions.
+ *
+ * To annotate a class/struct with MOZ_FINAL, place MOZ_FINAL immediately after
+ * the name of the class, before the list of classes from which it derives (if
+ * any) and before its opening brace.  MOZ_FINAL must not be used to annotate
+ * unnamed classes or structs.  (With some compilers, and with C++11 proper, the
+ * underlying expansion is ambiguous with specifying a class name.)
+ *
+ *   class Base MOZ_FINAL
+ *   {
+ *     public:
+ *       Base();
+ *       ~Base();
+ *       virtual void f() { }
+ *   };
+ *   // This will be an error in some compilers:
+ *   class Derived : public Base
+ *   {
+ *     public:
+ *       ~Derived() { }
+ *   };
+ *
+ * One particularly common reason to specify MOZ_FINAL upon a class is to tell
+ * the compiler that it's not dangerous for it to have a non-virtual destructor
+ * yet have one or more virtual functions, silencing the warning it might emit
+ * in this case.  Suppose Base above weren't annotated with MOZ_FINAL.  Because
+ * ~Base() is non-virtual, an attempt to delete a Derived* through a Base*
+ * wouldn't call ~Derived(), so any cleanup ~Derived() might do wouldn't happen.
+ * (Formally C++ says behavior is undefined, but compilers will likely just call
+ * ~Base() and not ~Derived().)  Specifying MOZ_FINAL tells the compiler that
+ * it's safe for the destructor to be non-virtual.
+ *
+ * In compilers implementing final controls, it is an error to inherit from a
+ * class annotated with MOZ_FINAL.  In other compilers it serves only as
+ * documentation.
+ *
+ * To annotate a virtual member function with MOZ_FINAL, place MOZ_FINAL
+ * immediately before the ';' terminating the member function's declaration, or
+ * before '= 0;' if the member function is pure.  If the member function is
+ * defined in the class definition, it should appear before the opening brace of
+ * the function body.  (This placement is identical to that for MOZ_OVERRIDE.
+ * If both are used, they should appear in the order 'MOZ_FINAL MOZ_OVERRIDE'
+ * for consistency.)
+ *
+ *   class Base
+ *   {
+ *     public:
+ *       virtual void f() MOZ_FINAL;
+ *   };
+ *   class Derived
+ *   {
+ *     public:
+ *       // This will be an error in some compilers:
+ *       virtual void f();
+ *   };
+ *
+ * In compilers implementing final controls, it is an error for a derived class
+ * to override a method annotated with MOZ_FINAL.  In other compilers it serves
+ * only as documentation.
+ */
+#if defined(MOZ_HAVE_CXX11_FINAL)
+#  define MOZ_FINAL             MOZ_HAVE_CXX11_FINAL
+#else
+#  define MOZ_FINAL             /* no support */
+#endif
+
+/**
+ * MOZ_ENUM_TYPE specifies the underlying numeric type for an enum.  It's
+ * specified by placing MOZ_ENUM_TYPE(type) immediately after the enum name in
+ * its declaration, and before the opening curly brace, like
+ *
+ *   enum MyEnum MOZ_ENUM_TYPE(uint16_t)
+ *   {
+ *     A,
+ *     B = 7,
+ *     C
+ *   };
+ *
+ * In supporting compilers, the macro will expand to ": uint16_t".  The
+ * compiler will allocate exactly two bytes for MyEnum, and will require all
+ * enumerators to have values between 0 and 65535.  (Thus specifying "B =
+ * 100000" instead of "B = 7" would fail to compile.)  In old compilers, the
+ * macro expands to the empty string, and the underlying type is generally
+ * undefined.
+ */
+#ifdef MOZ_HAVE_CXX11_ENUM_TYPE
+#  define MOZ_ENUM_TYPE(type)   : type
+#else
+#  define MOZ_ENUM_TYPE(type)   /* no support */
+#endif
+
+/**
+ * MOZ_BEGIN_ENUM_CLASS and MOZ_END_ENUM_CLASS provide access to the
+ * strongly-typed enumeration feature of C++11 ("enum class").  If supported
+ * by the compiler, an enum defined using these macros will not be implicitly
+ * converted to any other type, and its enumerators will be scoped using the
+ * enumeration name.  Place MOZ_BEGIN_ENUM_CLASS(EnumName, type) in place of
+ * "enum EnumName {", and MOZ_END_ENUM_CLASS(EnumName) in place of the closing
+ * "};".  For example,
+ *
+ *   MOZ_BEGIN_ENUM_CLASS(Enum, int32_t)
+ *     A, B = 6
+ *   MOZ_END_ENUM_CLASS(Enum)
+ *
+ * This will make "Enum::A" and "Enum::B" appear in the global scope, but "A"
+ * and "B" will not.  In compilers that support C++11 strongly-typed
+ * enumerations, implicit conversions of Enum values to numeric types will
+ * fail.  In other compilers, Enum itself will actually be defined as a class,
+ * and some implicit conversions will fail while others will succeed.
+ *
+ * The type argument specifies the underlying type for the enum where
+ * supported, as with MOZ_ENUM_TYPE().  For simplicity, it is currently
+ * mandatory.  As with MOZ_ENUM_TYPE(), it will do nothing on compilers that do
+ * not support it.
+ */
+#if defined(MOZ_HAVE_CXX11_STRONG_ENUMS)
+  /* All compilers that support strong enums also support an explicit
+   * underlying type, so no extra check is needed */
+#  define MOZ_BEGIN_ENUM_CLASS(Name, type) enum class Name : type {
+#  define MOZ_END_ENUM_CLASS(Name)         };
+#else
+   /**
+    * We need Name to both name a type, and scope the provided enumerator
+    * names.  Namespaces and classes both provide scoping, but namespaces
+    * aren't types, so we need to use a class that wraps the enum values.  We
+    * have an implicit conversion from the inner enum type to the class, so
+    * statements like
+    *
+    *   Enum x = Enum::A;
+    *
+    * will still work.  We need to define an implicit conversion from the class
+    * to the inner enum as well, so that (for instance) switch statements will
+    * work.  This means that the class can be implicitly converted to a numeric
+    * value as well via the enum type, since C++ allows an implicit
+    * user-defined conversion followed by a standard conversion to still be
+    * implicit.
+    *
+    * We have an explicit constructor from int defined, so that casts like
+    * (Enum)7 will still work.  We also have a zero-argument constructor with
+    * no arguments, so declaration without initialization (like "Enum foo;")
+    * will work.
+    *
+    * Additionally, we'll delete as many operators as possible for the inner
+    * enum type, so statements like this will still fail:
+    *
+    *   f(5 + Enum::B); // deleted operator+
+    *
+    * But we can't prevent things like this, because C++ doesn't allow
+    * overriding conversions or assignment operators for enums:
+    *
+    *   int x = Enum::A;
+    *   int f()
+    *   {
+    *     return Enum::A;
+    *   }
+    */
+#  define MOZ_BEGIN_ENUM_CLASS(Name, type) \
+     class Name \
+     { \
+       public: \
+         enum Enum MOZ_ENUM_TYPE(type) \
+         {
+#  define MOZ_END_ENUM_CLASS(Name) \
+         }; \
+         Name() {} \
+         Name(Enum aEnum) : mEnum(aEnum) {} \
+         explicit Name(int num) : mEnum((Enum)num) {} \
+         operator Enum() const { return mEnum; } \
+       private: \
+         Enum mEnum; \
+     }; \
+     inline int operator+(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator+(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator-(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator-(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator*(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator*(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator/(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator/(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator%(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator%(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator+(const Name::Enum&) MOZ_DELETE; \
+     inline int operator-(const Name::Enum&) MOZ_DELETE; \
+     inline int& operator++(Name::Enum&) MOZ_DELETE; \
+     inline int operator++(Name::Enum&, int) MOZ_DELETE; \
+     inline int& operator--(Name::Enum&) MOZ_DELETE; \
+     inline int operator--(Name::Enum&, int) MOZ_DELETE; \
+     inline bool operator==(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline bool operator==(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline bool operator!=(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline bool operator!=(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline bool operator>(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline bool operator>(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline bool operator<(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline bool operator<(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline bool operator>=(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline bool operator>=(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline bool operator<=(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline bool operator<=(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline bool operator!(const Name::Enum&) MOZ_DELETE; \
+     inline bool operator&&(const bool&, const Name::Enum&) MOZ_DELETE; \
+     inline bool operator&&(const Name::Enum&, const bool&) MOZ_DELETE; \
+     inline bool operator||(const bool&, const Name::Enum&) MOZ_DELETE; \
+     inline bool operator||(const Name::Enum&, const bool&) MOZ_DELETE; \
+     inline int operator~(const Name::Enum&) MOZ_DELETE; \
+     inline int operator&(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator&(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator|(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator|(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator^(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator^(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator<<(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator<<(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int operator>>(const int&, const Name::Enum&) MOZ_DELETE; \
+     inline int operator>>(const Name::Enum&, const int&) MOZ_DELETE; \
+     inline int& operator+=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator-=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator*=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator/=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator%=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator&=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator|=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator^=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator<<=(int&, const Name::Enum&) MOZ_DELETE; \
+     inline int& operator>>=(int&, const Name::Enum&) MOZ_DELETE;
+#endif
+
+/**
+ * MOZ_WARN_UNUSED_RESULT tells the compiler to emit a warning if a function's
+ * return value is not used by the caller.
+ *
+ * Place this attribute at the very beginning of a function definition. For
+ * example, write
+ *
+ *   MOZ_WARN_UNUSED_RESULT int foo();
+ *
+ * or
+ *
+ *   MOZ_WARN_UNUSED_RESULT int foo() { return 42; }
+ */
+#if defined(__GNUC__) || defined(__clang__)
+#  define MOZ_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
+#else
+#  define MOZ_WARN_UNUSED_RESULT
+#endif
+
+#endif /* __cplusplus */
+
+#endif  /* mozilla_Attributes_h_ */
new file mode 100644
--- /dev/null
+++ b/mfbt/CheckedInt.h
@@ -0,0 +1,800 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Provides checked integers, detecting integer overflow and divide-by-0. */
+
+#ifndef mozilla_CheckedInt_h_
+#define mozilla_CheckedInt_h_
+
+/*
+ * Build options. Comment out these #defines to disable the corresponding
+ * optional feature. Disabling features may be useful for code using
+ * CheckedInt outside of Mozilla (e.g. WebKit)
+ */
+
+// Enable usage of MOZ_STATIC_ASSERT to check for unsupported types.
+// If disabled, static asserts are replaced by regular assert().
+#include <cassert>
+#define MOZ_STATIC_ASSERT(cond, reason) assert((cond) && reason)
+
+/*
+ * End of build options
+ */
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Util.h"
+
+#include <climits>
+#include <cstddef>
+
+namespace mozilla {
+
+namespace detail {
+
+/*
+ * Step 1: manually record supported types
+ *
+ * What's nontrivial here is that there are different families of integer
+ * types: basic integer types and stdint types. It is merrily undefined which
+ * types from one family may be just typedefs for a type from another family.
+ *
+ * For example, on GCC 4.6, aside from the basic integer types, the only other
+ * type that isn't just a typedef for some of them, is int8.
+ */
+
+struct UnsupportedType {};
+
+template<typename IntegerType>
+struct IsSupportedPass2
+{
+    static const bool value = false;
+};
+
+template<typename IntegerType>
+struct IsSupported
+{
+    static const bool value = IsSupportedPass2<IntegerType>::value;
+};
+
+template<>
+struct IsSupported<int8>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<uint8>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<int16>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<uint16>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<int32>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<uint32>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<int64>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<uint64>
+{ static const bool value = true; };
+
+
+template<>
+struct IsSupportedPass2<char>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<unsigned char>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<short>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<unsigned short>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<int>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<unsigned int>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<long>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<unsigned long>
+{ static const bool value = true; };
+
+
+/*
+ * Step 2: some integer-traits kind of stuff.
+ */
+
+template<size_t Size, bool Signedness>
+struct StdintTypeForSizeAndSignedness
+{};
+
+template<>
+struct StdintTypeForSizeAndSignedness<1, true>
+{ typedef int8   Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<1, false>
+{ typedef uint8  Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<2, true>
+{ typedef int16  Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<2, false>
+{ typedef uint16 Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<4, true>
+{ typedef int32  Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<4, false>
+{ typedef uint32 Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<8, true>
+{ typedef int64  Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<8, false>
+{ typedef uint64 Type; };
+
+template<typename IntegerType>
+struct UnsignedType
+{
+    typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType),
+                                                    false>::Type Type;
+};
+
+template<typename IntegerType>
+struct IsSigned
+{
+    static const bool value = IntegerType(-1) <= IntegerType(0);
+};
+
+template<typename IntegerType, size_t Size = sizeof(IntegerType)>
+struct TwiceBiggerType
+{
+    typedef typename StdintTypeForSizeAndSignedness<
+                       sizeof(IntegerType) * 2,
+                       IsSigned<IntegerType>::value
+                     >::Type Type;
+};
+
+template<typename IntegerType>
+struct TwiceBiggerType<IntegerType, 8>
+{
+    typedef UnsupportedType Type;
+};
+
+template<typename IntegerType>
+struct PositionOfSignBit
+{
+    static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1;
+};
+
+template<typename IntegerType>
+struct MinValue
+{
+  private:
+    typedef typename UnsignedType<IntegerType>::Type UnsignedIntegerType;
+    static const size_t PosOfSignBit = PositionOfSignBit<IntegerType>::value;
+
+  public:
+    // Bitwise ops may return a larger type, that's why we cast explicitly.
+    // In C++, left bit shifts on signed values is undefined by the standard
+    // unless the shifted value is representable.
+    // Notice that signed-to-unsigned conversions are always well-defined in
+    // the standard as the value congruent to 2**n, as expected. By contrast,
+    // unsigned-to-signed is only well-defined if the value is representable.
+    static const IntegerType value =
+        IsSigned<IntegerType>::value
+        ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit)
+        : IntegerType(0);
+};
+
+template<typename IntegerType>
+struct MaxValue
+{
+    // Tricksy, but covered by the unit test.
+    // Relies heavily on the type of MinValue<IntegerType>::value
+    // being IntegerType.
+    static const IntegerType value = ~MinValue<IntegerType>::value;
+};
+
+/*
+ * Step 3: Implement the actual validity checks.
+ *
+ * Ideas taken from IntegerLib, code different.
+ */
+
+template<typename T>
+inline bool
+HasSignBit(T x)
+{
+  // In C++, right bit shifts on negative values is undefined by the standard.
+  // Notice that signed-to-unsigned conversions are always well-defined in the
+  // standard, as the value congruent modulo 2**n as expected. By contrast,
+  // unsigned-to-signed is only well-defined if the value is representable.
+  return bool(typename UnsignedType<T>::Type(x)
+                >> PositionOfSignBit<T>::value);
+}
+
+// Bitwise ops may return a larger type, so it's good to use this inline
+// helper guaranteeing that the result is really of type T.
+template<typename T>
+inline T
+BinaryComplement(T x)
+{
+  return ~x;
+}
+
+template<typename T,
+         typename U,
+         bool IsTSigned = IsSigned<T>::value,
+         bool IsUSigned = IsSigned<U>::value>
+struct DoesRangeContainRange
+{
+};
+
+template<typename T, typename U, bool Signedness>
+struct DoesRangeContainRange<T, U, Signedness, Signedness>
+{
+    static const bool value = sizeof(T) >= sizeof(U);
+};
+
+template<typename T, typename U>
+struct DoesRangeContainRange<T, U, true, false>
+{
+    static const bool value = sizeof(T) > sizeof(U);
+};
+
+template<typename T, typename U>
+struct DoesRangeContainRange<T, U, false, true>
+{
+    static const bool value = false;
+};
+
+template<typename T,
+         typename U,
+         bool IsTSigned = IsSigned<T>::value,
+         bool IsUSigned = IsSigned<U>::value,
+         bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
+struct IsInRangeImpl {};
+
+template<typename T, typename U, bool IsTSigned, bool IsUSigned>
+struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
+{
+    static bool run(U)
+    {
+       return true;
+    }
+};
+
+template<typename T, typename U>
+struct IsInRangeImpl<T, U, true, true, false>
+{
+    static bool run(U x)
+    {
+      return x <= MaxValue<T>::value && x >= MinValue<T>::value;
+    }
+};
+
+template<typename T, typename U>
+struct IsInRangeImpl<T, U, false, false, false>
+{
+    static bool run(U x)
+    {
+      return x <= MaxValue<T>::value;
+    }
+};
+
+template<typename T, typename U>
+struct IsInRangeImpl<T, U, true, false, false>
+{
+    static bool run(U x)
+    {
+      return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value);
+    }
+};
+
+template<typename T, typename U>
+struct IsInRangeImpl<T, U, false, true, false>
+{
+    static bool run(U x)
+    {
+      return sizeof(T) >= sizeof(U)
+             ? x >= 0
+             : x >= 0 && x <= U(MaxValue<T>::value);
+    }
+};
+
+template<typename T, typename U>
+inline bool
+IsInRange(U x)
+{
+  return IsInRangeImpl<T, U>::run(x);
+}
+
+template<typename T>
+inline bool
+IsAddValid(T x, T y)
+{
+  // Addition is valid if the sign of x+y is equal to either that of x or that
+  // of y. Since the value of x+y is undefined if we have a signed type, we
+  // compute it using the unsigned type of the same size.
+  // Beware! These bitwise operations can return a larger integer type,
+  // if T was a small type like int8, so we explicitly cast to T.
+
+  typename UnsignedType<T>::Type ux = x;
+  typename UnsignedType<T>::Type uy = y;
+  typename UnsignedType<T>::Type result = ux + uy;
+  return IsSigned<T>::value
+         ? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y))))
+         : BinaryComplement(x) >= y;
+}
+
+template<typename T>
+inline bool
+IsSubValid(T x, T y)
+{
+  // Subtraction is valid if either x and y have same sign, or x-y and x have
+  // same sign. Since the value of x-y is undefined if we have a signed type,
+  // we compute it using the unsigned type of the same size.
+  typename UnsignedType<T>::Type ux = x;
+  typename UnsignedType<T>::Type uy = y;
+  typename UnsignedType<T>::Type result = ux - uy;
+
+  return IsSigned<T>::value
+         ? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y))))
+         : x >= y;
+}
+
+template<typename T,
+         bool IsTSigned = IsSigned<T>::value,
+         bool TwiceBiggerTypeIsSupported =
+           IsSupported<typename TwiceBiggerType<T>::Type>::value>
+struct IsMulValidImpl {};
+
+template<typename T, bool IsTSigned>
+struct IsMulValidImpl<T, IsTSigned, true>
+{
+    static bool run(T x, T y)
+    {
+      typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
+      TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
+      return IsInRange<T>(product);
+    }
+};
+
+template<typename T>
+struct IsMulValidImpl<T, true, false>
+{
+    static bool run(T x, T y)
+    {
+      const T max = MaxValue<T>::value;
+      const T min = MinValue<T>::value;
+
+      if (x == 0 || y == 0)
+        return true;
+
+      if (x > 0) {
+        return y > 0
+               ? x <= max / y
+               : y >= min / x;
+      }
+
+      // If we reach this point, we know that x < 0.
+      return y > 0
+             ? x >= min / y
+             : y >= max / x;
+    }
+};
+
+template<typename T>
+struct IsMulValidImpl<T, false, false>
+{
+    static bool run(T x, T y)
+    {
+      return y == 0 ||  x <= MaxValue<T>::value / y;
+    }
+};
+
+template<typename T>
+inline bool
+IsMulValid(T x, T y)
+{
+  return IsMulValidImpl<T>::run(x, y);
+}
+
+template<typename T>
+inline bool
+IsDivValid(T x, T y)
+{
+  // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
+  return y != 0 &&
+         !(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1));
+}
+
+// This is just to shut up msvc warnings about negating unsigned ints.
+template<typename T, bool IsTSigned = IsSigned<T>::value>
+struct OppositeIfSignedImpl
+{
+    static T run(T x) { return -x; }
+};
+template<typename T>
+struct OppositeIfSignedImpl<T, false>
+{
+    static T run(T x) { return x; }
+};
+template<typename T>
+inline T
+OppositeIfSigned(T x)
+{
+  return OppositeIfSignedImpl<T>::run(x);
+}
+
+} // namespace detail
+
+
+/*
+ * Step 4: Now define the CheckedInt class.
+ */
+
+/**
+ * @class CheckedInt
+ * @brief Integer wrapper class checking for integer overflow and other errors
+ * @param T the integer type to wrap. Can be any type among the following:
+ *            - any basic integer type such as |int|
+ *            - any stdint type such as |int8|
+ *
+ * This class implements guarded integer arithmetic. Do a computation, check
+ * that isValid() returns true, you then have a guarantee that no problem, such
+ * as integer overflow, happened during this computation, and you can call
+ * value() to get the plain integer value.
+ *
+ * The arithmetic operators in this class are guaranteed not to raise a signal
+ * (e.g. in case of a division by zero).
+ *
+ * For example, suppose that you want to implement a function that computes
+ * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by
+ * zero or integer overflow). You could code it as follows:
+   @code
+   bool computeXPlusYOverZ(int x, int y, int z, int *result)
+   {
+       CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z;
+       if (checkedResult.isValid()) {
+           *result = checkedResult.value();
+           return true;
+       } else {
+           return false;
+       }
+   }
+   @endcode
+ *
+ * Implicit conversion from plain integers to checked integers is allowed. The
+ * plain integer is checked to be in range before being casted to the
+ * destination type. This means that the following lines all compile, and the
+ * resulting CheckedInts are correctly detected as valid or invalid:
+ * @code
+   // 1 is of type int, is found to be in range for uint8, x is valid
+   CheckedInt<uint8> x(1);
+   // -1 is of type int, is found not to be in range for uint8, x is invalid
+   CheckedInt<uint8> x(-1);
+   // -1 is of type int, is found to be in range for int8, x is valid
+   CheckedInt<int8> x(-1);
+   // 1000 is of type int16, is found not to be in range for int8,
+   // x is invalid
+   CheckedInt<int8> x(int16(1000)); 
+   // 3123456789 is of type uint32, is found not to be in range for int32,
+   // x is invalid
+   CheckedInt<int32> x(uint32(3123456789));
+ * @endcode
+ * Implicit conversion from
+ * checked integers to plain integers is not allowed. As shown in the
+ * above example, to get the value of a checked integer as a normal integer,
+ * call value().
+ *
+ * Arithmetic operations between checked and plain integers is allowed; the
+ * result type is the type of the checked integer.
+ *
+ * Checked integers of different types cannot be used in the same arithmetic
+ * expression.
+ *
+ * There are convenience typedefs for all stdint types, of the following form
+ * (these are just 2 examples):
+   @code
+   typedef CheckedInt<int32> CheckedInt32;
+   typedef CheckedInt<uint16> CheckedUint16;
+   @endcode
+ */
+template<typename T>
+class CheckedInt
+{
+  protected:
+    T mValue;
+    bool mIsValid;
+
+    template<typename U>
+    CheckedInt(U value, bool isValid) : mValue(value), mIsValid(isValid)
+    {
+      MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
+                        "This type is not supported by CheckedInt");
+    }
+
+  public:
+    /**
+     * Constructs a checked integer with given @a value. The checked integer is
+     * initialized as valid or invalid depending on whether the @a value
+     * is in range.
+     *
+     * This constructor is not explicit. Instead, the type of its argument is a
+     * separate template parameter, ensuring that no conversion is performed
+     * before this constructor is actually called. As explained in the above
+     * documentation for class CheckedInt, this constructor checks that its
+     * argument is valid.
+     */
+    template<typename U>
+    CheckedInt(U value)
+      : mValue(T(value)),
+        mIsValid(detail::IsInRange<T>(value))
+    {
+      MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
+                        "This type is not supported by CheckedInt");
+    }
+
+    /** Constructs a valid checked integer with initial value 0 */
+    CheckedInt() : mValue(0), mIsValid(true)
+    {
+      MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
+                        "This type is not supported by CheckedInt");
+    }
+
+    /** @returns the actual value */
+    T value() const
+    {
+      MOZ_ASSERT(mIsValid);
+      return mValue;
+    }
+
+    /**
+     * @returns true if the checked integer is valid, i.e. is not the result
+     * of an invalid operation or of an operation involving an invalid checked
+     * integer
+     */
+    bool isValid() const
+    {
+      return mIsValid;
+    }
+
+    template<typename U>
+    friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U>& rhs);
+    template<typename U>
+    CheckedInt& operator +=(U rhs);
+    template<typename U>
+    friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U> &rhs);
+    template<typename U>
+    CheckedInt& operator -=(U rhs);
+    template<typename U>
+    friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U> &rhs);
+    template<typename U>
+    CheckedInt& operator *=(U rhs);
+    template<typename U>
+    friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U> &rhs);
+    template<typename U>
+    CheckedInt& operator /=(U rhs);
+
+    CheckedInt operator -() const
+    {
+      // Circumvent msvc warning about - applied to unsigned int.
+      // if we're unsigned, the only valid case anyway is 0
+      // in which case - is a no-op.
+      T result = detail::OppositeIfSigned(mValue);
+      /* Help the compiler perform RVO (return value optimization). */
+      return CheckedInt(result,
+                        mIsValid && detail::IsSubValid(T(0),
+                                                       mValue));
+    }
+
+    /**
+     * @returns true if the left and right hand sides are valid
+     * and have the same value.
+     *
+     * Note that these semantics are the reason why we don't offer
+     * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
+     * but that would mean that whenever a or b is invalid, a!=b
+     * is always true, which would be very confusing.
+     *
+     * For similar reasons, operators <, >, <=, >= would be very tricky to
+     * specify, so we just avoid offering them.
+     *
+     * Notice that these == semantics are made more reasonable by these facts:
+     *  1. a==b implies equality at the raw data level
+     *     (the converse is false, as a==b is never true among invalids)
+     *  2. This is similar to the behavior of IEEE floats, where a==b
+     *     means that a and b have the same value *and* neither is NaN.
+     */
+    bool operator ==(const CheckedInt& other) const
+    {
+      return mIsValid && other.mIsValid && mValue == other.mValue;
+    }
+
+    /** prefix ++ */
+    CheckedInt& operator++()
+    {
+      *this += 1;
+      return *this;
+    }
+
+    /** postfix ++ */
+    CheckedInt operator++(int)
+    {
+      CheckedInt tmp = *this;
+      *this += 1;
+      return tmp;
+    }
+
+    /** prefix -- */
+    CheckedInt& operator--()
+    {
+      *this -= 1;
+      return *this;
+    }
+
+    /** postfix -- */
+    CheckedInt operator--(int)
+    {
+      CheckedInt tmp = *this;
+      *this -= 1;
+      return tmp;
+    }
+
+  private:
+    /**
+     * The !=, <, <=, >, >= operators are disabled:
+     * see the comment on operator==.
+     */
+    template<typename U>
+    bool operator !=(U other) const MOZ_DELETE;
+    template<typename U>
+    bool operator <(U other) const MOZ_DELETE;
+    template<typename U>
+    bool operator <=(U other) const MOZ_DELETE;
+    template<typename U>
+    bool operator >(U other) const MOZ_DELETE;
+    template<typename U>
+    bool operator >=(U other) const MOZ_DELETE;
+};
+
+#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP)                \
+template<typename T>                                                  \
+inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs,            \
+                                 const CheckedInt<T> &rhs)            \
+{                                                                     \
+  if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue))               \
+    return CheckedInt<T>(0, false);                                   \
+                                                                      \
+  return CheckedInt<T>(lhs.mValue OP rhs.mValue,                      \
+                       lhs.mIsValid && rhs.mIsValid);                 \
+}
+
+MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
+MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
+MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
+MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
+
+#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
+
+// Implement castToCheckedInt<T>(x), making sure that
+//  - it allows x to be either a CheckedInt<T> or any integer type
+//    that can be casted to T
+//  - if x is already a CheckedInt<T>, we just return a reference to it,
+//    instead of copying it (optimization)
+
+namespace detail {
+
+template<typename T, typename U>
+struct CastToCheckedIntImpl
+{
+    typedef CheckedInt<T> ReturnType;
+    static CheckedInt<T> run(U u) { return u; }
+};
+
+template<typename T>
+struct CastToCheckedIntImpl<T, CheckedInt<T> >
+{
+    typedef const CheckedInt<T>& ReturnType;
+    static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
+};
+
+} // namespace detail
+
+template<typename T, typename U>
+inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
+castToCheckedInt(U u)
+{
+  return detail::CastToCheckedIntImpl<T, U>::run(u);
+}
+
+#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP)  \
+template<typename T>                                              \
+template<typename U>                                              \
+CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs)         \
+{                                                                 \
+  *this = *this OP castToCheckedInt<T>(rhs);                      \
+  return *this;                                                   \
+}                                                                 \
+template<typename T, typename U>                                  \
+inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
+{                                                                 \
+  return lhs OP castToCheckedInt<T>(rhs);                         \
+}                                                                 \
+template<typename T, typename U>                                  \
+inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
+{                                                                 \
+  return castToCheckedInt<T>(lhs) OP rhs;                         \
+}
+
+MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
+MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
+MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
+MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
+
+#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
+
+template<typename T, typename U>
+inline bool
+operator ==(const CheckedInt<T> &lhs, U rhs)
+{
+  return lhs == castToCheckedInt<T>(rhs);
+}
+
+template<typename T, typename U>
+inline bool
+operator ==(U  lhs, const CheckedInt<T> &rhs)
+{
+  return castToCheckedInt<T>(lhs) == rhs;
+}
+
+// Convenience typedefs.
+typedef CheckedInt<int8>   CheckedInt8;
+typedef CheckedInt<uint8>  CheckedUint8;
+typedef CheckedInt<int16>  CheckedInt16;
+typedef CheckedInt<uint16> CheckedUint16;
+typedef CheckedInt<int32>  CheckedInt32;
+typedef CheckedInt<uint32> CheckedUint32;
+typedef CheckedInt<int64>  CheckedInt64;
+typedef CheckedInt<uint64> CheckedUint64;
+
+} // namespace mozilla
+
+#endif /* mozilla_CheckedInt_h_ */