Bug 598907 - crash [@ _purecall | nsGenericHTMLFormElement::IsDisabled() ]. r=smaug a=blocking
authorMounir Lamouri <mounir.lamouri@gmail.com>
Fri, 05 Nov 2010 18:15:05 +0100
changeset 56935 132b620273acca64b03c292090fd244992dbb9d5
parent 56934 92091fd140dfe9c8bf4347ffb94e88af7e81264a
child 56936 9ca441f29257effcd2a3d1a5d1209576ede2707c
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, blocking
bugs598907
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 598907 - crash [@ _purecall | nsGenericHTMLFormElement::IsDisabled() ]. r=smaug a=blocking
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLFieldSetElement.cpp
content/html/content/src/nsHTMLFieldSetElement.h
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2317,16 +2317,20 @@ nsGenericHTMLFormElement::nsGenericHTMLF
   : nsGenericHTMLElement(aNodeInfo)
   , mForm(nsnull)
   , mFieldSet(nsnull)
 {
 }
 
 nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
 {
+  if (mFieldSet) {
+    static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
+  }
+
   // Check that this element doesn't know anything about its form at this point.
   NS_ASSERTION(!mForm, "mForm should be null at this point!");
 }
 
 NS_IMPL_QUERY_INTERFACE_INHERITED1(nsGenericHTMLFormElement,
                                    nsGenericHTMLElement,
                                    nsIFormControl)
 
@@ -2934,23 +2938,30 @@ nsGenericHTMLFormElement::UpdateFieldSet
 
   for (parent = GetParent(); parent;
        prev = parent, parent = parent->GetParent()) {
     if (parent->IsHTML(nsGkAtoms::fieldset)) {
       nsHTMLFieldSetElement* fieldset =
         static_cast<nsHTMLFieldSetElement*>(parent);
 
       if (!prev || fieldset->GetFirstLegend() != prev) {
+        if (mFieldSet) {
+          static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
+        }
         mFieldSet = fieldset;
+        fieldset->AddElement(this);
         return;
       }
     }
   }
 
   // No fieldset found.
+  if (mFieldSet) {
+    static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
+  }
   mFieldSet = nsnull;
 }
 
 void
 nsGenericHTMLFormElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
 {
   if (!aNotify) {
     return;
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -870,16 +870,29 @@ public:
     UpdateFieldSet();
 
     // The disabled state may have change because the element might not be in
     // the first legend anymore.
     FieldSetDisabledChanged(nsEventStates(), aNotify);
   }
 
   /**
+   * This callback is called by a fieldset on all it's elements when it's being
+   * destroyed. When called, the elements should check that aFieldset is there
+   * first parent fieldset and null mFieldset in that case only.
+   *
+   * @param aFieldSet The fieldset being removed.
+   */
+  void ForgetFieldSet(nsIContent* aFieldset) {
+    if (mFieldSet == aFieldset) {
+      mFieldSet = nsnull;
+    }
+  }
+
+  /**
    * Returns if the control can be disabled.
    */
   PRBool CanBeDisabled() const;
 
 protected:
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
 
--- a/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -53,16 +53,20 @@ nsHTMLFieldSetElement::nsHTMLFieldSetEle
   , mFirstLegend(nsnull)
 {
   // <fieldset> is always barred from constraint validation.
   SetBarredFromConstraintValidation(PR_TRUE);
 }
 
 nsHTMLFieldSetElement::~nsHTMLFieldSetElement()
 {
+  PRUint32 length = mDependentElements.Length();
+  for (PRUint32 i=0; i<length; ++i) {
+    mDependentElements[i]->ForgetFieldSet(this);
+  }
 }
 
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHTMLFieldSetElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mElements)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
--- a/content/html/content/src/nsHTMLFieldSetElement.h
+++ b/content/html/content/src/nsHTMLFieldSetElement.h
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsHTMLFieldSetElement_h___
 #define nsHTMLFieldSetElement_h___
 
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLFieldSetElement.h"
 #include "nsIConstraintValidation.h"
+#include "nsTPtrArray.h"
 
 
 class nsHTMLFieldSetElement : public nsGenericHTMLFormElement,
                               public nsIDOMHTMLFieldSetElement,
                               public nsIConstraintValidation
 {
 public:
   using nsIConstraintValidation::GetValidationMessage;
@@ -82,16 +83,24 @@ public:
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_FIELDSET; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
 
   const nsIContent* GetFirstLegend() const { return mFirstLegend; }
 
+  void AddElement(nsGenericHTMLFormElement* aElement) {
+    mDependentElements.AppendElement(aElement);
+  }
+
+  void RemoveElement(nsGenericHTMLFormElement* aElement) {
+    mDependentElements.RemoveElement(aElement);
+  }
+
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLFieldSetElement,
                                            nsGenericHTMLFormElement)
 private:
 
   /**
    * Notify all elements (in mElements) that the first legend of the fieldset
    * has now changed.
    */
@@ -99,13 +108,16 @@ private:
 
   // This function is used to generate the nsContentList (listed form elements).
   static PRBool MatchListedElements(nsIContent* aContent, PRInt32 aNamespaceID,
                                     nsIAtom* aAtom, void* aData);
 
   // listed form controls elements.
   nsRefPtr<nsContentList> mElements;
 
+  // List of elements which have this fieldset as first fieldset ancestor.
+  nsTPtrArray<nsGenericHTMLFormElement> mDependentElements;
+
   nsIContent* mFirstLegend;
 };
 
 #endif /* nsHTMLFieldSetElement_h___ */