summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 18:45:47 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 18:45:47 +0000
commit7263dbd86fec864bb9604971aceeeee6b4b32816 (patch)
treeb55181f22655e86d499d78ed8b0aaba9104e6c7d
parent9a925a7db044b8d99119ac5023ab7fa0c7868024 (diff)
downloadchromium_src-7263dbd86fec864bb9604971aceeeee6b4b32816.zip
chromium_src-7263dbd86fec864bb9604971aceeeee6b4b32816.tar.gz
chromium_src-7263dbd86fec864bb9604971aceeeee6b4b32816.tar.bz2
Revert 71327 - Attempt at fixing crash in ProcessPendingTabs. With the current code,
during closing a window with unload handlers if a tab is disconnected then we delay cleanup by way of PostTask with the tab being disconnected. During the time between when the disconnect happens and the task is run the unloader handler sets still maintain a reference to the tab. If ProcessPendingTabs is invoked during this window and the tab is deleted, then we can crash. I'm fixing it by making disconnect remove from the sets immediately, but delay the call to ProcessPendingTabs. I'm also doing a similar thing in TabDetachedAt. BUG=15620 TEST=none Review URL: http://codereview.chromium.org/6203006 TBR=sky@chromium.org Review URL: http://codereview.chromium.org/6318001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71336 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/ui/browser.cc35
-rw-r--r--chrome/browser/ui/browser.h9
-rw-r--r--chrome/test/data/reliability/known_crashes.txt3
3 files changed, 17 insertions, 30 deletions
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index da64bdaa..3ba24b0 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2837,7 +2837,7 @@ void Browser::CloseContents(TabContents* source) {
// waiting for unload to fire. Don't actually try to close the tab as it
// will go down the slow shutdown path instead of the fast path of killing
// all the renderer processes.
- ClearUnloadState(source, true);
+ ClearUnloadState(source);
return;
}
@@ -3198,10 +3198,12 @@ void Browser::Observe(NotificationType type,
switch (type.value) {
case NotificationType::TAB_CONTENTS_DISCONNECTED:
if (is_attempting_to_close_browser_) {
- // Pass in false so that we delay processing. We need to delay the
- // processing as it may close the tab, which is currently on the call
- // stack above us.
- ClearUnloadState(Source<TabContents>(source).ptr(), false);
+ // Need to do this asynchronously as it will close the tab, which is
+ // currently on the call stack above us.
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
+ Source<TabContents>(source).ptr()));
}
break;
@@ -3858,7 +3860,7 @@ void Browser::ProcessPendingTabs() {
if (tab->render_view_host()) {
tab->render_view_host()->FirePageBeforeUnload(false);
} else {
- ClearUnloadState(tab, true);
+ ClearUnloadState(tab);
}
} else if (!tabs_needing_unload_fired_.empty()) {
// We've finished firing all beforeunload events and can proceed with unload
@@ -3875,7 +3877,7 @@ void Browser::ProcessPendingTabs() {
if (tab->render_view_host()) {
tab->render_view_host()->ClosePage(false, -1, -1);
} else {
- ClearUnloadState(tab, true);
+ ClearUnloadState(tab);
}
} else {
NOTREACHED();
@@ -3915,23 +3917,18 @@ bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
return false;
}
-void Browser::ClearUnloadState(TabContents* tab, bool process_now) {
+void Browser::ClearUnloadState(TabContents* tab) {
// Closing of browser could be canceled (via IsClosingPermitted) between the
// time when request was initiated and when this method is called, so check
// for is_attempting_to_close_browser_ flag before proceeding.
if (is_attempting_to_close_browser_) {
RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
RemoveFromSet(&tabs_needing_unload_fired_, tab);
- if (process_now) {
- ProcessPendingTabs();
- } else {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- method_factory_.NewRunnableMethod(&Browser::ProcessPendingTabs));
- }
+ ProcessPendingTabs();
}
}
+
///////////////////////////////////////////////////////////////////////////////
// Browser, In-progress download termination handling (private):
@@ -4090,14 +4087,6 @@ void Browser::TabDetachedAtImpl(TabContentsWrapper* contents, int index,
find_bar_controller_->ChangeTabContents(NULL);
}
- if (is_attempting_to_close_browser_) {
- // If this is the last tab with unload handlers, then ProcessPendingTabs
- // would call back into the TabStripModel (which is invoking this method on
- // us). Avoid that by passing in false so that the call to
- // ProcessPendingTabs is delayed.
- ClearUnloadState(contents->tab_contents(), false);
- }
-
registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
Source<TabContentsWrapper>(contents));
}
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index ecc1d15..16b0aba 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -909,13 +909,8 @@ class Browser : public TabHandlerDelegate,
// Cleans up state appropriately when we are trying to close the browser and
// the tab has finished firing its unload handler. We also use this in the
// cases where a tab crashes or hangs even if the beforeunload/unload haven't
- // successfully fired. If |process_now| is true |ProcessPendingTabs| is
- // invoked immediately, otherwise it is invoked after a delay (PostTask).
- //
- // Typically you'll want to pass in true for |process_now|. Passing in true
- // may result in deleting |tab|. If you know that shouldn't happen (because of
- // the state of the stack), pass in false.
- void ClearUnloadState(TabContents* tab, bool process_now);
+ // successfully fired.
+ void ClearUnloadState(TabContents* tab);
// In-progress download termination handling /////////////////////////////////
diff --git a/chrome/test/data/reliability/known_crashes.txt b/chrome/test/data/reliability/known_crashes.txt
index 8413585..03f42b1 100644
--- a/chrome/test/data/reliability/known_crashes.txt
+++ b/chrome/test/data/reliability/known_crashes.txt
@@ -40,6 +40,9 @@ REGEX : `anonymous namespace'::purecall$
# is the only one on the stack, so ignore that instance
REGEX : `anonymous namespace'::invalidparameter$
+# 15620
+PREFIX : browser::processpendingtabs___browser::clearunloadstate
+
# 47207
PREFIX : messageloop::runtask___messageloop::deferorrunpendingtask___messageloop::dodelayedwork___base::messagepumpforio::dorunloop___base::messagepumpwin::run___messageloop::runinternal___messageloop::run___base::thread::run___base::thread::threadmain___`anonymous namespace'::threadfunc
PREFIX : messageloop::runtask___messageloop::dodelayedwork___base::messagepumpforio::dorunloop___base::messagepumpwin::run___messageloop::runinternal___messageloop::run___base::thread::run___base::thread::threadmain___`anonymous namespace'::threadfunc