Bug 615147. r=dbaron a=dveditz
authorMats Palmgren <matspal@gmail.com>
Sun, 30 Jan 2011 03:49:57 +0100
changeset 27320 2f8a379f58466e42759563fc2959cc3b60882cc0
parent 27319 b6efde698e76afb5f12cfdb6a0b4aec933fbe988
child 27321 59a1a0a2d9ff99bf327d596ed80553576e67dfc6
push id2656
push usermpalmgren@mozilla.com
push dateSun, 30 Jan 2011 02:50:46 +0000
reviewersdbaron, dveditz
bugs615147
milestone1.9.1.17pre
Bug 615147. r=dbaron a=dveditz
xpcom/string/src/nsSubstring.cpp
xpcom/string/src/nsTSubstring.cpp
--- a/xpcom/string/src/nsSubstring.cpp
+++ b/xpcom/string/src/nsSubstring.cpp
@@ -194,16 +194,19 @@ nsStringBuffer::Release()
 
   /**
    * Alloc returns a pointer to a new string header with set capacity.
    */
 nsStringBuffer*
 nsStringBuffer::Alloc(size_t size)
   {
     NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
+    NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(PRUint32(-1)) &&
+                 sizeof(nsStringBuffer) + size > size,
+                 "mStorageSize will truncate");
 
     nsStringBuffer *hdr =
         (nsStringBuffer *) malloc(sizeof(nsStringBuffer) + size);
     if (hdr)
       {
         STRING_STAT_INCREMENT(Alloc);
 
         hdr->mRefCount = 1;
@@ -214,22 +217,25 @@ nsStringBuffer::Alloc(size_t size)
   }
 
 nsStringBuffer*
 nsStringBuffer::Realloc(nsStringBuffer* hdr, size_t size)
   {
     STRING_STAT_INCREMENT(Realloc);
 
     NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
+    NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(PRUint32(-1)) &&
+                 sizeof(nsStringBuffer) + size > size,
+                 "mStorageSize will truncate");
 
     // no point in trying to save ourselves if we hit this assertion
     NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string");
 
     // Treat this as a release and addref for refcounting purposes, since we
-    // just asserted that the refcound is 1.  If we don't do that, refcount
+    // just asserted that the refcount is 1.  If we don't do that, refcount
     // logging will claim we've leaked all sorts of stuff.
     NS_LOG_RELEASE(hdr, 0, "nsStringBuffer");
     
     hdr = (nsStringBuffer*) realloc(hdr, sizeof(nsStringBuffer) + size);
     if (hdr) {
       NS_LOG_ADDREF(hdr, 1, "nsStringBuffer", sizeof(*hdr));
       hdr->mStorageSize = size;
     }
--- a/xpcom/string/src/nsTSubstring.cpp
+++ b/xpcom/string/src/nsTSubstring.cpp
@@ -92,20 +92,23 @@ PRBool
 nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint32* oldFlags )
   {
     // initialize to no old data
     *oldData = nsnull;
     *oldFlags = 0;
 
     size_type curCapacity = Capacity();
 
-    // If |capacity > size_type(-1)/2|, then our doubling algorithm may not be
+    // If |capacity > kMaxCapacity|, then our doubling algorithm may not be
     // able to allocate it.  Just bail out in cases like that.  We don't want
     // to be allocating 2GB+ strings anyway.
-    if (capacity > size_type(-1)/2) {
+    PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0);
+    const size_type kMaxCapacity =
+      (size_type(-1)/2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2;
+    if (capacity > kMaxCapacity) {
       // Also assert for |capacity| equal to |size_type(-1)|, since we use that value to
       // flag immutability.
       NS_ASSERTION(capacity != size_type(-1), "Bogus capacity");
       return PR_FALSE;
     }
 
     // |curCapacity == size_type(-1)| means that the buffer is immutable, so we
     // need to allocate a new buffer.  we cannot use the existing buffer even
@@ -113,25 +116,25 @@ nsTSubstring_CharT::MutatePrep( size_typ
 
     if (curCapacity != size_type(-1))
       {
         if (capacity <= curCapacity) {
           mFlags &= ~F_VOIDED;  // mutation clears voided flag
           return PR_TRUE;
         }
 
-        if (curCapacity > 0)
-          {
-            // use doubling algorithm when forced to increase available
-            // capacity.
-            PRUint32 temp = curCapacity;
-            while (temp < capacity)
-              temp <<= 1;
-            capacity = temp;
-          }
+        if (curCapacity > 0) {
+          // Use doubling algorithm when forced to increase available capacity.
+          size_type temp = curCapacity;
+          while (temp < capacity)
+            temp <<= 1;
+          NS_ASSERTION(NS_MIN(temp, kMaxCapacity) >= capacity,
+                       "should have hit the early return at the top");
+          capacity = NS_MIN(temp, kMaxCapacity);
+        }
       }
 
     //
     // several cases:
     //
     //  (1) we have a shared buffer (mFlags & F_SHARED)
     //  (2) we have an owned buffer (mFlags & F_OWNED)
     //  (3) we have a fixed buffer (mFlags & F_FIXED)