Regression-Fix (Re: security patches 1.5.0.9/2.0.0.1 issues for 1.7 branch)

Alexander Sack asac at jwsdot.com
Tue Jan 16 01:29:40 CET 2007


Eric Dorland wrote:
> * Alexander Sack (asac at debian.org) wrote:
>> Hi,
>>
>> somehow late, but here they are :):
>>
>> I uploaded 1.7 branch backports for issues announced with
>> 1.5.0.9/2.0.0.1 release.
>>
>> Note: Everything, but mfsa2006-74, does apply to firefox.
>>
>> Current patches can be found at:
>>    http://people.debian.org/~asac/backports-1.5.0.9.tar.gz
>>
>> Eric/Mike, can you prepare a firefox update and make it available
>> somewhere?
> 
> Untested builds are up at http://people.debian.org/~eric/mozilla. I'll
> let you blog about it Alexander, I'm going to bed. 
> 

OK, as you know there has been a regression. Unfortunately, it was not mailnews
only, but a general xul regression due to code I uncommented for testing and
just forgot to revert that later. Anyway, though we haven't had explicit reports
for crashes of updated mozilla-firefox, it definitly needs an update too before
we can release.

To summarize: All packages need a new upload to security queue.

Attached you find the updated patch:

  - 0015-MFSA-2006-68-CVE-2006-6497-Part-3-348304-with-regression.txt

which replaces the patch

  - 0015-MFSA-2006-68-CVE-2006-6497-Part-3-348304.txt

previously released.

For mozilla-firefox, the -regression-interdiff patch should apply to svn sarge
branch. Eric, you have time to provide package updates?

 - Alexander

-- 
 GPG messages preferred.   |  .''`.  ** Debian GNU/Linux **
 Alexander Sack            | : :' :      The  universal
 asac at jwsdot.com           | `. `'      Operating System
 http://www.asoftsite.org  |   `-    http://www.debian.org/
-------------- next part --------------
diff -u b/layout/xul/base/src/nsMenuFrame.cpp b/layout/xul/base/src/nsMenuFrame.cpp
--- b/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -2049,12 +2049,11 @@
   nsASyncMenuGeneration(nsIFrame* aFrame)
     : mWeakFrame(aFrame)
   {
-    // XXX: asac: implement this properly
-    //    nsIContent* content = aFrame ? aFrame->GetContent() : nsnull;
-    //    mDocument = content ? content->GetDocument() : nsnull;
+    nsIContent* content = aFrame ? aFrame->GetContent() : nsnull;
+    mDocument = content ? content->GetDocument() : nsnull;
     if (mDocument) {
           nsCOMPtr<nsIDocument_MOZILLA_1_7_BRANCH> doc17(do_QueryInterface(mDocument));
-          //doc17->BlockOnload();
+          doc17->BlockOnload();
     }
   }
 
@@ -2076,7 +2075,7 @@
     }
     if (mDocument) {
       nsCOMPtr<nsIDocument_MOZILLA_1_7_BRANCH> doc17(do_QueryInterface(mDocument));
-//      doc17->UnblockOnload();
+      doc17->UnblockOnload();
     }
   }
 
-------------- next part --------------
From 75b9e9f0e7b569e2ccb2acb2eada552911231efb Mon Sep 17 00:00:00 2001
From: Alexander Sack <asac at hanson.localdomain>
Date: Mon, 8 Jan 2007 03:40:38 +0100
Subject: [PATCH] MFSA 2006-68; CVE-2006-6497; Part 3; 348304

---
 content/base/public/nsIDocument.h        |   22 +++
 content/base/src/nsDocument.cpp          |   92 +++++++++++++
 content/base/src/nsDocument.h            |   21 +++-
 content/xul/content/src/nsXULElement.cpp |  172 ++++++++++++++----------
 layout/xul/base/src/nsMenuBarFrame.cpp   |   63 ++++++++--
 layout/xul/base/src/nsMenuFrame.cpp      |  212 ++++++++++++++++++++++++++----
 layout/xul/base/src/nsMenuFrame.h        |    1 +
 layout/xul/base/src/nsMenuPopupFrame.cpp |   73 ++++++++++-
 8 files changed, 544 insertions(+), 112 deletions(-)

diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h
index 529cfe2..5e523fa 100644
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -92,6 +92,10 @@ class nsIHTMLCSSStyleSheet;
 { 0x3000c2a4, 0xf7f1, 0x4636, \
   {0x9c, 0x6e, 0xd5, 0x38, 0x1b, 0xf0, 0x18, 0x8a} }
 
+#define NS_IDOCUMENT_MOZILLA_1_7_BRANCH_IID \
+{ 0x8c0ccaeb, 0x0b83, 0x46ee, \
+  { 0xbe, 0x2c, 0xbe, 0xf6, 0x32, 0xb6, 0x5b, 0xa0 } }
+
 // The base value for the content ID counter.
 // This counter is used by the document to 
 // assign a monotonically increasing ID to each content
@@ -628,6 +632,24 @@ protected:
   nsCOMPtr<nsISupports> mSecurityInfo;
 };
 
+class nsIDocument_MOZILLA_1_7_BRANCH : public nsIDocument
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_MOZILLA_1_7_BRANCH_IID)
+
+  /**
+   * [asac: backported from 1.8 branch]
+   * Methods that can be used to prevent onload firing while an event that
+   * should block onload is posted.  onload is guaranteed to not fire until
+   * either all calls to BlockOnload() have been matched by calls to
+   * UnblockOnload() or the load has been stopped altogether (by the user
+   * pressing the Stop button, say).  onload may fire synchronously from inside
+   * the UnblockOnload() call.
+   */
+  virtual void BlockOnload() = 0;
+  virtual void UnblockOnload() = 0;
+};
+
 
 /**
  * Helper class to automatically handle batching of document updates.  This
diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp
index 1495a1f..2133306 100644
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -272,6 +272,65 @@ nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument *aDocument,
   }
 }
 
+NS_IMPL_ISUPPORTS1(nsOnloadBlocker, nsIRequest)
+
+NS_IMETHODIMP
+nsOnloadBlocker::GetName(nsACString &aResult)
+{
+  aResult = "about:document-onload-blocker";
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::IsPending(PRBool *_retval)
+{
+  *_retval = PR_TRUE;
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::GetStatus(nsresult *status)
+{
+  *status = NS_OK;
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::Cancel(nsresult status)
+{
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::Suspend(void)
+{
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::Resume(void)
+{
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::GetLoadGroup(nsILoadGroup * *aLoadGroup)
+{
+  *aLoadGroup = nsnull;
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::SetLoadGroup(nsILoadGroup * aLoadGroup)
+{
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::GetLoadFlags(nsLoadFlags *aLoadFlags)
+{
+  *aLoadFlags = nsIRequest::LOAD_NORMAL;
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags)
+{
+  return NS_OK;
+}
+
+
 
 class nsDOMImplementation : public nsIDOMDOMImplementation,
                             public nsIPrivateDOMImplementation
@@ -630,6 +689,7 @@ PRBool gHaveXPathDOM = PR_FALSE;
 
 NS_INTERFACE_MAP_BEGIN(nsDocument)
   NS_INTERFACE_MAP_ENTRY(nsIDocument)
+  NS_INTERFACE_MAP_ENTRY(nsIDocument_MOZILLA_1_7_BRANCH)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDocument)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNSDocument)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentEvent)
@@ -691,6 +751,9 @@ nsDocument::Init()
   mNodeInfoManager = new nsNodeInfoManager();
   NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
 
+  mOnloadBlocker = new nsOnloadBlocker();
+  NS_ENSURE_TRUE(mOnloadBlocker, NS_ERROR_OUT_OF_MEMORY);
+
   return mNodeInfoManager->Init(this);
 }
 
@@ -3904,6 +3967,35 @@ nsDocument::RemoveEventListener(const nsAString& aType,
   return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
 }
 
+void
+nsDocument::BlockOnload()
+{
+  if (mOnloadBlockCount == 0) {
+    nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
+    if (loadGroup) {
+      loadGroup->AddRequest(mOnloadBlocker, nsnull);
+    }
+  }
+  ++mOnloadBlockCount;
+}
+
+void
+nsDocument::UnblockOnload()
+{
+  if (mOnloadBlockCount == 0) {
+    return;
+  }
+
+  --mOnloadBlockCount;
+
+  if (mOnloadBlockCount == 0) {
+    nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
+    if (loadGroup) {
+      loadGroup->RemoveRequest(mOnloadBlocker, nsnull, NS_OK);
+    }
+  }
+}
+
 NS_IMETHODIMP
 nsDocument::DispatchEvent(nsIDOMEvent* aEvent, PRBool *_retval)
 {
diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h
index 85b2a9e..f9db18e 100644
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -104,7 +104,7 @@ class nsIRadioVisitor;
 class nsIFormControl;
 class nsStyleSet;
 struct nsRadioGroupStruct;
-
+class nsOnloadBlocker;
 
 class nsDocHeaderData
 {
@@ -168,6 +168,17 @@ protected:
   void*         mScriptObject;
 };
 
+class nsOnloadBlocker : public nsIRequest
+{
+public:
+  nsOnloadBlocker() {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIREQUEST
+
+private:
+  ~nsOnloadBlocker() {}
+};
 
 // Base class for our document implementations.
 //
@@ -178,7 +189,7 @@ protected:
 // nsIDOMXMLDocument's. nsDocument's QI should *not* claim to support
 // nsIDOMXMLDocument unless someone writes a real implementation of
 // the interface.
-class nsDocument : public nsIDocument,
+class nsDocument : public nsIDocument_MOZILLA_1_7_BRANCH,
                    public nsIDOMXMLDocument, // inherits nsIDOMDocument
                    public nsIDOMNSDocument,
                    public nsIDOMDocumentEvent,
@@ -199,6 +210,9 @@ class nsDocument : public nsIDocument,
 public:
   NS_DECL_ISUPPORTS
 
+  virtual void BlockOnload();
+  virtual void UnblockOnload();
+
   virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
   virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup);
 
@@ -592,6 +606,9 @@ private:
   nsDocument& operator=(const nsDocument& aOther);
 
   nsXPathDocumentTearoff* mXPathDocument;
+
+  PRUint32 mOnloadBlockCount;
+  nsCOMPtr<nsIRequest> mOnloadBlocker;
 };
 
 
diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp
index 8686ecd..ad077ac 100644
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -619,18 +619,19 @@ nsXULElement::GetNodeType(PRUint16* aNodeType)
 NS_IMETHODIMP
 nsXULElement::GetParentNode(nsIDOMNode** aParentNode)
 {
+    nsCOMPtr<nsIDocument> doc = mDocument; // hard ref
     if (GetParent()) {
         return CallQueryInterface(GetParent(), aParentNode);
     }
 
-    if (mDocument) {
+    if (doc) {
         nsIContent *thisIContent = this;
 
-        if (mDocument->GetRootContent() == thisIContent) {
+        if (doc->GetRootContent() == thisIContent) {
             // If we don't have a parent, and we're the root content
             // of the document, DOM says that our parent is the
             // document.
-            return CallQueryInterface(mDocument, aParentNode);
+            return CallQueryInterface(doc, aParentNode);
         }
     }
 
@@ -885,6 +886,7 @@ nsXULElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
     nsresult rv;
 
     nsCOMPtr<nsIContent> result;
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
     // If we have a prototype, so will our clone.
     if (mPrototype) {
@@ -900,7 +902,7 @@ nsXULElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
 
         // XXX setting document on nodes not in a document so XBL will bind
         // and chrome won't break. Make XBL bind to document-less nodes!
-        result->SetDocument(mDocument, PR_TRUE, PR_TRUE);
+        result->SetDocument(doc, PR_TRUE, PR_TRUE);
     }
 
     // Copy attributes
@@ -1373,7 +1375,8 @@ nsXULElement::GetLazyState(LazyState aFlag, PRBool& aResult)
 NS_IMETHODIMP
 nsXULElement::AddScriptEventListener(nsIAtom* aName, const nsAString& aValue)
 {
-    if (! mDocument)
+    nsCOMPtr<nsIDocument> doc = mDocument;
+    if (! doc)
         return NS_OK; // XXX
 
     nsresult rv;
@@ -1383,10 +1386,10 @@ nsXULElement::AddScriptEventListener(nsIAtom* aName, const nsAString& aValue)
 
     nsCOMPtr<nsIEventListenerManager> manager;
 
-    nsIContent *root = mDocument->GetRootContent();
+    nsIContent *root = doc->GetRootContent();
     nsCOMPtr<nsIContent> content(do_QueryInterface(NS_STATIC_CAST(nsIStyledContent*, this)));
     if ((!root || root == content) && !NodeInfo()->Equals(nsXULAtoms::overlay)) {
-        nsIScriptGlobalObject *global = mDocument->GetScriptGlobalObject();
+        nsIScriptGlobalObject *global = doc->GetScriptGlobalObject();
 
         nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(global);
         if (! receiver)
@@ -1404,7 +1407,7 @@ nsXULElement::AddScriptEventListener(nsIAtom* aName, const nsAString& aValue)
     if (NS_FAILED(rv)) return rv;
 
     return manager->AddScriptEventListener(target, aName, aValue, defer,
-                                           !nsContentUtils::IsChromeDoc(mDocument));
+                                           !nsContentUtils::IsChromeDoc(doc));
 }
 
 nsresult
@@ -1456,6 +1459,8 @@ nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
     nsresult rv;
     JSObject* scopeObject;
 
+    nsCOMPtr<nsIDocument> doc = mDocument;
+
     XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheSets);
 
     nsIScriptContext *context;
@@ -1472,7 +1477,7 @@ nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
         // keeps the global object alive, so if we use this document's
         // global object, we'll be putting something in the prototype
         // that protects this document's global object from GC.
-        nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mDocument);
+        nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
         NS_ENSURE_TRUE(xuldoc, NS_ERROR_UNEXPECTED);
 
         nsCOMPtr<nsIXULPrototypeDocument> protodoc;
@@ -1574,17 +1579,19 @@ void
 nsXULElement::SetDocument(nsIDocument* aDocument, PRBool aDeep,
                           PRBool aCompileEventHandlers)
 {
-    if (aDocument != mDocument) {
-        if (mDocument) {
+    nsCOMPtr<nsIDocument> doc = mDocument;
+
+    if (aDocument != doc) {
+        if (doc) {
           // Notify XBL- & nsIAnonymousContentCreator-generated
           // anonymous content that the document is changing.
-          nsIBindingManager *bindingManager = mDocument->GetBindingManager();
+          nsIBindingManager *bindingManager = doc->GetBindingManager();
           NS_ASSERTION(bindingManager, "no binding manager");
           if (bindingManager) {
-            bindingManager->ChangeDocumentFor(this, mDocument, aDocument);
+            bindingManager->ChangeDocumentFor(this, doc, aDocument);
           }
 
-          nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(mDocument));
+          nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc));
           nsDoc->SetBoxObjectFor(this, nsnull);
         }
 
@@ -1608,8 +1615,9 @@ nsXULElement::SetDocument(nsIDocument* aDocument, PRBool aDeep,
         mListenerManager = nsnull;
 
         nsIContent::SetDocument(aDocument, aDeep, aCompileEventHandlers);
+        doc = mDocument;
 
-        if (mDocument) {
+        if (doc) {
             // When we SetDocument(), we're either adding an element
             // into the document that wasn't there before, or we're
             // moving the element from one document to
@@ -1711,6 +1719,7 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify,
 {
     nsresult rv = EnsureContentsGenerated();
     NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
     NS_PRECONDITION(nsnull != aKid, "null ptr");
 
@@ -1722,7 +1731,7 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify,
 
     PRBool isAppend = aIndex == mAttrsAndChildren.ChildCount();
 
-    mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, aNotify);
+    mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
 
     if (aIndex > mAttrsAndChildren.ChildCount()) {
       // XXX This *does* happen, probably a bug in the overlay code.
@@ -1736,14 +1745,14 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify,
     aKid->SetParent(this);
     //nsRange::OwnerChildInserted(this, aIndex);
 
-    if (mDocument) {
-        aKid->SetDocument(mDocument, aDeepSetDocument, PR_TRUE);
+    if (doc) {
+        aKid->SetDocument(doc, aDeepSetDocument, PR_TRUE);
 
         if (aNotify) {
             if (isAppend) {
-                mDocument->ContentAppended(this, aIndex);
+                doc->ContentAppended(this, aIndex);
             } else {
-                mDocument->ContentInserted(this, aKid, aIndex);
+                doc->ContentInserted(this, aKid, aIndex);
             }
         }
 
@@ -1769,6 +1778,7 @@ nsXULElement::ReplaceChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify,
 {
     nsresult rv = EnsureContentsGenerated();
     NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
     NS_PRECONDITION(nsnull != aKid, "null ptr");
     if (!aKid)
@@ -1783,18 +1793,18 @@ nsXULElement::ReplaceChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify,
     if (oldKid == aKid)
         return NS_OK;
 
-    mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, aNotify);
+    mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
     
     mAttrsAndChildren.ReplaceChildAt(aKid, aIndex);
 
     aKid->SetParent(this);
     //nsRange::OwnerChildReplaced(this, aIndex, oldKid);
 
-    if (mDocument) {
-        aKid->SetDocument(mDocument, aDeepSetDocument, PR_TRUE);
+    if (doc) {
+        aKid->SetDocument(doc, aDeepSetDocument, PR_TRUE);
 
         if (aNotify) {
-            mDocument->ContentReplaced(this, oldKid, aKid, aIndex);
+            doc->ContentReplaced(this, oldKid, aKid, aIndex);
         }
         if (HasMutationListeners(this,
                                  NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED)) {
@@ -1823,10 +1833,11 @@ nsXULElement::AppendChildTo(nsIContent* aKid, PRBool aNotify,
 {
     nsresult rv = EnsureContentsGenerated();
     NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
     NS_PRECONDITION((nsnull != aKid) && (aKid != NS_STATIC_CAST(nsIStyledContent*, this)), "null ptr");
 
-    mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, aNotify);
+    mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
 
     rv = mAttrsAndChildren.AppendChild(aKid);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1834,11 +1845,11 @@ nsXULElement::AppendChildTo(nsIContent* aKid, PRBool aNotify,
     aKid->SetParent(this);
     // ranges don't need adjustment since new child is at end of list
 
-    if (mDocument) {
-        aKid->SetDocument(mDocument, aDeepSetDocument, PR_TRUE);
+    if (doc) {
+        aKid->SetDocument(doc, aDeepSetDocument, PR_TRUE);
 
         if (aNotify) {
-            mDocument->ContentAppended(this,
+            doc->ContentAppended(this,
                                        mAttrsAndChildren.ChildCount() - 1);
         }
 
@@ -1861,6 +1872,7 @@ nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
 {
     nsresult rv = EnsureContentsGenerated();
     NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
     nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.ChildAt(aIndex);
     NS_ENSURE_TRUE(oldKid, NS_ERROR_FAILURE);
@@ -1869,7 +1881,7 @@ nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
 
     nsMutationGuard guard;
 
-    mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, aNotify);
+    mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
 
     if (HasMutationListeners(this, NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
       nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEREMOVED, oldKid);
@@ -1949,8 +1961,8 @@ nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
 
     mAttrsAndChildren.RemoveChildAt(aIndex);
     //nsRange::OwnerChildRemoved(this, aIndex, oldKid);
-    if (aNotify && mDocument) {
-        mDocument->ContentRemoved(this, oldKid, aIndex);
+    if (aNotify && doc) {
+        doc->ContentRemoved(this, oldKid, aIndex);
     }
 
     if (newCurrentIndex == -2)
@@ -1972,7 +1984,7 @@ nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
     }
 
     if (fireSelectionHandler && GetDocument()) {
-      nsCOMPtr<nsIDOMDocumentEvent> doc(do_QueryInterface(mDocument));
+      nsCOMPtr<nsIDOMDocumentEvent> doc(do_QueryInterface(doc));
       nsCOMPtr<nsIDOMEvent> event;
       doc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
       nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
@@ -2033,10 +2045,11 @@ nsXULElement::GetExistingAttrNameFromQName(const nsAString& aStr) const
 void
 nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
 {
+    nsCOMPtr<nsIDocument> doc = mDocument;
     // If someone changes the accesskey, unregister the old one
     //
-    if (mDocument && !aOldValue.IsEmpty()) {
-        nsIPresShell *shell = mDocument->GetShellAt(0);
+    if (doc && !aOldValue.IsEmpty()) {
+        nsIPresShell *shell = doc->GetShellAt(0);
 
         if (shell) {
             PRBool validElement = PR_TRUE;
@@ -2072,11 +2085,13 @@ nsresult
 nsXULElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName, nsIAtom* aPrefix,
                       const nsAString& aValue, PRBool aNotify)
 {
+    nsCOMPtr<nsIDocument> doc = mDocument;
+
     nsAutoString oldValue;
     PRBool hasListeners = PR_FALSE;
     PRBool modification = PR_FALSE;
 
-    if (mDocument) {
+    if (doc) {
         PRBool isAccessKey = aName == nsXULAtoms::accesskey &&
                              aNamespaceID == kNameSpaceID_None;
         hasListeners = nsGenericElement::HasMutationListeners(this,
@@ -2180,9 +2195,11 @@ nsXULElement::SetAttrAndNotify(PRInt32 aNamespaceID,
         NS_STATIC_CAST(PRUint8, nsIDOMMutationEvent::MODIFICATION) :
         NS_STATIC_CAST(PRUint8, nsIDOMMutationEvent::ADDITION);
 
-    mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, aNotify);
-    if (aNotify && mDocument) {
-        mDocument->AttributeWillChange(this, aNamespaceID, aAttribute);
+    nsCOMPtr<nsIDocument> doc = mDocument;
+
+    mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
+    if (aNotify && doc) {
+        doc->AttributeWillChange(this, aNamespaceID, aAttribute);
     }
 
     if (aNamespaceID == kNameSpaceID_None) {
@@ -2200,9 +2217,9 @@ nsXULElement::SetAttrAndNotify(PRInt32 aNamespaceID,
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    if (mDocument) {
+    if (doc) {
         nsCOMPtr<nsIXBLBinding> binding;
-        mDocument->GetBindingManager()->GetBinding(this, getter_AddRefs(binding));
+        doc->GetBindingManager()->GetBinding(this, getter_AddRefs(binding));
         if (binding) {
             binding->AttributeChanged(aAttribute, aNamespaceID, PR_FALSE, aNotify);
         }
@@ -2237,7 +2254,7 @@ nsXULElement::SetAttrAndNotify(PRInt32 aNamespaceID,
         }
 
         if (aNotify) {
-            mDocument->AttributeChanged(this, aNamespaceID, aAttribute, modType);
+            doc->AttributeChanged(this, aNamespaceID, aAttribute, modType);
         }
     }
 
@@ -2307,6 +2324,7 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
 {
     NS_ASSERTION(nsnull != aName, "must have attribute name");
     nsresult rv;
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
     // Because It's Hard to maintain a magic ``unset'' value in
     // the local attributes, we'll fault all the attributes,
@@ -2343,9 +2361,9 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
     nsAutoString oldValue;
     GetAttr(aNameSpaceID, aName, oldValue);
 
-    mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, aNotify);
-    if (aNotify && mDocument) {
-        mDocument->AttributeWillChange(this, aNameSpaceID, aName);
+    mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
+    if (aNotify && doc) {
+        doc->AttributeWillChange(this, aNameSpaceID, aName);
     }
 
     PRBool hasMutationListeners =
@@ -2379,13 +2397,13 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
 
         // Check to see if the OBSERVES attribute is being unset.  If so, we
         // need to remove our broadcaster goop completely.
-        if (mDocument && (aName == nsXULAtoms::observes ||
-                          aName == nsXULAtoms::command)) {
-            nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(mDocument);
+        if (doc && (aName == nsXULAtoms::observes ||
+                    aName == nsXULAtoms::command)) {
+            nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(doc);
             if (xuldoc) {
                 // Do a getElementById to retrieve the broadcaster
                 nsCOMPtr<nsIDOMElement> broadcaster;
-                nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
+                nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
                 domDoc->GetElementById(oldValue, getter_AddRefs(broadcaster));
                 if (broadcaster) {
                     xuldoc->RemoveBroadcastListenerFor(broadcaster, this,
@@ -2395,7 +2413,7 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
         }
     }
 
-    if (mDocument) {
+    if (doc) {
         if (hasMutationListeners) {
             nsCOMPtr<nsIDOMEventTarget> node(do_QueryInterface(NS_STATIC_CAST(nsIContent *, this)));
             nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED, node);
@@ -2413,12 +2431,12 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
         }
 
         nsCOMPtr<nsIXBLBinding> binding;
-        mDocument->GetBindingManager()->GetBinding(this, getter_AddRefs(binding));
+        doc->GetBindingManager()->GetBinding(this, getter_AddRefs(binding));
         if (binding)
             binding->AttributeChanged(aName, aNameSpaceID, PR_TRUE, aNotify);
 
         if (aNotify) {
-            mDocument->AttributeChanged(this, aNameSpaceID, aName,
+            doc->AttributeChanged(this, aNameSpaceID, aName,
                                         nsIDOMMutationEvent::REMOVAL);
         }
     }
@@ -2550,6 +2568,7 @@ nsXULElement::List(FILE* out, PRInt32 aIndent) const
     NS_PRECONDITION(mDocument != nsnull, "bad content");
 
     PRUint32 i;
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
     rdf_Indent(out, aIndent);
     fputs("<XUL", out);
@@ -2605,8 +2624,8 @@ nsXULElement::List(FILE* out, PRInt32 aIndent) const
     }
     fputs(">\n", out);
 
-    if (mDocument) {
-        nsIBindingManager *bindingManager = mDocument->GetBindingManager();
+    if (doc) {
+        nsIBindingManager *bindingManager = doc->GetBindingManager();
         if (bindingManager) {
             nsCOMPtr<nsIDOMNodeList> anonymousChildren;
             bindingManager->GetAnonymousNodesFor(NS_STATIC_CAST(nsIContent*, NS_CONST_CAST(nsXULElement*, this)),
@@ -2677,6 +2696,7 @@ nsXULElement::HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent,
     PRBool retarget = PR_FALSE;
     PRBool externalDOMEvent = PR_FALSE;
     nsCOMPtr<nsIDOMEventTarget> oldTarget;
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
     nsIDOMEvent* domEvent = nsnull;
     if (NS_EVENT_FLAG_INIT & aFlags) {
@@ -2686,7 +2706,7 @@ nsXULElement::HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent,
             nsAutoString command;
             GetAttr(kNameSpaceID_None, nsXULAtoms::command, command);
             if (!command.IsEmpty()) {
-                nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mDocument));
+                nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
                 nsCOMPtr<nsIDOMElement> commandElt;
                 domDoc->GetElementById(command, getter_AddRefs(commandElt));
                 nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
@@ -2785,8 +2805,8 @@ nsXULElement::HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent,
 
     // determine the parent:
     nsCOMPtr<nsIContent> parent;
-    if (mDocument) {
-        nsIBindingManager* bindingManager = mDocument->GetBindingManager();
+    if (doc) {
+        nsIBindingManager* bindingManager = doc->GetBindingManager();
         if (bindingManager) {
             // we have a binding manager -- do we have an anonymous parent?
             bindingManager->GetInsertionParent(this, getter_AddRefs(parent));
@@ -2842,8 +2862,8 @@ nsXULElement::HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent,
         if (parent) {
             parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, aFlags & NS_EVENT_CAPTURE_MASK, aEventStatus);
         }
-        else if (mDocument != nsnull) {
-            ret = mDocument->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
+        else if (doc != nsnull) {
+            ret = doc->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
                                             aFlags & NS_EVENT_CAPTURE_MASK, aEventStatus);
         }
     }
@@ -2881,10 +2901,10 @@ nsXULElement::HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent,
             ret = parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
                                          aFlags & NS_EVENT_BUBBLE_MASK, aEventStatus);
         }
-        else if (mDocument != nsnull) {
+        else if (doc != nsnull) {
             // We must be the document root. The event should bubble to the
             // document.
-            ret = mDocument->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
+            ret = doc->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
                                             aFlags & NS_EVENT_BUBBLE_MASK, aEventStatus);
         }
     }
@@ -2943,9 +2963,10 @@ nsXULElement::GetBaseURI() const
 {
     // XXX TODO, should share the impl with nsGenericElement
     nsIURI *base;
+    nsCOMPtr<nsIDocument> doc = mDocument;
 
-    if (mDocument) {
-        base = mDocument->GetBaseURI();
+    if (doc) {
+        base = doc->GetBaseURI();
         NS_IF_ADDREF(base);
     } else {
         base = nsnull;
@@ -3281,9 +3302,11 @@ nsXULElement::GetClassAttributeName() const
 NS_IMETHODIMP
 nsXULElement::GetControllers(nsIControllers** aResult)
 {
+    nsCOMPtr<nsIDocument> doc = mDocument;
+
     if (! Controllers()) {
-        NS_PRECONDITION(mDocument != nsnull, "no document");
-        if (! mDocument)
+        NS_PRECONDITION(doc != nsnull, "no document");
+        if (! doc)
             return NS_ERROR_NOT_INITIALIZED;
 
         nsresult rv;
@@ -3295,7 +3318,7 @@ nsXULElement::GetControllers(nsIControllers** aResult)
         if (NS_FAILED(rv)) return rv;
 
         // Set the command dispatcher on the new controllers object
-        nsCOMPtr<nsIDOMXULDocument> domxuldoc = do_QueryInterface(mDocument);
+        nsCOMPtr<nsIDOMXULDocument> domxuldoc = do_QueryInterface(doc);
         NS_ASSERTION(domxuldoc != nsnull, "not an nsIDOMXULDocument");
         if (! domxuldoc)
             return NS_ERROR_UNEXPECTED;
@@ -3317,11 +3340,12 @@ NS_IMETHODIMP
 nsXULElement::GetBoxObject(nsIBoxObject** aResult)
 {
   *aResult = nsnull;
+  nsCOMPtr<nsIDocument> doc = mDocument;
 
-  if (!mDocument)
+  if (!doc)
     return NS_ERROR_FAILURE;
 
-  nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(mDocument));
+  nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc));
   return nsDoc->GetBoxObjectFor(this, aResult);
 }
 
@@ -3811,19 +3835,20 @@ nsXULElement::IsAncestor(nsIDOMNode* aParentNode, nsIDOMNode* aChildNode)
 NS_IMETHODIMP
 nsXULElement::Focus()
 {
+    nsCOMPtr<nsIDocument> doc = mDocument;
     if (!nsGenericElement::ShouldFocus(this)) {
         return NS_OK;
     }
 
     // What kind of crazy tries to focus an element without a doc?
-    if (!mDocument)
+    if (!doc)
         return NS_OK;
 
     // Obtain a presentation context and then call SetFocus.
-    if (mDocument->GetNumberOfShells() == 0)
+    if (doc->GetNumberOfShells() == 0)
         return NS_OK;
 
-    nsIPresShell *shell = mDocument->GetShellAt(0);
+    nsIPresShell *shell = doc->GetShellAt(0);
 
     // Retrieve the context
     nsCOMPtr<nsIPresContext> presContext;
@@ -3838,15 +3863,16 @@ nsXULElement::Focus()
 NS_IMETHODIMP
 nsXULElement::Blur()
 {
+    nsCOMPtr<nsIDocument> doc = mDocument;
     // What kind of crazy tries to blur an element without a doc?
-    if (!mDocument)
+    if (!doc)
         return NS_OK;
 
     // Obtain a presentation context and then call SetFocus.
-    if (mDocument->GetNumberOfShells() == 0)
+    if (doc->GetNumberOfShells() == 0)
         return NS_OK;
 
-    nsIPresShell *shell = mDocument->GetShellAt(0);
+    nsIPresShell *shell = doc->GetShellAt(0);
 
     // Retrieve the context
     nsCOMPtr<nsIPresContext> presContext;
diff --git a/layout/xul/base/src/nsMenuBarFrame.cpp b/layout/xul/base/src/nsMenuBarFrame.cpp
index c23aeff..d408d76 100644
--- a/layout/xul/base/src/nsMenuBarFrame.cpp
+++ b/layout/xul/base/src/nsMenuBarFrame.cpp
@@ -373,11 +373,21 @@ nsMenuBarFrame::ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFl
   nsIMenuFrame* result = FindMenuWithShortcut(aKeyEvent);
   if (result) {
     // We got one!
+    nsWeakFrame weakFrame(this);
+    nsIFrame* frame = nsnull;
+    CallQueryInterface(result, &frame);
+    nsWeakFrame weakResult(frame);
     aHandledFlag = PR_TRUE;
     SetActive(PR_TRUE);
-    SetCurrentMenuItem(result);
-    result->OpenMenu(PR_TRUE);
-    result->SelectFirstItem();
+    if (weakFrame.IsAlive()) {
+      SetCurrentMenuItem(result);
+    }
+    if (weakResult.IsAlive()) {
+      result->OpenMenu(PR_TRUE);
+      if (weakResult.IsAlive()) {
+        result->SelectFirstItem();
+      }
+    }
   }
 
   return NS_OK;
@@ -391,6 +401,7 @@ nsMenuBarFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
   if (!mCurrentMenu)
     return NS_OK;
   
+  nsWeakFrame weakFrame(this);
   PRBool isContainer = PR_FALSE;
   PRBool isOpen = PR_FALSE;
   mCurrentMenu->MenuIsContainer(isContainer);
@@ -414,8 +425,13 @@ nsMenuBarFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
       GetNextMenuItem(mCurrentMenu, &nextItem);
     else GetPreviousMenuItem(mCurrentMenu, &nextItem);
 
-    SetCurrentMenuItem(nextItem);
+    nsIFrame* nextFrame = nsnull;
     if (nextItem) {
+      CallQueryInterface(nextItem, &nextFrame);
+    }
+    nsWeakFrame weakNext(nextFrame);
+    SetCurrentMenuItem(nextItem);
+    if (weakNext.IsAlive()) {
       PRBool nextIsOpen;
       nextItem->MenuIsOpen(nextIsOpen);
       if (nextIsOpen) {
@@ -428,6 +444,16 @@ nsMenuBarFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
     // Open the menu and select its first item.
     mCurrentMenu->OpenMenu(PR_TRUE);
     mCurrentMenu->SelectFirstItem();
+    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
+    nsIFrame* frame = nsnull;
+    CallQueryInterface(mCurrentMenu, &frame);
+    nsWeakFrame weakCurrentMenu(frame);
+    nsIMenuFrame* currentMenu = mCurrentMenu;
+     // Open the menu and select its first item.
+    currentMenu->OpenMenu(PR_TRUE);
+    if (weakCurrentMenu.IsAlive()) {
+      currentMenu->SelectFirstItem();
+    }
   }
 
   return NS_OK;
@@ -555,18 +581,31 @@ NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
   if (nsMenuFrame::IsContextMenuActive())
     return NS_OK;
 
+  nsWeakFrame weakFrame(this);
+
   // Unset the current child.
   if (mCurrentMenu) {
-    mCurrentMenu->MenuIsOpen(wasOpen);
-    mCurrentMenu->SelectMenu(PR_FALSE);
-    if (wasOpen)
-      mCurrentMenu->OpenMenu(PR_FALSE);
+    nsIFrame* frame = nsnull;
+    CallQueryInterface(mCurrentMenu, &frame);
+    nsWeakFrame weakCurrentMenu(frame);
+    nsIMenuFrame* currentMenu = mCurrentMenu;
+    currentMenu->MenuIsOpen(wasOpen);
+    currentMenu->SelectMenu(PR_FALSE);
+    if (wasOpen && weakCurrentMenu.IsAlive()) {
+      currentMenu->OpenMenu(PR_FALSE);
+    }
   }
+  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
 
   // Set the new child.
   if (aMenuItem) {
+    nsIFrame* newMenu = nsnull;
+    CallQueryInterface(aMenuItem, &newMenu);
+    nsWeakFrame weakNewMenu(newMenu);
     aMenuItem->SelectMenu(PR_TRUE);
+    NS_ENSURE_TRUE(weakNewMenu.IsAlive(), NS_OK);
     aMenuItem->MarkAsGenerated(); // Have the menu building. Get it ready to be shown.
+    NS_ENSURE_TRUE(weakNewMenu.IsAlive(), NS_OK);
 
     PRBool isDisabled = PR_FALSE;
     aMenuItem->MenuIsDisabled(isDisabled);
@@ -575,6 +614,7 @@ NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
     ClearRecentlyRolledUp();
   }
 
+  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
   mCurrentMenu = aMenuItem;
 
   return NS_OK;
@@ -587,6 +627,7 @@ nsMenuBarFrame::Escape(PRBool& aHandledFlag)
   if (!mCurrentMenu)
     return NS_OK;
 
+  nsWeakFrame weakFrame(this);
   // See if our menu is open.
   PRBool isOpen = PR_FALSE;
   mCurrentMenu->MenuIsOpen(isOpen);
@@ -594,10 +635,12 @@ nsMenuBarFrame::Escape(PRBool& aHandledFlag)
     // Let the child menu handle this.
     aHandledFlag = PR_FALSE;
     mCurrentMenu->Escape(aHandledFlag);
+    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
     if (!aHandledFlag) {
       // Close up this menu but keep our current menu item
       // designation.
       mCurrentMenu->OpenMenu(PR_FALSE);
+      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
     }
 	if (nsMenuFrame::sDismissalListener)
       nsMenuFrame::sDismissalListener->Unregister();
@@ -606,6 +649,7 @@ nsMenuBarFrame::Escape(PRBool& aHandledFlag)
 
   // Clear our current menu item if we've got one.
   SetCurrentMenuItem(nsnull);
+  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
 
   SetActive(PR_FALSE);
 
@@ -670,8 +714,9 @@ nsMenuBarFrame::HideChain()
   if (nsMenuFrame::sDismissalListener)
     nsMenuFrame::sDismissalListener->Unregister();
 
+  nsWeakFrame weakFrame(this);
   ClearRecentlyRolledUp();
-  if (mCurrentMenu) {
+  if (mCurrentMenu && weakFrame.IsAlive()) {
     mCurrentMenu->ActivateMenu(PR_FALSE);
     mCurrentMenu->SelectMenu(PR_FALSE);
     mRecentRollupMenu = mCurrentMenu;
diff --git a/layout/xul/base/src/nsMenuFrame.cpp b/layout/xul/base/src/nsMenuFrame.cpp
index bcaa6b9..c542a35 100644
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -86,6 +86,8 @@
 #include "nsIEventStateManager.h"
 #include "nsITimerInternal.h"
 #include "nsContentUtils.h"
+#include "nsIEventQueueService.h"
+#include "nsIServiceManager.h"
 
 #define NS_MENU_POPUP_LIST_INDEX   0
 
@@ -93,6 +95,8 @@
 #define NSCONTEXTMENUISMOUSEUP 1
 #endif
 
+static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
+
 static PRInt32 gEatMouseMove = PR_FALSE;
 
 nsMenuDismissalListener* nsMenuFrame::sDismissalListener = nsnull;
@@ -180,6 +184,37 @@ nsMenuFrame::SetParent(const nsIFrame* aParent)
   return NS_OK;
 }
 
+struct nsASyncMenuInitialization : public PLEvent
+{
+  nsASyncMenuInitialization(nsIFrame* aFrame)
+    : mWeakFrame(aFrame)
+  {
+  }
+
+  void HandleEvent() {
+    if (mWeakFrame.IsAlive()) {
+      nsIMenuFrame* imenu = nsnull;
+      CallQueryInterface(mWeakFrame.GetFrame(), &imenu);
+      if (imenu) {
+        nsMenuFrame* menu = NS_STATIC_CAST(nsMenuFrame*, imenu);
+        menu->UpdateMenuType(menu->GetPresContext());
+      }
+    }
+  }
+
+  nsWeakFrame mWeakFrame;
+};
+
+static void* PR_CALLBACK HandleASyncMenuInitialization(PLEvent* aEvent)
+{
+  NS_STATIC_CAST(nsASyncMenuInitialization*, aEvent)->HandleEvent();
+  return nsnull;
+}
+static void PR_CALLBACK DestroyASyncMenuInitialization(PLEvent* aEvent)
+{
+  delete NS_STATIC_CAST(nsASyncMenuInitialization*, aEvent);
+}
+
 NS_IMETHODIMP
 nsMenuFrame::Init(nsIPresContext*  aPresContext,
                      nsIContent*      aContent,
@@ -199,9 +234,6 @@ nsMenuFrame::Init(nsIPresContext*  aPresContext,
     currFrame = currFrame->GetParent();
   }
 
-  // Do the type="checkbox" magic
-  UpdateMenuType(aPresContext);
-
   //load the display strings for the keyboard accelerators, but only once
   if (gRefCnt++ == 0) {
     
@@ -238,6 +270,24 @@ nsMenuFrame::Init(nsIPresContext*  aPresContext,
   
   BuildAcceleratorText();
   
+  nsCOMPtr<nsIEventQueueService> eventService =
+    do_GetService(kEventQueueServiceCID);
+  NS_ENSURE_TRUE(eventService, PR_FALSE);
+  nsCOMPtr<nsIEventQueue> eventQueue;
+    eventService->GetThreadEventQueue(PR_GetCurrentThread(),
+                                      getter_AddRefs(eventQueue));
+  if (eventQueue) {
+    nsASyncMenuInitialization* initialization =
+      new nsASyncMenuInitialization(this);
+    if (initialization) {
+      PL_InitEvent(initialization, nsnull,
+                   ::HandleASyncMenuInitialization,
+                   ::DestroyASyncMenuInitialization);
+      if (NS_FAILED(eventQueue->PostEvent(initialization))) {
+        PL_DestroyEvent(initialization);
+      }
+    }
+  }
   return rv;
 }
 
@@ -338,15 +388,18 @@ NS_IMETHODIMP
 nsMenuFrame::Destroy(nsIPresContext* aPresContext)
 {
   // are we our menu parent's current menu item?
+  nsWeakFrame weakFrame(this);
   if (mMenuParent) {
     nsIMenuFrame *curItem = nsnull;
     mMenuParent->GetCurrentMenuItem(&curItem);
     if (curItem == this) {
       // yes; tell it that we're going away
       mMenuParent->SetCurrentMenuItem(nsnull);
+      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
     }
   }
 
+  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
   DestroyPopupFrames(aPresContext);
   return nsBoxFrame::Destroy(aPresContext);
 }
@@ -383,6 +436,7 @@ nsMenuFrame::HandleEvent(nsIPresContext* aPresContext,
                              nsEventStatus*  aEventStatus)
 {
   NS_ENSURE_ARG_POINTER(aEventStatus);
+  nsWeakFrame weakFrame(this);
   if (*aEventStatus == nsEventStatus_eIgnore)
     *aEventStatus = nsEventStatus_eConsumeDoDefault;
   
@@ -409,6 +463,7 @@ nsMenuFrame::HandleEvent(nsIPresContext* aPresContext,
     // We have children.
     if ( isMenuBar || !mMenuParent ) {
       ToggleMenuState();
+      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
 
       if (!IsOpen() && mMenuParent) {
         // We closed up. The menu bar should always be
@@ -496,6 +551,8 @@ nsMenuFrame::HandleEvent(nsIPresContext* aPresContext,
 
     // Let the menu parent know we're the new item.
     mMenuParent->SetCurrentMenuItem(this);
+    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
+    NS_ENSURE_TRUE(mMenuParent, NS_OK);
 
     // we need to check if we really became the current menu
     // item or not
@@ -533,8 +590,10 @@ nsMenuFrame::HandleEvent(nsIPresContext* aPresContext,
 NS_IMETHODIMP
 nsMenuFrame::ToggleMenuState()
 {  
+  nsWeakFrame weakFrame(this);
   if (mMenuOpen) {
     OpenMenu(PR_FALSE);
+    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
   }
   else {
     PRBool justRolledUp = PR_FALSE;
@@ -546,21 +605,28 @@ nsMenuFrame::ToggleMenuState()
       // from the same click. Otherwise, the user can't click on
       // a menubar item to toggle its submenu closed.
       OpenMenu(PR_FALSE);
+      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
       SelectMenu(PR_TRUE);
       mMenuParent->SetActive(PR_FALSE);
+      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
+      NS_ENSURE_TRUE(mMenuParent, NS_OK);
     }
     else {
       if (mMenuParent) {
         mMenuParent->SetActive(PR_TRUE);
+        NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
       }
       OpenMenu(PR_TRUE);
     }
   }
+  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
 
   if (mMenuParent) {
     // Make sure the current menu which is being toggled on
     // the menubar is highlighted
     mMenuParent->SetCurrentMenuItem(this);
+    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
+    NS_ENSURE_TRUE(mMenuParent, NS_OK);
     // We've successfully prevented the same click from both
     // dismissing and reopening this menu. 
     // Clear the recent rollup state so we don't prevent
@@ -579,6 +645,7 @@ nsMenuFrame::SelectMenu(PRBool aActivateFlag)
   }
 
   nsAutoString domEventToFire;
+  nsWeakFrame weakFrame(this);
 
   if (aActivateFlag) {
     // Highlight the menu.
@@ -592,7 +659,9 @@ nsMenuFrame::SelectMenu(PRBool aActivateFlag)
     domEventToFire.Assign(NS_LITERAL_STRING("DOMMenuItemInactive"));
   }
 
-  FireChromeDOMEvent(mPresContext, domEventToFire);
+  if (weakFrame.IsAlive()) {
+    FireChromeDOMEvent(mPresContext, domEventToFire);
+  }
   return NS_OK;
 }
 
@@ -734,15 +803,21 @@ nsMenuFrame::OpenMenu(PRBool aActivateFlag)
   if (!mContent)
     return NS_OK;
 
+  nsWeakFrame weakFrame(this);
   nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(mContent));
   if (aActivateFlag) {
     // Now that the menu is opened, we should have a menupopup child built.
     // Mark it as generated, which ensures a frame gets built.
     MarkAsGenerated();
+    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
 
     domElement->SetAttribute(NS_LITERAL_STRING("open"), NS_LITERAL_STRING("true"));
   }
-  else domElement->RemoveAttribute(NS_LITERAL_STRING("open"));
+  else {
+    domElement->RemoveAttribute(NS_LITERAL_STRING("open"));
+  }
+
+  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
 
   return NS_OK;
 }
@@ -755,9 +830,11 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
   if (!mIsMenu)
     return;
 
+  nsWeakFrame weakFrame(this);
+
   if (aActivateFlag) {
     // Execute the oncreate handler
-    if (!OnCreate())
+    if (!OnCreate() || !weakFrame.IsAlive())
       return;
 
     mCreateHandlerSucceeded = PR_TRUE;
@@ -768,6 +845,7 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
     
     // XXX Only have this here because of RDF-generated content.
     MarkAsGenerated();
+    ENSURE_TRUE(weakFrame.IsAlive());
 
     nsIFrame* frame = mPopupFrames.FirstChild();
     nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
@@ -775,11 +853,13 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
     mMenuOpen = PR_TRUE;
 
     if (menuPopup) {
+      nsWeakFrame weakMenuPopup(frame);
       // inherit whether or not we're a context menu from the parent
       if ( mMenuParent ) {
         PRBool parentIsContextMenu = PR_FALSE;
         mMenuParent->GetIsContextMenu(parentIsContextMenu);
         menuPopup->SetIsContextMenu(parentIsContextMenu);
+        ENSURE_TRUE(weakFrame.IsAlive());
       }
 
       // Install a keyboard navigation listener if we're the root of the menu chain.
@@ -790,11 +870,16 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
       if (mMenuParent && onMenuBar)
         mMenuParent->InstallKeyboardNavigator();
       else if (!mMenuParent)
+      {
+        ENSURE_TRUE(weakMenuPopup.IsAlive());
         menuPopup->InstallKeyboardNavigator();
+      }
       
       // Tell the menu bar we're active.
-      if (mMenuParent)
+      if (mMenuParent) {
         mMenuParent->SetActive(PR_TRUE);
+        ENSURE_TRUE(weakFrame.IsAlive());
+      }
 
       nsIContent* menuPopupContent = menuPopup->GetContent();
 
@@ -849,12 +934,14 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
       }
 
       ActivateMenu(PR_TRUE);
+      ENSURE_TRUE(weakFrame.IsAlive());
 
       nsIMenuParent *childPopup = nsnull;
       CallQueryInterface(frame, &childPopup);
       UpdateDismissalListener(childPopup);
 
       OnCreated();
+      ENSURE_TRUE(weakFrame.IsAlive());
     }
 
     // Set the focus back to our view's widget.
@@ -866,7 +953,7 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
 
     // Close the menu. 
     // Execute the ondestroy handler, but only if we're actually open
-    if ( !mCreateHandlerSucceeded || !OnDestroy() )
+    if ( !mCreateHandlerSucceeded || !OnDestroy() || !weakFrame.IsAlive())
       return;
 
     mMenuOpen = PR_FALSE;
@@ -883,6 +970,7 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
     // Make sure we clear out our own items.
     if (menuPopup) {
       menuPopup->SetCurrentMenuItem(nsnull);
+      ENSURE_TRUE(weakFrame.IsAlive());
       menuPopup->KillCloseTimer();
 
       PRBool onMenuBar = PR_TRUE;
@@ -909,8 +997,10 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
 
     // activate false will also set the mMenuOpen to false.
     ActivateMenu(PR_FALSE);
+    ENSURE_TRUE(weakFrame.IsAlive());
 
     OnDestroyed();
+    ENSURE_TRUE(weakFrame.IsAlive());
 
     if (nsMenuFrame::sDismissalListener)
       nsMenuFrame::sDismissalListener->EnableListener(PR_TRUE);
@@ -1364,9 +1454,12 @@ nsMenuFrame::UpdateMenuType(nsIPresContext* aPresContext)
       mGroupName = valueName;
   } 
   else {
-    if (mType != eMenuType_Normal)
+    if (mType != eMenuType_Normal) {
+      nsWeakFrame weakFrame(this);
       mContent->UnsetAttr(kNameSpaceID_None, nsHTMLAtoms::checked,
                           PR_TRUE);
+      ENSURE_TRUE(weakFrame.IsAlive());
+    }
     mType = eMenuType_Normal;
   }
   UpdateMenuSpecialState(aPresContext);
@@ -1481,7 +1574,9 @@ nsMenuFrame::BuildAcceleratorText()
   AddStateBits(NS_STATE_ACCELTEXT_IS_DERIVED);
 
   // If anything below fails, just leave the accelerator text blank.
+  nsWeakFrame weakFrame(this);
   mContent->UnsetAttr(kNameSpaceID_None, nsXULAtoms::acceltext, PR_FALSE);
+  ENSURE_TRUE(weakFrame.IsAlive());
 
   // See if we have a key node and use that instead.
   nsAutoString keyValue;
@@ -1607,6 +1702,7 @@ nsMenuFrame::BuildAcceleratorText()
 void
 nsMenuFrame::Execute(nsGUIEvent *aEvent)
 {
+  nsWeakFrame weakFrame(this);
   // flip "checked" state if we're a checkbox menu, or an un-checked radio menu
   if (mType == eMenuType_Checkbox || (mType == eMenuType_Radio && !mChecked)) {
     nsAutoString value;
@@ -1615,10 +1711,12 @@ nsMenuFrame::Execute(nsGUIEvent *aEvent)
       if (mChecked) {
         mContent->UnsetAttr(kNameSpaceID_None, nsHTMLAtoms::checked,
                             PR_TRUE);
+        ENSURE_TRUE(weakFrame.IsAlive());
       }
       else {
         mContent->SetAttr(kNameSpaceID_None, nsHTMLAtoms::checked, NS_LITERAL_STRING("true"),
                           PR_TRUE);
+        ENSURE_TRUE(weakFrame.IsAlive());
       }        
       /* the AttributeChanged code will update all the internal state */
     }
@@ -1636,6 +1734,7 @@ nsMenuFrame::Execute(nsGUIEvent *aEvent)
 
   // Deselect ourselves.
   SelectMenu(PR_FALSE);
+  ENSURE_TRUE(weakFrame.IsAlive());
 
   // Now hide all of the open menus.
   if (mMenuParent) {
@@ -1672,22 +1771,14 @@ nsMenuFrame::Execute(nsGUIEvent *aEvent)
   nsCOMPtr<nsIViewManager> kungFuDeathGrip = mPresContext->GetViewManager();
   // keep a reference so we can safely use this after dispatching the DOM event
   nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell();
-  nsIFrame* me = this;
   if (shell) {
     shell->HandleDOMEventWithTarget(mContent, &event, &status);
-    // shell may no longer be alive, don't use it here unless you keep a ref
+    ENSURE_TRUE(weakFrame.IsAlive());
   }
 
-  // XXX HACK. Just gracefully exit if the node has been removed, e.g., window.close()
-  // was executed.
-  nsIFrame* primary = nsnull;
-  if (shell) shell->GetPrimaryFrameFor(content, &primary);
-
-  // Now properly close them all up.
-  if (content->GetDocument() &&     // <-- HACK IS HERE. ICK.
-      (primary == me) && mMenuParent)
+  if (mMenuParent) {
     mMenuParent->DismissChain();
-  // END HACK
+  }
 
   // Re-enable rollup events on this menu.
   if ( nsMenuFrame::sDismissalListener ) {
@@ -1729,7 +1820,7 @@ nsMenuFrame::OnCreate()
 
     PRUint32 count = child->GetChildCount();
     for (PRUint32 i = 0; i < count; i++) {
-      nsIContent *grandChild = child->GetChildAt(i);
+      nsCOMPtr<nsIContent> grandChild = child->GetChildAt(i);
 
       if (grandChild->Tag() == nsXULAtoms::menuitem) {
         // See if we have a command attribute.
@@ -1953,6 +2044,55 @@ nsMenuFrame::UpdateDismissalListener(nsIMenuParent* aMenuParent)
   nsMenuFrame::sDismissalListener->SetCurrentMenuParent(aMenuParent);
 }
 
+struct nsASyncMenuGeneration : public PLEvent
+{
+  nsASyncMenuGeneration(nsIFrame* aFrame)
+    : mWeakFrame(aFrame)
+  {
+    nsIContent* content = aFrame ? aFrame->GetContent() : nsnull;
+    mDocument = content ? content->GetDocument() : nsnull;
+    if (mDocument) {
+          nsCOMPtr<nsIDocument_MOZILLA_1_7_BRANCH> doc17(do_QueryInterface(mDocument));
+          doc17->BlockOnload();
+    }
+  }
+
+  void HandleEvent() {
+    nsIFrame* frame = mWeakFrame.GetFrame();
+    nsIBox *box = nsnull;
+    CallQueryInterface(frame, &box);
+    if (box) {
+      PRBool collapsed = PR_FALSE;
+      nsBoxLayoutState state(frame->GetPresContext());
+      box->IsCollapsed(state, collapsed);
+      if (!collapsed) {
+        nsIMenuFrame* imenu = nsnull;
+        CallQueryInterface(frame, &imenu);
+        if (imenu) {
+          imenu->MarkAsGenerated();
+        }
+      }
+    }
+    if (mDocument) {
+      nsCOMPtr<nsIDocument_MOZILLA_1_7_BRANCH> doc17(do_QueryInterface(mDocument));
+      doc17->UnblockOnload();
+    }
+  }
+
+  nsWeakFrame           mWeakFrame;
+  nsCOMPtr<nsIDocument> mDocument;
+};
+
+static void* PR_CALLBACK HandleASyncMenuGeneration(PLEvent* aEvent)
+{
+  NS_STATIC_CAST(nsASyncMenuGeneration*, aEvent)->HandleEvent();
+  return nsnull;
+}
+static void PR_CALLBACK DestroyASyncMenuGeneration(PLEvent* aEvent)
+{
+  delete NS_STATIC_CAST(nsASyncMenuGeneration*, aEvent);
+}
+
 NS_IMETHODIMP
 nsMenuFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize)
 {
@@ -1969,10 +2109,32 @@ nsMenuFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize)
     if (tmpSize.width == -1 && flex==0) {
       nsIFrame* frame = mPopupFrames.FirstChild();
       if (!frame) {
-        MarkAsGenerated();
-        frame = mPopupFrames.FirstChild();
-        // No child - just return
-        if (!frame) return NS_OK;
+        nsCOMPtr<nsIContent> child;
+        GetMenuChildrenElement(getter_AddRefs(child));
+        if (child) {
+          nsAutoString genVal;
+          child->GetAttr(kNameSpaceID_None, nsXULAtoms::menugenerated, genVal);
+          if (genVal.IsEmpty()) {
+            nsCOMPtr<nsIEventQueueService> eventService =
+              do_GetService(kEventQueueServiceCID);
+            NS_ENSURE_TRUE(eventService, PR_FALSE);
+            nsCOMPtr<nsIEventQueue> eventQueue;
+              eventService->GetThreadEventQueue(PR_GetCurrentThread(),
+                                                getter_AddRefs(eventQueue));
+            if (eventQueue) {
+              nsASyncMenuGeneration* gen = new nsASyncMenuGeneration(this);
+              if (gen) {
+                PL_InitEvent(gen, nsnull,
+                             ::HandleASyncMenuGeneration,
+                             ::DestroyASyncMenuGeneration);
+                if (NS_FAILED(eventQueue->PostEvent(gen))) {
+                  PL_DestroyEvent(gen);
+                }
+              }
+            }
+          }
+        }
+        return PR_FALSE;
       }
     
       nsIBox* ibox = nsnull;
diff --git a/layout/xul/base/src/nsMenuFrame.h b/layout/xul/base/src/nsMenuFrame.h
index f3ea8ec..71f4589 100644
--- a/layout/xul/base/src/nsMenuFrame.h
+++ b/layout/xul/base/src/nsMenuFrame.h
@@ -200,6 +200,7 @@ protected:
   virtual void RePositionPopup(nsBoxLayoutState& aState);
 
   static void UpdateDismissalListener(nsIMenuParent* aMenuParent);
+  friend class nsASyncMenuInitialization;
   void UpdateMenuType(nsIPresContext* aPresContext);
   void UpdateMenuSpecialState(nsIPresContext* aPresContext);
 
diff --git a/layout/xul/base/src/nsMenuPopupFrame.cpp b/layout/xul/base/src/nsMenuPopupFrame.cpp
index 046b599..2e2ff8e 100644
--- a/layout/xul/base/src/nsMenuPopupFrame.cpp
+++ b/layout/xul/base/src/nsMenuPopupFrame.cpp
@@ -73,10 +73,14 @@
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsCSSFrameConstructor.h"
+#include "nsIEventQueueService.h"
+#include "nsIServiceManager.h"
 #ifdef XP_WIN
 #include "nsISound.h"
 #endif
 
+static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
+
 const PRInt32 kMaxZ = 0x7fffffff; //XXX: Shouldn't there be a define somewhere for MaxInt for PRInt32
 
 
@@ -827,6 +831,37 @@ nsMenuPopupFrame::MovePopupToOtherSideOfParent ( PRBool inFlushAboveBelow, PRInt
 
 } // MovePopupToOtherSideOfParent
 
+struct nsASyncMenuActivation : public PLEvent
+{
+  nsASyncMenuActivation(nsIContent* aContent)
+    : mContent(aContent)
+  {
+  }
+
+  void HandleEvent() {
+    nsAutoString shouldDisplay, menuActive;
+    mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::menuactive, menuActive);
+    if (!menuActive.Equals(NS_LITERAL_STRING("true"))) {
+      mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::menutobedisplayed,
+                        shouldDisplay);
+      if(shouldDisplay.Equals(NS_LITERAL_STRING("true"))) {
+        mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::menuactive,
+                          NS_LITERAL_STRING("true"), PR_TRUE);
+      }
+    }
+  }
+
+  nsCOMPtr<nsIContent> mContent;
+};
+
+static void PR_CALLBACK HandleASyncMenuActivation(nsASyncMenuActivation* aEvent)
+{
+  aEvent->HandleEvent();
+}
+static void PR_CALLBACK DestroyASyncMenuActivation(nsASyncMenuActivation* aEvent)
+{
+  delete aEvent;
+}
 
 
 nsresult 
@@ -1213,8 +1248,25 @@ nsMenuPopupFrame::SyncViewWithFrame(nsIPresContext* aPresContext,
   mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::menuactive, menuActive);
   if (menuActive != NS_LITERAL_STRING("true")) {
     mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::menutobedisplayed, shouldDisplay);
-    if ( shouldDisplay == NS_LITERAL_STRING("true") )
-      mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::menuactive, NS_LITERAL_STRING("true"), PR_TRUE);
+    if ( shouldDisplay.Equals(NS_LITERAL_STRING("true")) ) {
+      nsCOMPtr<nsIEventQueueService> eventService =
+        do_GetService(kEventQueueServiceCID);
+      NS_ENSURE_TRUE(eventService, NS_ERROR_FAILURE);
+      nsCOMPtr<nsIEventQueue> eventQueue;
+      eventService->GetThreadEventQueue(PR_GetCurrentThread(),
+                                        getter_AddRefs(eventQueue));
+      if (eventQueue) {
+        nsASyncMenuActivation* activation = new nsASyncMenuActivation(mContent);
+        if (activation) {
+          PL_InitEvent(activation, nsnull,
+                       (PLHandleEventProc) ::HandleASyncMenuActivation,
+                       (PLDestroyEventProc) ::DestroyASyncMenuActivation);
+          if (NS_FAILED(eventQueue->PostEvent(activation))) {
+            PL_DestroyEvent(activation);
+          }
+        }
+      }
+    }
   }
 
   return NS_OK;
@@ -1751,10 +1803,14 @@ nsMenuPopupFrame::ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandled
   nsIMenuFrame* result = FindMenuWithShortcut(aKeyEvent, action);
   if (result) {
     // We got one!
+    nsIFrame* frame = nsnull;
+    CallQueryInterface(result, &frame);
+    nsWeakFrame weakResult(frame);
     aHandledFlag = PR_TRUE;
     SetCurrentMenuItem(result);
-    if (action)
+    if (action && weakResult.IsAlive()) {
       result->Enter();
+    }
   }
 
   return NS_OK;
@@ -1792,6 +1848,7 @@ nsMenuPopupFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
   PRBool isContainer = PR_FALSE;
   PRBool isOpen = PR_FALSE;
   PRBool isDisabled = PR_FALSE;
+  nsWeakFrame weakFrame(this);
   if (mCurrentMenu) {
     mCurrentMenu->MenuIsContainer(isContainer);
     mCurrentMenu->MenuIsOpen(isOpen);
@@ -1800,13 +1857,19 @@ nsMenuPopupFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
     if (isOpen) {
       // Give our child a shot.
       mCurrentMenu->KeyboardNavigation(aKeyCode, aHandledFlag);
+      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
     }
     else if (theDirection == eNavigationDirection_End &&
              isContainer && !isDisabled) {
       // The menu is not yet open. Open it and select the first item.
       aHandledFlag = PR_TRUE;
+      nsIFrame* frame = nsnull;
+      CallQueryInterface(mCurrentMenu, &frame);
+      nsWeakFrame weakCurrentFrame(frame);
       mCurrentMenu->OpenMenu(PR_TRUE);
+      NS_ENSURE_TRUE(weakCurrentFrame.IsAlive(), NS_OK);
       mCurrentMenu->SelectFirstItem();
+      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
     }
   }
 
@@ -1836,6 +1899,7 @@ nsMenuPopupFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
     if (theDirection == eNavigationDirection_Start) {
       // Close it up.
       mCurrentMenu->OpenMenu(PR_FALSE);
+      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
       aHandledFlag = PR_TRUE;
     }
   }
@@ -1875,6 +1939,7 @@ nsMenuPopupFrame::HideChain()
   
   nsIFrame* frame = GetParent();
   if (frame) {
+    nsWeakFrame weakMenu(frame);
     nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(frame);
     if (!menuFrame) {
       nsIPopupSetFrame* popupSetFrame = GetPopupSetFrame(mPresContext);
@@ -1885,7 +1950,9 @@ nsMenuPopupFrame::HideChain()
     }
    
     menuFrame->ActivateMenu(PR_FALSE);
+    NS_ENSURE_TRUE(weakMenu.IsAlive(), NS_OK);
     menuFrame->SelectMenu(PR_FALSE);
+    NS_ENSURE_TRUE(weakMenu.IsAlive(), NS_OK);
 
     // Get the parent.
     nsCOMPtr<nsIMenuParent> menuParent;
-- 
1.4.4.2


More information about the pkg-mozilla-maintainers mailing list