b=432467, firefox segfaults in plone kupu editor [@ nsDocAccessible::FlushPendingEvents], on Tablet PC [@arena_dalloc_small] (steps to reproduce in comment #26), p=Ginn Chen <ginn.chen@sun.com>, r=surkov
authorMarco Zehe <marco.zehe@googlemail.com>
Thu, 05 Jun 2008 11:49:51 +0200
changeset 15262 263749849d0be4a861529d025daae66f5e5601f4
parent 15261 49cdeb4f814489ca9128233588b948936448329f
child 15263 ed7cbf8018185348bb8c46dec64677471be8b92e
push idunknown
push userunknown
push dateunknown
reviewerssurkov
bugs432467
milestone1.9.1a1pre
b=432467, firefox segfaults in plone kupu editor [@ nsDocAccessible::FlushPendingEvents], on Tablet PC [@arena_dalloc_small] (steps to reproduce in comment #26), p=Ginn Chen <ginn.chen@sun.com>, r=surkov
accessible/src/base/nsDocAccessible.cpp
accessible/src/base/nsDocAccessible.h
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -80,17 +80,18 @@
 PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0;
 nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull;
 
 //-----------------------------------------------------
 // construction
 //-----------------------------------------------------
 nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
   nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
-  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE), mIsLoadCompleteFired(PR_FALSE)
+  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
+  mIsLoadCompleteFired(PR_FALSE), mInFlushPendingEvents(PR_FALSE)
 {
   // For GTK+ native window, we do nothing here.
   if (!mDOMNode)
     return;
 
   // Because of the way document loading happens, the new nsIWidget is created before
   // the old one is removed. Since it creates the nsDocAccessible, for a brief moment
   // there can be 2 nsDocAccessible's for the content area, although for 2 different
@@ -584,17 +585,20 @@ NS_IMETHODIMP nsDocAccessible::Shutdown(
   if (mFireEventTimer) {
     // Doc being shut down before events fired,
     mFireEventTimer->Cancel();
     mFireEventTimer = nsnull;
     if (mEventsToFire.Count() > 0 ) {
       mEventsToFire.Clear();
       // Make sure we release the kung fu death grip which is always
       // there when there are still events left to be fired
-      NS_RELEASE_THIS();
+      // If FlushPendingEvents() is in call stack,
+      // kung fu death grip will be released there.
+      if (!mInFlushPendingEvents)
+        NS_RELEASE_THIS();
     }
   }
 
   // Remove from the cache after other parts of Shutdown(), so that Shutdown() procedures
   // can find the doc or root accessible in the cache if they need it.
   // We don't do this during ShutdownAccessibility() because that is already clearing the cache
   if (!gIsShuttingDownApp)
     gGlobalDocAccessibleCache.Remove(static_cast<void*>(kungFuDeathGripDoc));
@@ -1500,16 +1504,17 @@ nsDocAccessible::FireDelayedAccessibleEv
                                           0, nsITimer::TYPE_ONE_SHOT);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
 {
+  mInFlushPendingEvents = PR_TRUE;
   PRUint32 length = mEventsToFire.Count();
   NS_ASSERTION(length, "How did we get here without events to fire?");
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell)
     length = 0; // The doc is now shut down, don't fire events in it anymore
   else
     nsAccEvent::ApplyEventRules(mEventsToFire);
   
@@ -1620,17 +1625,18 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
           // Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
           // line-number object attribute on it
           nsCOMPtr<nsIAccessible> accForFocus;
           GetAccService()->GetAccessibleFor(gLastFocusedNode, getter_AddRefs(accForFocus));
           nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_ALERT, accForFocus);
 #endif
           nsCOMPtr<nsIAccessibleCaretMoveEvent> caretMoveEvent =
             new nsAccCaretMoveEvent(accessible, caretOffset);
-          NS_ENSURE_TRUE(caretMoveEvent, NS_ERROR_OUT_OF_MEMORY);
+          if (!caretMoveEvent)
+            break; // Out of memory, break out to release kung fu death grip
 
           FireAccessibleEvent(caretMoveEvent);
 
           PRInt32 selectionCount;
           accessibleText->GetSelectionCount(&selectionCount);
           if (selectionCount) {  // There's a selection so fire selection change as well
             nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
                                      accessible, PR_TRUE);
@@ -1656,16 +1662,17 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
     }
   }
   mEventsToFire.Clear(); // Clear out array
   NS_RELEASE_THIS(); // Release kung fu death grip
 
   // After a flood of events, reset so that user input flag is off
   nsAccEvent::ResetLastInputState();
 
+  mInFlushPendingEvents = PR_FALSE;
   return NS_OK;
 }
 
 void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
 {
   nsPIAccessibleDocument *accessibleDoc = static_cast<nsPIAccessibleDocument*>(aClosure);
   NS_ASSERTION(accessibleDoc, "How did we get here without an accessible document?");
   if (accessibleDoc) {
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -216,13 +216,14 @@ class nsDocAccessible : public nsHyperTe
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
     PRPackedBool mIsContentLoaded;
     PRPackedBool mIsLoadCompleteFired;
     nsCOMArray<nsIAccessibleEvent> mEventsToFire;
 
 protected:
     PRBool mIsAnchor;
     PRBool mIsAnchorJumped;
+    PRBool mInFlushPendingEvents;
     static PRUint32 gLastFocusedAccessiblesState;
     static nsIAtom *gLastFocusedFrameType;
 };
 
 #endif