Bug 1309834. r=wchen. a=ritu
authorHenri Sivonen <hsivonen@hsivonen.fi>
Fri, 14 Oct 2016 11:47:17 +0300
changeset 462130 4c8cafd1dc8bb63380bf145a1c31a88f79927426
parent 462129 a68998d0287fdf9d5ee1819bb212926f448068ad
child 462131 420cc786a095985dd1fc7b37f3a40fe2b8dc3035
push id41678
push userfelipc@gmail.com
push dateMon, 16 Jan 2017 20:19:38 +0000
reviewerswchen, ritu
bugs1309834
milestone50.1.0
Bug 1309834. r=wchen. a=ritu MozReview-Commit-ID: FO7bXlx6lv
parser/html/jArray.h
parser/html/nsHtml5ArrayCopy.h
parser/html/nsHtml5TokenizerCppSupplement.h
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/html/nsHtml5TreeBuilderHSupplement.h
--- a/parser/html/jArray.h
+++ b/parser/html/jArray.h
@@ -45,22 +45,22 @@ struct staticJArray {
 };
 
 template<class T, class L>
 struct jArray {
   T* arr;
   L length;
   static jArray<T,L> newJArray(L const len) {
     MOZ_ASSERT(len >= 0, "Negative length.");
-    jArray<T,L> newArray = { new T[len], len };
+    jArray<T,L> newArray = { new T[size_t(len)], len };
     return newArray;
   }
   static jArray<T,L> newFallibleJArray(L const len) {
     MOZ_ASSERT(len >= 0, "Negative length.");
-    T* a = new (mozilla::fallible) T[len];
+    T* a = new (mozilla::fallible) T[size_t(len)];
     jArray<T,L> newArray = { a, a ? len : 0 };
     return newArray;
   }
   operator T*() { return arr; }
   T& operator[] (L const index) {
     MOZ_ASSERT(index >= 0, "Array access with negative index.");
     MOZ_ASSERT(index < length, "Array index out of bounds.");
     return arr[index];
--- a/parser/html/nsHtml5ArrayCopy.h
+++ b/parser/html/nsHtml5ArrayCopy.h
@@ -31,48 +31,48 @@ class nsHtml5AttributeName;
 // Unfortunately, these don't work as template functions because the arguments
 // would need coercion from a template class, which complicates things.
 class nsHtml5ArrayCopy {
   public:
 
     static inline void
     arraycopy(char16_t* source, int32_t sourceOffset, char16_t* target, int32_t targetOffset, int32_t length)
     {
-      memcpy(&(target[targetOffset]), &(source[sourceOffset]), length * sizeof(char16_t));
+      memcpy(&(target[targetOffset]), &(source[sourceOffset]), size_t(length) * sizeof(char16_t));
     }
 
     static inline void
     arraycopy(char16_t* source, char16_t* target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(char16_t));
+      memcpy(target, source, size_t(length) * sizeof(char16_t));
     }
 
     static inline void
     arraycopy(int32_t* source, int32_t* target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(int32_t));
+      memcpy(target, source, size_t(length) * sizeof(int32_t));
     }
 
     static inline void
     arraycopy(nsString** source, nsString** target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(nsString*));
+      memcpy(target, source, size_t(length) * sizeof(nsString*));
     }
 
     static inline void
     arraycopy(nsHtml5AttributeName** source, nsHtml5AttributeName** target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(nsHtml5AttributeName*));
+      memcpy(target, source, size_t(length) * sizeof(nsHtml5AttributeName*));
     }
 
     static inline void
     arraycopy(nsHtml5StackNode** source, nsHtml5StackNode** target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(nsHtml5StackNode*));
+      memcpy(target, source, size_t(length) * sizeof(nsHtml5StackNode*));
     }
 
     static inline void
     arraycopy(nsHtml5StackNode** arr, int32_t sourceOffset, int32_t targetOffset, int32_t length)
     {
-      memmove(&(arr[targetOffset]), &(arr[sourceOffset]), length * sizeof(nsHtml5StackNode*));
+      memmove(&(arr[targetOffset]), &(arr[sourceOffset]), size_t(length) * sizeof(nsHtml5StackNode*));
     }
 };
 #endif // nsHtml5ArrayCopy_h
--- a/parser/html/nsHtml5TokenizerCppSupplement.h
+++ b/parser/html/nsHtml5TokenizerCppSupplement.h
@@ -1,47 +1,64 @@
 /* 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/. */
 
 #include "mozilla/Likely.h"
 
+// INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
+// is 2^30. Note that this is counting char16_t units. The underlying
+// bytes will be twice that, but they fit even in 32-bit size_t even
+// if a contiguous chunk of memory of that size is pretty unlikely to
+// be available on a 32-bit system.
+#define MAX_POWER_OF_TWO_IN_INT32 0x40000000
+
 bool
 nsHtml5Tokenizer::EnsureBufferSpace(int32_t aLength)
 {
-  MOZ_ASSERT(aLength >= 0, "Negative length.");
+  MOZ_RELEASE_ASSERT(aLength >= 0, "Negative length.");
+  if (aLength > MAX_POWER_OF_TWO_IN_INT32) {
+    // Can't happen when loading from network.
+    return false;
+  }
+  CheckedInt<int32_t> worstCase(strBufLen);
+  worstCase += aLength;
+  worstCase += charRefBufLen;
   // Add 2 to account for emissions of LT_GT, LT_SOLIDUS and RSQB_RSQB.
   // Adding to the general worst case instead of only the
   // TreeBuilder-exposed worst case to avoid re-introducing a bug when
   // unifying the tokenizer and tree builder buffers in the future.
-  size_t worstCase = size_t(strBufLen) +
-                     size_t(aLength) +
-                     size_t(charRefBufLen) +
-                     size_t(2);
-  if (worstCase > INT32_MAX) {
-    // Since we index into the buffer using int32_t due to the Java heritage
-    // of the code, let's treat this as OOM.
+  worstCase += 2;
+  if (!worstCase.isValid()) {
+    return false;
+  }
+  if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
     return false;
   }
   // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
   // so that the call below becomes unnecessary.
-  tokenHandler->EnsureBufferSpace(worstCase);
+  if (!tokenHandler->EnsureBufferSpace(worstCase.value())) {
+    return false;
+  }
   if (!strBuf) {
-    // Add one to round to the next power of two to avoid immediate
-    // reallocation once there are a few characters in the buffer.
-    strBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase + 1));
+    if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) {
+      // Add one to round to the next power of two to avoid immediate
+      // reallocation once there are a few characters in the buffer.
+      worstCase += 1;
+    }
+    strBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
     if (!strBuf) {
       return false;
     }
-  } else if (worstCase > size_t(strBuf.length)) {
-    jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase));
+  } else if (worstCase.value() > strBuf.length) {
+    jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
     if (!newBuf) {
       return false;
     }
-    memcpy(newBuf,strBuf, sizeof(char16_t) * strBufLen);
+    memcpy(newBuf, strBuf, sizeof(char16_t) * size_t(strBufLen));
     strBuf = newBuf;
   }
   return true;
 }
 
 void
 nsHtml5Tokenizer::StartPlainText()
 {
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -956,40 +956,52 @@ void
 nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, int32_t aLength)
 {
   MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length,
                      "About to memcpy past the end of the buffer!");
   memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength);
   charBufferLen += aLength;
 }
 
+// INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
+// is 2^30. Note that this is counting char16_t units. The underlying
+// bytes will be twice that, but they fit even in 32-bit size_t even
+// if a contiguous chunk of memory of that size is pretty unlikely to
+// be available on a 32-bit system.
+#define MAX_POWER_OF_TWO_IN_INT32 0x40000000
+
 bool
-nsHtml5TreeBuilder::EnsureBufferSpace(size_t aLength)
+nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength)
 {
   // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
   // so that this method becomes unnecessary.
-  size_t worstCase = size_t(charBufferLen) + aLength;
-  if (worstCase > INT32_MAX) {
-    // Since we index into the buffer using int32_t due to the Java heritage
-    // of the code, let's treat this as OOM.
+  CheckedInt<int32_t> worstCase(charBufferLen);
+  worstCase += aLength;
+  if (!worstCase.isValid()) {
+    return false;
+  }
+  if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
     return false;
   }
   if (!charBuffer) {
-    // Add one to round to the next power of two to avoid immediate
-    // reallocation once there are a few characters in the buffer.
-    charBuffer = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase + 1));
+    if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) {
+      // Add one to round to the next power of two to avoid immediate
+      // reallocation once there are a few characters in the buffer.
+      worstCase += 1;
+    }
+    charBuffer = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
     if (!charBuffer) {
       return false;
     }
-  } else if (worstCase > size_t(charBuffer.length)) {
-    jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase));
+  } else if (worstCase.value() > charBuffer.length) {
+    jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
     if (!newBuf) {
       return false;
     }
-    memcpy(newBuf, charBuffer, sizeof(char16_t) * charBufferLen);
+    memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen));
     charBuffer = newBuf;
   }
   return true;
 }
 
 nsIContentHandle*
 nsHtml5TreeBuilder::AllocateContentHandle()
 {
--- a/parser/html/nsHtml5TreeBuilderHSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderHSupplement.h
@@ -133,17 +133,17 @@
     /**
      * Makes sure the buffers are large enough to be able to tokenize aLength
      * UTF-16 code units before having to make the buffers larger.
      *
      * @param aLength the number of UTF-16 code units to be tokenized before the
      *                next call to this method.
      * @return true if successful; false if out of memory
      */
-    bool EnsureBufferSpace(size_t aLength);
+    bool EnsureBufferSpace(int32_t aLength);
 
     void EnableViewSource(nsHtml5Highlighter* aHighlighter);
 
     void errStrayStartTag(nsIAtom* aName);
 
     void errStrayEndTag(nsIAtom* aName);
 
     void errUnclosedElements(int32_t aIndex, nsIAtom* aName);