diff options
author | andybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-26 22:33:58 +0000 |
---|---|---|
committer | andybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-26 22:33:58 +0000 |
commit | 6f39aee96cc206bc2f2cd90de3ebf5fc11fae17b (patch) | |
tree | 848ec8fe7e8728df46fa6981f280b4c2a8bd1be7 /chrome/browser/extensions/extension_host.cc | |
parent | 5dcbc02fef541561a2ff97a73e231fe751e05829 (diff) | |
download | chromium_src-6f39aee96cc206bc2f2cd90de3ebf5fc11fae17b.zip chromium_src-6f39aee96cc206bc2f2cd90de3ebf5fc11fae17b.tar.gz chromium_src-6f39aee96cc206bc2f2cd90de3ebf5fc11fae17b.tar.bz2 |
Prevents a crash that occurs when multiple ExtensionHost objects point to the same Extension object and then crash (or are killed by the Task manager). Since the first ExtensionHost RenderViewGone will cause the Extension to be unloaded, the subsequent call will try and unload a dirty pointer. This is prevented by NULLing out the Extension pointer in the host and checking it upon RenderViewGone before sending a notification to have it unloaded (again).
TEST=none
BUG=32613,32653
Review URL: http://codereview.chromium.org/555103
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37156 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions/extension_host.cc')
-rw-r--r-- | chrome/browser/extensions/extension_host.cc | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index a600235..ef06bef 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -137,6 +137,10 @@ ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance, // to the task manager then. registrar_.Add(this, NotificationType::RENDERER_PROCESS_CREATED, Source<RenderProcessHost>(render_process_host())); + // Listen for when an extension is unloaded from the same profile, as it may + // be the same extension that this points to. + registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, + Source<Profile>(profile_)); } ExtensionHost::~ExtensionHost() { @@ -226,19 +230,32 @@ void ExtensionHost::NavigateToURL(const GURL& url) { void ExtensionHost::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - if (type == NotificationType::EXTENSION_BACKGROUND_PAGE_READY) { - DCHECK(extension_->GetBackgroundPageReady()); - NavigateToURL(url_); - } else if (type == NotificationType::BROWSER_THEME_CHANGED) { - InsertThemeCSS(); - } else if (type == NotificationType::RENDERER_PROCESS_CREATED) { - LOG(INFO) << "Sending EXTENSION_PROCESS_CREATED"; - NotificationService::current()->Notify( - NotificationType::EXTENSION_PROCESS_CREATED, - Source<Profile>(profile_), - Details<ExtensionHost>(this)); - } else { - NOTREACHED(); + switch (type.value) { + case NotificationType::EXTENSION_BACKGROUND_PAGE_READY: + DCHECK(extension_->GetBackgroundPageReady()); + NavigateToURL(url_); + break; + case NotificationType::BROWSER_THEME_CHANGED: + InsertThemeCSS(); + break; + case NotificationType::RENDERER_PROCESS_CREATED: + LOG(INFO) << "Sending EXTENSION_PROCESS_CREATED"; + NotificationService::current()->Notify( + NotificationType::EXTENSION_PROCESS_CREATED, + Source<Profile>(profile_), + Details<ExtensionHost>(this)); + break; + case NotificationType::EXTENSION_UNLOADED: + // The extension object will be deleted after this notification has been + // sent. NULL it out so that dirty pointer issues don't arise in cases + // when multiple ExtensionHost objects pointing to the same Extension are + // present. + if (extension_ == Details<Extension>(details).ptr()) + extension_ = NULL; + break; + default: + NOTREACHED() << "Unexpected notification sent."; + break; } } @@ -254,6 +271,15 @@ void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host) { if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID) return; + // In certain cases, multiple ExtensionHost objects may have pointed to + // the same Extension at some point (one with a background page and a + // popup, for example). When the first ExtensionHost goes away, the extension + // is unloaded, and any other host that pointed to that extension will have + // its pointer to it NULLed out so that any attempt to unload a dirty pointer + // will be averted. + if (!extension_) + return; + LOG(INFO) << "Sending EXTENSION_PROCESS_TERMINATED for " + extension_->name(); DCHECK_EQ(render_view_host_, render_view_host); NotificationService::current()->Notify( |