Bug 775676 - Fix leak in nsWebShellWindow. r=roc

After nsWebShellWindow::Destroy clears mSPTimer, it calls
nsXULWindow::Destroy, which runs script.  That script might cause us to
call nsWebShellWindow::SetPersistenceTimer.

If that happens, SetPersistenceTimer will create mSPTimer (it was nulled
out during nsWebShellWindow::Destroy) and addref this.  But there is no
corresponding release.

Let this be a lesson to all ye who try to be clever with manual
addref/release!
This commit is contained in:
Justin Lebar 2012-07-23 10:40:36 -04:00
Родитель 645b8457bb
Коммит 2afb0a8c77
2 изменённых файлов: 51 добавлений и 12 удалений

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

@ -473,28 +473,63 @@ static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow)
}
#endif
namespace mozilla {
class WebShellWindowTimerCallback : public nsITimerCallback
{
public:
WebShellWindowTimerCallback(nsWebShellWindow* aWindow)
: mWindow(aWindow)
{}
NS_DECL_ISUPPORTS
NS_IMETHOD Notify(nsITimer* aTimer)
{
// Although this object participates in a refcount cycle (this -> mWindow
// -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this
// after it fires. So we don't need to release mWindow here.
mWindow->FirePersistenceTimer();
return NS_OK;
}
private:
nsRefPtr<nsWebShellWindow> mWindow;
};
NS_IMPL_THREADSAFE_ADDREF(WebShellWindowTimerCallback)
NS_IMPL_THREADSAFE_RELEASE(WebShellWindowTimerCallback)
NS_IMPL_THREADSAFE_QUERY_INTERFACE1(WebShellWindowTimerCallback,
nsITimerCallback)
} // namespace mozilla
void
nsWebShellWindow::SetPersistenceTimer(PRUint32 aDirtyFlags)
{
MutexAutoLock lock(mSPTimerLock);
if (!mSPTimer) {
nsresult rv;
mSPTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_SUCCEEDED(rv)) {
NS_ADDREF_THIS(); // for the timer, which holds a reference to this window
mSPTimer = do_CreateInstance("@mozilla.org/timer;1");
if (!mSPTimer) {
NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?");
return;
}
}
mSPTimer->InitWithFuncCallback(FirePersistenceTimer, this,
SIZE_PERSISTENCE_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
nsRefPtr<WebShellWindowTimerCallback> callback =
new WebShellWindowTimerCallback(this);
mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT,
nsITimer::TYPE_ONE_SHOT);
PersistentAttributesDirty(aDirtyFlags);
}
void
nsWebShellWindow::FirePersistenceTimer(nsITimer *aTimer, void *aClosure)
nsWebShellWindow::FirePersistenceTimer()
{
nsWebShellWindow *win = static_cast<nsWebShellWindow *>(aClosure);
MutexAutoLock lock(win->mSPTimerLock);
win->SavePersistentAttributes();
MutexAutoLock lock(mSPTimerLock);
SavePersistentAttributes();
}
@ -747,7 +782,6 @@ NS_IMETHODIMP nsWebShellWindow::Destroy()
mSPTimer->Cancel();
SavePersistentAttributes();
mSPTimer = nsnull;
NS_RELEASE_THIS(); // the timer held a reference to us
}
}
return nsXULWindow::Destroy();

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

@ -16,6 +16,10 @@
/* Forward declarations.... */
class nsIURI;
namespace mozilla {
class WebShellWindowTimerCallback;
} // namespace mozilla
class nsWebShellWindow : public nsXULWindow,
public nsIWebProgressListener
{
@ -41,6 +45,7 @@ public:
NS_IMETHOD Destroy();
protected:
friend class mozilla::WebShellWindowTimerCallback;
virtual ~nsWebShellWindow();
@ -54,7 +59,7 @@ protected:
mozilla::Mutex mSPTimerLock;
void SetPersistenceTimer(PRUint32 aDirtyFlags);
static void FirePersistenceTimer(nsITimer *aTimer, void *aClosure);
void FirePersistenceTimer();
};