Bug 688208 - Guard against accessing destroyed object [r=mfinkle]

The nsWindow for Android often dispatches events but doesn't check
for window destruction afterwards. Ensure that necessary destruction
checks and kungFuDeathGrips are in place to avoid accessing a
destroyed object.
This commit is contained in:
Kartikaya Gupta 2011-11-22 15:31:49 -05:00
Родитель a71ec3750f
Коммит 28e52ff018
1 изменённых файлов: 39 добавлений и 5 удалений

Просмотреть файл

@ -273,6 +273,8 @@ nsWindow::Create(nsIWidget *aParent,
NS_IMETHODIMP
nsWindow::Destroy(void)
{
nsBaseWidget::mOnDestroyCalled = true;
for (PRUint32 i = 0; i < mChildren.Length(); ++i) {
// why do we still have children?
ALOG("### Warning: Destroying window %p and reparenting child %p to null!", (void*)this, (void*)mChildren[i]);
@ -639,7 +641,10 @@ nsWindow::BringToFront()
return;
}
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsWindow *oldTop = nsnull;
nsWindow *newTop = this;
if (!gTopLevelWindows.IsEmpty())
oldTop = gTopLevelWindows[0];
@ -651,11 +656,20 @@ nsWindow::BringToFront()
DispatchEvent(&event);
}
nsGUIEvent event(true, NS_ACTIVATE, this);
if (Destroyed()) {
// somehow the deactivate event handler destroyed this window.
// try to recover by grabbing the next window in line and activating
// that instead
if (gTopLevelWindows.IsEmpty())
return;
newTop = gTopLevelWindows[0];
}
nsGUIEvent event(true, NS_ACTIVATE, newTop);
DispatchEvent(&event);
// force a window resize
nsAppShell::gAppShell->ResendLastResizeEvent(this);
nsAppShell::gAppShell->ResendLastResizeEvent(newTop);
RedrawAll();
}
@ -985,6 +999,7 @@ nsWindow::DrawTo(gfxASurface *targetSurface, const nsIntRect &invalidRect)
if (!mIsVisible)
return false;
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsEventStatus status;
nsIntRect boundsRect(0, 0, mBounds.width, mBounds.height);
@ -1247,6 +1262,7 @@ nsWindow::OnSizeChanged(const gfxIntSize& aSize)
ALOG("nsWindow: %p OnSizeChanged [%d %d]", (void*)this, w, h);
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsSizeEvent event(true, NS_SIZE, this);
InitEvent(event);
@ -1321,6 +1337,7 @@ nsWindow::OnMotionEvent(AndroidGeckoEvent *ae)
return;
}
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsIntPoint pt(ae->P0());
nsIntPoint offset = WidgetToScreenOffset();
@ -1353,6 +1370,8 @@ send_again:
// XXX add the double-click handling logic here
DispatchEvent(&event);
if (Destroyed())
return;
if (msg == NS_MOUSE_BUTTON_DOWN) {
msg = NS_MOUSE_MOVE;
@ -1402,7 +1421,10 @@ void nsWindow::OnMultitouchEvent(AndroidGeckoEvent *ae)
}
if (!mGestureFinished) {
nsRefPtr<nsWindow> kungFuDeathGrip(this);
DispatchGestureEvent(msg, 0, pinchDelta, refPoint, ae->Time());
if (Destroyed())
return;
// If the cumulative pinch delta goes past the threshold, treat this
// as a pinch only, and not a swipe.
@ -1429,6 +1451,8 @@ void nsWindow::OnMultitouchEvent(AndroidGeckoEvent *ae)
// Finish the pinch gesture, then fire the swipe event:
msg = NS_SIMPLE_GESTURE_MAGNIFY;
DispatchGestureEvent(msg, 0, pinchDist - mStartDist, refPoint, ae->Time());
if (Destroyed())
return;
msg = NS_SIMPLE_GESTURE_SWIPE;
DispatchGestureEvent(msg, direction, 0, refPoint, ae->Time());
@ -1631,6 +1655,7 @@ nsWindow::InitKeyEvent(nsKeyEvent& event, AndroidGeckoEvent& key)
void
nsWindow::HandleSpecialKey(AndroidGeckoEvent *ae)
{
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsCOMPtr<nsIAtom> command;
bool isDown = ae->Action() == AndroidKeyEvent::ACTION_DOWN;
bool isLongPress = !!(ae->Flags() & AndroidKeyEvent::FLAG_LONG_PRESS);
@ -1692,6 +1717,7 @@ nsWindow::HandleSpecialKey(AndroidGeckoEvent *ae)
void
nsWindow::OnKeyEvent(AndroidGeckoEvent *ae)
{
nsRefPtr<nsWindow> kungFuDeathGrip(this);
PRUint32 msg;
switch (ae->Action()) {
case AndroidKeyEvent::ACTION_DOWN:
@ -1734,6 +1760,8 @@ nsWindow::OnKeyEvent(AndroidGeckoEvent *ae)
InitKeyEvent(event, *ae);
DispatchEvent(&event, status);
if (Destroyed())
return;
if (!firePress)
return;
@ -1781,6 +1809,7 @@ nsWindow::OnIMEAddRange(AndroidGeckoEvent *ae)
void
nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
{
nsRefPtr<nsWindow> kungFuDeathGrip(this);
switch (ae->Action()) {
case AndroidGeckoEvent::IME_COMPOSITION_END:
{
@ -1826,9 +1855,8 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
compositionUpdate.data = event.theText;
mIMELastDispatchedComposingText = event.theText;
DispatchEvent(&compositionUpdate);
// XXX We must check whether this widget is destroyed or not
// before dispatching next event. However, Android's
// nsWindow has never checked it...
if (Destroyed())
return;
}
ALOGIME("IME: IME_SET_TEXT: l=%u, r=%u",
@ -1949,6 +1977,8 @@ nsWindow::ResetInputState()
// Cancel composition on Gecko side
if (mIMEComposing) {
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsTextEvent textEvent(true, NS_TEXT_TEXT, this);
InitEvent(textEvent, nsnull);
textEvent.theText = mIMEComposingText;
@ -2003,6 +2033,8 @@ nsWindow::CancelIMEComposition()
// Cancel composition on Gecko side
if (mIMEComposing) {
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsTextEvent textEvent(true, NS_TEXT_TEXT, this);
InitEvent(textEvent, nsnull);
DispatchEvent(&textEvent);
@ -2043,6 +2075,7 @@ nsWindow::OnIMETextChange(PRUint32 aStart, PRUint32 aOldEnd, PRUint32 aNewEnd)
// The more efficient way would have been passing the substring from index
// aStart to index aNewEnd
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, this);
InitEvent(event, nsnull);
event.InitForQueryTextContent(0, PR_UINT32_MAX);
@ -2063,6 +2096,7 @@ nsWindow::OnIMESelectionChange(void)
{
ALOGIME("IME: OnIMESelectionChange");
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, this);
InitEvent(event, nsnull);