Bug 1153939 - Avoid a race condition with setting nsBaseWidgets WidgetShutdownObserver widget pointer to null. Fixes a crash in nsBaseWidget::DestroyCompositor(). r=roc

--HG--
extra : rebase_source : 3b38830b93428aedc44c83278efe4667f77fd0ba
This commit is contained in:
Jim Mathies 2015-04-16 10:16:04 -05:00
parent 39caf57915
commit 27569381f4
2 changed files with 61 additions and 25 deletions

View File

@ -154,35 +154,65 @@ nsBaseWidget::nsBaseWidget()
}
#endif
mShutdownObserver = new WidgetShutdownObserver(this);
nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
}
NS_IMPL_ISUPPORTS(WidgetShutdownObserver, nsIObserver)
WidgetShutdownObserver::WidgetShutdownObserver(nsBaseWidget* aWidget) :
mWidget(aWidget),
mRegistered(false)
{
Register();
}
WidgetShutdownObserver::~WidgetShutdownObserver()
{
// No need to call Unregister(), we can't be destroyed until nsBaseWidget
// gets torn down. The observer service and nsBaseWidget have a ref on us
// so nsBaseWidget has to call Unregister and then clear its ref.
}
NS_IMETHODIMP
WidgetShutdownObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *aData)
{
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0 &&
mWidget) {
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
if (sPluginWidgetList) {
delete sPluginWidgetList;
sPluginWidgetList = nullptr;
}
#endif
if (mWidget && !strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
nsCOMPtr<nsIWidget> kungFuDeathGrip(mWidget);
mWidget->Shutdown();
nsContentUtils::UnregisterShutdownObserver(this);
}
return NS_OK;
return NS_OK;
}
void
WidgetShutdownObserver::Register()
{
if (!mRegistered) {
mRegistered = true;
nsContentUtils::RegisterShutdownObserver(this);
}
}
void
WidgetShutdownObserver::Unregister()
{
if (mRegistered) {
nsContentUtils::UnregisterShutdownObserver(this);
mRegistered = false;
}
}
void
nsBaseWidget::Shutdown()
{
DestroyCompositor();
mShutdownObserver = nullptr;
FreeShutdownObserver();
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
if (sPluginWidgetList) {
delete sPluginWidgetList;
sPluginWidgetList = nullptr;
}
#endif
}
void nsBaseWidget::DestroyCompositor()
@ -205,6 +235,15 @@ void nsBaseWidget::DestroyLayerManager()
DestroyCompositor();
}
void
nsBaseWidget::FreeShutdownObserver()
{
if (mShutdownObserver) {
mShutdownObserver->Unregister();
}
mShutdownObserver = nullptr;
}
//-------------------------------------------------------------------------
//
// nsBaseWidget destructor
@ -217,15 +256,7 @@ nsBaseWidget::~nsBaseWidget()
static_cast<BasicLayerManager*>(mLayerManager.get())->ClearRetainerWidget();
}
if (mShutdownObserver) {
// If the shutdown observer is currently processing observers,
// then UnregisterShutdownObserver won't stop our Observer
// function from being called. Make sure we don't try
// to reference the dead widget.
mShutdownObserver->mWidget = nullptr;
nsContentUtils::UnregisterShutdownObserver(mShutdownObserver);
}
FreeShutdownObserver();
DestroyLayerManager();
#ifdef NOISY_WIDGET_LEAKS

View File

@ -56,19 +56,22 @@ class Thread;
class nsBaseWidget;
// Helper class used in shutting down gfx related code.
class WidgetShutdownObserver final : public nsIObserver
{
~WidgetShutdownObserver() {}
~WidgetShutdownObserver();
public:
explicit WidgetShutdownObserver(nsBaseWidget* aWidget)
: mWidget(aWidget)
{ }
explicit WidgetShutdownObserver(nsBaseWidget* aWidget);
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
void Register();
void Unregister();
nsBaseWidget *mWidget;
bool mRegistered;
};
/**
@ -471,6 +474,8 @@ protected:
void DestroyCompositor();
void DestroyLayerManager();
void FreeShutdownObserver();
nsIWidgetListener* mWidgetListener;
nsIWidgetListener* mAttachedWidgetListener;
nsRefPtr<LayerManager> mLayerManager;