Bug 292940 partial OOM audit for nsStringArray and nsCStringArray r=darin, r=bsmedberg, sr=mrbkap, a=mtschrep thanks to ryanvm@gmail.com for unbitrotting
authortimeless@mozdev.org
Mon, 14 Jan 2008 13:01:40 -0800
changeset 10261 15e27c78b54c9d2865165f458226d95145b8a036
parent 10260 c99699c21855c24d7b4a79cef76a988d3bbc5915
child 10262 63a24f081916b720480800d69d1604bc8ad03494
push idunknown
push userunknown
push dateunknown
reviewersdarin, bsmedberg, mrbkap, mtschrep
bugs292940
milestone1.9b3pre
Bug 292940 partial OOM audit for nsStringArray and nsCStringArray r=darin, r=bsmedberg, sr=mrbkap, a=mtschrep thanks to ryanvm@gmail.com for unbitrotting
xpcom/glue/nsVoidArray.cpp
xpcom/glue/nsVoidArray.h
--- a/xpcom/glue/nsVoidArray.cpp
+++ b/xpcom/glue/nsVoidArray.cpp
@@ -731,20 +731,27 @@ nsStringArray::~nsStringArray(void)
 
 nsStringArray& 
 nsStringArray::operator=(const nsStringArray& other)
 {
   // Copy the pointers
   nsVoidArray::operator=(other);
 
   // Now copy the strings
-  for (PRInt32 i = Count() - 1; i >= 0; --i)
+  PRInt32 count = Count();
+  for (PRInt32 i = 0; i < count; ++i)
   {
     nsString* oldString = static_cast<nsString*>(other.ElementAt(i));
-    mImpl->mArray[i] = new nsString(*oldString);
+    nsString* newString = new nsString(*oldString);
+    if (!newString)
+    {
+      mImpl->mCount = i;
+      return *this;
+    }
+    mImpl->mArray[i] = newString;
   }
 
   return *this;
 }
 
 void 
 nsStringArray::StringAt(PRInt32 aIndex, nsAString& aString) const
 {
@@ -784,20 +791,21 @@ nsStringArray::IndexOf(const nsAString& 
   }
   return -1;
 }
 
 PRBool 
 nsStringArray::InsertStringAt(const nsAString& aString, PRInt32 aIndex)
 {
   nsString* string = new nsString(aString);
+  if (!string)
+    return PR_FALSE;
   if (nsVoidArray::InsertElementAt(string, aIndex))
-  {
     return PR_TRUE;
-  }
+
   delete string;
   return PR_FALSE;
 }
 
 PRBool
 nsStringArray::ReplaceStringAt(const nsAString& aString,
                                PRInt32 aIndex)
 {
@@ -918,33 +926,52 @@ nsStringArray::EnumerateBackwards(nsStri
 
 nsCStringArray::nsCStringArray(void)
   : nsVoidArray()
 {
 }
 
 // Parses a given string using the delimiter passed in and appends items
 // parsed to the array.
-void
+PRBool
 nsCStringArray::ParseString(const char* string, const char* delimiter)
 {
   if (string && *string && delimiter && *delimiter) {
     char *rest = strdup(string);
+    if (!rest)
+      return PR_FALSE;
     char *newStr = rest;
     char *token = NS_strtok(delimiter, &newStr);
 
+    PRInt32 count = Count();
     while (token) {
       if (*token) {
         /* calling AppendElement(void*) to avoid extra nsCString copy */
-        AppendElement(new nsCString(token));
+        nsCString *cstring = new nsCString(token);
+        if (cstring && !AppendElement(cstring)) {
+          // AppendElement failed, release and null cstring so we fall
+          // through to the case below.
+          delete cstring;
+          cstring = nsnull;
+        }
+        if (!cstring) {
+          // We've run out of memory. Remove all newly appended elements from
+          // our array so we don't leave ourselves in a partially added state.
+          // When we return, the array will be precisely as it was when this
+          // function was called.
+          RemoveElementsAt(count, Count() - count);
+          free(rest);
+          return PR_FALSE;
+        }
       }
       token = NS_strtok(delimiter, &newStr);
     }
     free(rest);
   }
+  return PR_TRUE;
 }
 
 nsCStringArray::nsCStringArray(PRInt32 aCount)
   : nsVoidArray(aCount)
 {
 }
 
 nsCStringArray::~nsCStringArray(void)
@@ -954,20 +981,27 @@ nsCStringArray::~nsCStringArray(void)
 
 nsCStringArray& 
 nsCStringArray::operator=(const nsCStringArray& other)
 {
   // Copy the pointers
   nsVoidArray::operator=(other);
 
   // Now copy the strings
-  for (PRInt32 i = Count() - 1; i >= 0; --i)
+  PRInt32 count = Count();
+  for (PRInt32 i = 0; i < count; ++i)
   {
     nsCString* oldString = static_cast<nsCString*>(other.ElementAt(i));
-    mImpl->mArray[i] = new nsCString(*oldString);
+    nsCString* newString = new nsCString(*oldString);
+    if (!newString)
+    {
+      mImpl->mCount = i;
+      return *this;
+    }
+    mImpl->mArray[i] = newString;
   }
 
   return *this;
 }
 
 void 
 nsCStringArray::CStringAt(PRInt32 aIndex, nsACString& aCString) const
 {
@@ -1029,20 +1063,21 @@ nsCStringArray::IndexOfIgnoreCase(const 
   return -1;
 }
 #endif
 
 PRBool 
 nsCStringArray::InsertCStringAt(const nsACString& aCString, PRInt32 aIndex)
 {
   nsCString* string = new nsCString(aCString);
+  if (!string)
+    return PR_FALSE;
   if (nsVoidArray::InsertElementAt(string, aIndex))
-  {
     return PR_TRUE;
-  }
+
   delete string;
   return PR_FALSE;
 }
 
 PRBool
 nsCStringArray::ReplaceCStringAt(const nsACString& aCString, PRInt32 aIndex)
 {
   nsCString* string = static_cast<nsCString*>(nsVoidArray::ElementAt(aIndex));
--- a/xpcom/glue/nsVoidArray.h
+++ b/xpcom/glue/nsVoidArray.h
@@ -270,17 +270,17 @@ public:
 
   nsCStringArray& operator=(const nsCStringArray& other);
 
   // Parses a given string using the delimiter passed in. If the array
   // already has some elements, items parsed from string will be appended 
   // to array. For example, array.ParseString("a,b,c", ","); will add strings
   // "a", "b" and "c" to the array. Parsing process has the same tokenizing 
   // behavior as strtok().  
-  void ParseString(const char* string, const char* delimiter);
+  PRBool ParseString(const char* string, const char* delimiter);
 
   PRInt32 Count(void) const {
     return nsVoidArray::Count();
   }
 
   void CStringAt(PRInt32 aIndex, nsACString& aCString) const;
   nsCString* CStringAt(PRInt32 aIndex) const;
   nsCString* operator[](PRInt32 aIndex) const { return CStringAt(aIndex); }