Index: content/browser/renderer_host/render_view_host_manager_browsertest.cc |
=================================================================== |
--- content/browser/renderer_host/render_view_host_manager_browsertest.cc (revision 97282) |
+++ content/browser/renderer_host/render_view_host_manager_browsertest.cc (working copy) |
@@ -8,12 +8,15 @@ |
#include "chrome/browser/ui/browser.h" |
#include "chrome/test/base/in_process_browser_test.h" |
#include "chrome/test/base/ui_test_utils.h" |
+#include "content/browser/renderer_host/render_view_host.h" |
+#include "content/browser/renderer_host/render_view_host_observer.h" |
#include "content/browser/site_instance.h" |
#include "content/browser/tab_contents/tab_contents.h" |
#include "content/common/content_notification_types.h" |
#include "content/common/notification_details.h" |
#include "content/common/notification_observer.h" |
#include "content/common/notification_registrar.h" |
+#include "content/common/url_constants.h" |
#include "net/base/net_util.h" |
#include "net/test/test_server.h" |
@@ -246,3 +249,89 @@ |
browser()->GetSelectedTabContents()->GetSiteInstance()); |
EXPECT_EQ(orig_site_instance, noref_site_instance); |
} |
+ |
+// This class holds onto RenderViewHostObservers for as long as their observed |
+// RenderViewHosts are alive. This allows us to confirm that all hosts have |
+// properly been shutdown. |
+class RenderViewHostObserverArray { |
+ public: |
+ ~RenderViewHostObserverArray() { |
+ // In case some would be left in there with a dead pointer to us. |
+ for (std::list<RVHObserver*>::iterator iter = observers_.begin(); |
+ iter != observers_.end(); ++iter) { |
+ (*iter)->ClearParent(); |
+ } |
+ } |
+ void AddObserverToRVH(RenderViewHost* rvh) { |
+ observers_.push_back(new RVHObserver(this, rvh)); |
+ } |
+ size_t GetNumObservers() const { |
+ return observers_.size(); |
+ } |
+ private: |
+ friend class RVHObserver; |
+ class RVHObserver : public RenderViewHostObserver { |
+ public: |
+ RVHObserver(RenderViewHostObserverArray* parent, RenderViewHost* rvh) |
+ : RenderViewHostObserver(rvh), |
+ parent_(parent) { |
+ } |
+ virtual void RenderViewHostDestroyed() OVERRIDE { |
+ if (parent_) |
+ parent_->RemoveObserver(this); |
+ RenderViewHostObserver::RenderViewHostDestroyed(); |
+ }; |
+ void ClearParent() { |
+ parent_ = NULL; |
+ } |
+ private: |
+ RenderViewHostObserverArray* parent_; |
+ }; |
+ |
+ void RemoveObserver(RVHObserver* observer) { |
+ observers_.remove(observer); |
+ } |
+ |
+ std::list<RVHObserver*> observers_; |
+}; |
+ |
+// Test for crbug.com/90867. Make sure we don't leak render view hosts since |
+// they may cause crashes or memory corruptions when trying to call dead |
+// delegate_. |
+IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, LeakingRenderViewHosts) { |
+ // Start two servers with different sites. |
+ ASSERT_TRUE(test_server()->Start()); |
+ net::TestServer https_server(net::TestServer::TYPE_HTTPS, |
+ FilePath(FILE_PATH_LITERAL("chrome/test/data"))); |
+ ASSERT_TRUE(https_server.Start()); |
+ |
+ // Create a new tab so that we can close the one we navigate and still have |
+ // a running browser. |
+ AddBlankTabAndShow(browser()); |
+ |
+ // Load a random page and then navigate to view-source: of it. |
+ // This is one way to cause two rvh instances for the same instance id. |
+ GURL navigated_url(test_server()->GetURL("files/title2.html")); |
+ ui_test_utils::NavigateToURL(browser(), navigated_url); |
+ |
+ // Observe the newly created render_view_host to make sure it will not leak. |
+ RenderViewHostObserverArray rvh_observers; |
+ rvh_observers.AddObserverToRVH(browser()->GetSelectedTabContents()-> |
+ render_view_host()); |
+ |
+ GURL view_source_url(chrome::kViewSourceScheme + std::string(":") + |
+ navigated_url.spec()); |
+ ui_test_utils::NavigateToURL(browser(), view_source_url); |
+ rvh_observers.AddObserverToRVH(browser()->GetSelectedTabContents()-> |
+ render_view_host()); |
+ |
+ // Now navigate to a different instance so that we swap out again. |
+ ui_test_utils::NavigateToURL(browser(), |
+ https_server.GetURL("files/title2.html")); |
+ rvh_observers.AddObserverToRVH(browser()->GetSelectedTabContents()-> |
+ render_view_host()); |
+ |
+ // This used to leak a render view host. |
+ browser()->CloseTabContents(browser()->GetSelectedTabContents()); |
+ EXPECT_EQ(0U, rvh_observers.GetNumObservers()); |
+} |