Commit 561b5ae6 authored by tapted's avatar tapted Committed by Commit bot

Mac: Fix lifetime problem under BookmarkBarController stopPulsingBookmarkNode.

BookmarkBarController has a weak pointer in a |pulsingButton_| data
member. This is an NSView which can be destroyed in
-[BookmarkBarController redistributeButtonsOnBarAsNeeded] when it is
removed from its superview.

Since bubbles close asynchronously, and fade out, the bookmark bubble
can cause a UAF to |pulsingButton_| via stopPulsingBookmarkNode. This
can occur if a resize triggers redistributeButtonsOnBarAsNeeded while a
bookmark bubble is still alive.

There's no need for this to be a weak pointer. Make it scoped_nsobject
instead.

This affects both Cocoa and MacViews.

BUG=616051
TEST=Added unit_test:
BookmarkBarControllerTest.RedistributeButtonsOnBarAsNeeded

Review-Url: https://codereview.chromium.org/2567973002
Cr-Commit-Position: refs/heads/master@{#437954}
parent 196cee5d
...@@ -294,10 +294,10 @@ willAnimateFromState:(BookmarkBar::State)oldState ...@@ -294,10 +294,10 @@ willAnimateFromState:(BookmarkBar::State)oldState
base::scoped_nsobject<BookmarkContextMenuCocoaController> base::scoped_nsobject<BookmarkContextMenuCocoaController>
contextMenuController_; contextMenuController_;
// Weak pointer to the pulsed button for the currently pulsing node. We need // The pulsed button for the currently pulsing node. We need to store this as
// to store this as it may not be possible to determine the pulsing button if // it may not be possible to determine the pulsing button if the pulsing node
// the pulsing node is deleted. Nil if there is no pulsing node. // is deleted. Nil if there is no pulsing node.
BookmarkButton* pulsingButton_; base::scoped_nsobject<BookmarkButton> pulsingButton_;
// Specifically watch the currently pulsing node. This lets us stop pulsing // Specifically watch the currently pulsing node. This lets us stop pulsing
// when anything happens to the node. Null if there is no pulsing node. // when anything happens to the node. Null if there is no pulsing node.
......
...@@ -361,7 +361,8 @@ void RecordAppLaunch(Profile* profile, GURL url) { ...@@ -361,7 +361,8 @@ void RecordAppLaunch(Profile* profile, GURL url) {
- (void)startPulsingBookmarkNode:(const BookmarkNode*)node { - (void)startPulsingBookmarkNode:(const BookmarkNode*)node {
[self stopPulsingBookmarkNode]; [self stopPulsingBookmarkNode];
pulsingButton_ = [self bookmarkButtonToPulseForNode:node]; pulsingButton_.reset([self bookmarkButtonToPulseForNode:node],
base::scoped_policy::RETAIN);
if (!pulsingButton_) if (!pulsingButton_)
return; return;
...@@ -379,7 +380,7 @@ void RecordAppLaunch(Profile* profile, GURL url) { ...@@ -379,7 +380,7 @@ void RecordAppLaunch(Profile* profile, GURL url) {
return; return;
[pulsingButton_ setPulseIsStuckOn:NO]; [pulsingButton_ setPulseIsStuckOn:NO];
pulsingButton_ = nil; pulsingButton_.reset();
pulsingBookmarkObserver_.reset(); pulsingBookmarkObserver_.reset();
} }
......
...@@ -1568,6 +1568,46 @@ TEST_F(BookmarkBarControllerTest, ShrinkOrHideView) { ...@@ -1568,6 +1568,46 @@ TEST_F(BookmarkBarControllerTest, ShrinkOrHideView) {
EXPECT_TRUE([view isHidden]); EXPECT_TRUE([view isHidden]);
} }
// Simulate coarse browser window width change and ensure that the bookmark
// buttons that should be visible are visible.
TEST_F(BookmarkBarControllerTest, RedistributeButtonsOnBarAsNeeded) {
// Hide the apps shortcut.
profile()->GetPrefs()->SetBoolean(
bookmarks::prefs::kShowAppsShortcutInBookmarkBar, false);
ASSERT_TRUE([bar_ appsPageShortcutButtonIsHidden]);
// Add three buttons to the bookmark bar.
BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile());
const BookmarkNode* root = model->bookmark_bar_node();
// Make long labels to test coarse resizes. After 16 digits, text eliding
// starts.
const std::string model_string(
"0000000000000000 1111111111111111 2222222222222222 ");
bookmarks::test::AddNodesFromModelString(model, root, model_string);
NSRect frame = [[bar_ view] frame];
frame.size.width = 400; // Typical minimum browser size.
[[bar_ view] setFrame:frame];
EXPECT_EQ(2, [bar_ displayedButtonCount]);
{
base::mac::ScopedNSAutoreleasePool pool;
frame.size.width = 800;
[[bar_ view] setFrame:frame];
EXPECT_EQ(3, [bar_ displayedButtonCount]);
const BookmarkNode* last = model->bookmark_bar_node()->GetChild(2);
EXPECT_TRUE(last);
[bar_ startPulsingBookmarkNode:last];
frame.size.width = 400;
[[bar_ view] setFrame:frame];
EXPECT_EQ(2, [bar_ displayedButtonCount]);
}
// Regression test for http://crbug.com/616051.
[bar_ stopPulsingBookmarkNode];
}
// Simiulate browser window width change and ensure that the bookmark buttons // Simiulate browser window width change and ensure that the bookmark buttons
// that should be visible are visible. // that should be visible are visible.
// Appears to fail on Mac 10.11 bot on the waterfall; http://crbug.com/612640. // Appears to fail on Mac 10.11 bot on the waterfall; http://crbug.com/612640.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment