Fix for bug 393357 (nsDocument::mRadioGroups leaks its members). Patch by sharparrow1@yahoo.com, r/sr=bz, a=sicking.
authorpeterv@propagandism.org
Thu, 27 Sep 2007 11:17:32 -0700
changeset 6365 bc018280ac3e6507b1e1cd801979c1769e84b3d8
parent 6364 ee2237f2b44391ad3ae0551a50f8c6153bbe77ae
child 6366 8c017fca34e1fb22b5e80499958d1e224212ac44
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs393357
milestone1.9a9pre
Fix for bug 393357 (nsDocument::mRadioGroups leaks its members). Patch by sharparrow1@yahoo.com, r/sr=bz, a=sicking.
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -310,17 +310,17 @@ struct FindContentData
  * A struct that holds all the information about a radio group.
  */
 struct nsRadioGroupStruct
 {
   /**
    * A strong pointer to the currently selected radio button.
    */
   nsCOMPtr<nsIDOMHTMLInputElement> mSelectedRadioButton;
-  nsSmallVoidArray mRadioButtons;
+  nsCOMArray<nsIFormControl> mRadioButtons;
 };
 
 
 nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
 {
   mLength = -1;
   // Not reference counted to avoid circular references.
   // The document will tell us when its going away.
@@ -940,33 +940,30 @@ SubDocTraverser(PLDHashTable *table, PLD
     static_cast<nsCycleCollectionTraversalCallback*>(arg);
 
   cb->NoteXPCOMChild(entry->mKey);
   cb->NoteXPCOMChild(entry->mSubDocument);
 
   return PL_DHASH_NEXT;
 }
 
-PR_STATIC_CALLBACK(PRIntn)
-RadioGroupsTraverser(nsHashKey *aKey, void *aData, void* aClosure)
-{
-  nsRadioGroupStruct *entry = static_cast<nsRadioGroupStruct*>(aData);
+PR_STATIC_CALLBACK(PLDHashOperator)
+RadioGroupsTraverser(const nsAString& aKey, nsAutoPtr<nsRadioGroupStruct>& aData, void* aClosure)
+{
   nsCycleCollectionTraversalCallback *cb = 
     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
 
-  cb->NoteXPCOMChild(entry->mSelectedRadioButton);
-
-  nsSmallVoidArray &radioButtons = entry->mRadioButtons;
-  PRUint32 i, count = radioButtons.Count();
+  cb->NoteXPCOMChild(aData->mSelectedRadioButton);
+
+  PRUint32 i, count = aData->mRadioButtons.Count();
   for (i = 0; i < count; ++i) {
-    cb->NoteXPCOMChild(static_cast<nsIFormControl*>(radioButtons[i]));
-  }
-  
-
-  return kHashEnumerateNext;
+    cb->NoteXPCOMChild(aData->mRadioButtons[i]);
+  }
+
+  return PL_DHASH_NEXT;
 }
 
 PR_STATIC_CALLBACK(PLDHashOperator)
 BoxObjectTraverser(nsISupports* key, nsPIBoxObject* boxObject, void* userArg)
 {
   nsCycleCollectionTraversalCallback *cb = 
     static_cast<nsCycleCollectionTraversalCallback*>(userArg);
  
@@ -1081,16 +1078,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 nsresult
 nsDocument::Init()
 {
   if (mBindingManager || mCSSLoader || mNodeInfoManager || mScriptLoader) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
   mLinkMap.Init();
+  mRadioGroups.Init();
 
   // Force initialization.
   nsBindingManager *bindingManager = new nsBindingManager();
   NS_ENSURE_TRUE(bindingManager, NS_ERROR_OUT_OF_MEMORY);
   NS_ADDREF(mBindingManager = bindingManager);
 
   // The binding manager needs to come before everything but us in our
   // mutation observer list.
@@ -5036,27 +5034,25 @@ nsDocument::IsScriptEnabled()
 
 nsresult
 nsDocument::GetRadioGroup(const nsAString& aName,
                           nsRadioGroupStruct **aRadioGroup)
 {
   nsAutoString tmKey(aName);
   if(!IsCaseSensitive())
      ToLowerCase(tmKey); //should case-insensitive.
-  nsStringKey key(tmKey);
-  nsRadioGroupStruct *radioGroup =
-    static_cast<nsRadioGroupStruct *>(mRadioGroups.Get(&key));
-
-  if (!radioGroup) {
-    radioGroup = new nsRadioGroupStruct();
-    NS_ENSURE_TRUE(radioGroup, NS_ERROR_OUT_OF_MEMORY);
-    mRadioGroups.Put(&key, radioGroup);
-  }
+  if (mRadioGroups.Get(tmKey, aRadioGroup))
+    return NS_OK;
+
+  nsAutoPtr<nsRadioGroupStruct> radioGroup(new nsRadioGroupStruct());
+  NS_ENSURE_TRUE(radioGroup, NS_ERROR_OUT_OF_MEMORY);
+  NS_ENSURE_TRUE(mRadioGroups.Put(tmKey, radioGroup), NS_ERROR_OUT_OF_MEMORY);
 
   *aRadioGroup = radioGroup;
+  radioGroup.forget();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::SetCurrentRadioButton(const nsAString& aName,
                                   nsIDOMHTMLInputElement* aRadio)
 {
@@ -5152,49 +5148,46 @@ nsDocument::GetNextRadioButton(const nsA
     if (aPrevious) {
       if (--index < 0) {
         index = numRadios -1;
       }
     }
     else if (++index >= numRadios) {
       index = 0;
     }
-    radio = do_QueryInterface(static_cast<nsIFormControl*>(radioGroup->mRadioButtons.ElementAt(index)));
+    radio = do_QueryInterface(radioGroup->mRadioButtons[index]);
     NS_ASSERTION(radio, "mRadioButtons holding a non-radio button");
     radio->GetDisabled(&disabled);
   } while (disabled && radio != currentRadio);
 
   NS_IF_ADDREF(*aRadioOut = radio);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::AddToRadioGroup(const nsAString& aName,
                             nsIFormControl* aRadio)
 {
   nsRadioGroupStruct* radioGroup = nsnull;
   GetRadioGroup(aName, &radioGroup);
   if (radioGroup) {
-    radioGroup->mRadioButtons.AppendElement(aRadio);
-    NS_IF_ADDREF(aRadio);
+    radioGroup->mRadioButtons.AppendObject(aRadio);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::RemoveFromRadioGroup(const nsAString& aName,
                                  nsIFormControl* aRadio)
 {
   nsRadioGroupStruct* radioGroup = nsnull;
   GetRadioGroup(aName, &radioGroup);
   if (radioGroup) {
-    if (radioGroup->mRadioButtons.RemoveElement(aRadio)) {
-      NS_IF_RELEASE(aRadio);
-    }
+    radioGroup->mRadioButtons.RemoveObject(aRadio);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::WalkRadioGroup(const nsAString& aName,
                            nsIRadioVisitor* aVisitor,
@@ -5203,19 +5196,17 @@ nsDocument::WalkRadioGroup(const nsAStri
   nsRadioGroupStruct* radioGroup = nsnull;
   GetRadioGroup(aName, &radioGroup);
   if (!radioGroup) {
     return NS_OK;
   }
 
   PRBool stop = PR_FALSE;
   for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
-    aVisitor->Visit(static_cast<nsIFormControl *>
-                               (radioGroup->mRadioButtons.ElementAt(i)),
-                    &stop);
+    aVisitor->Visit(radioGroup->mRadioButtons[i], &stop);
     if (stop) {
       return NS_OK;
     }
   }
 
   return NS_OK;
 }
 
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -750,17 +750,17 @@ protected:
   nsWeakPtr mScopeObject;
 
   nsCOMPtr<nsIEventListenerManager> mListenerManager;
   nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
   nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
   nsRefPtr<nsScriptLoader> mScriptLoader;
   nsDocHeaderData* mHeaderData;
 
-  nsHashtable mRadioGroups;
+  nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
 
   // True if the document has been detached from its content viewer.
   PRPackedBool mIsGoingAway:1;
   // True if the document is being destroyed.
   PRPackedBool mInDestructor:1;
   // True if the document "page" is not hidden
   PRPackedBool mVisible:1;