Commit 0f1c3f2d authored by Chris Hamilton's avatar Chris Hamilton Committed by Commit Bot

[PM] Fix null deref in TabLoadingFrameNavigationScheduler.

BUG=1083912

Change-Id: I2a5662f08e295cfc7a65c5aa0ba905c3fba84524
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2209376
Commit-Queue: Chris Hamilton <chrisha@chromium.org>
Reviewed-by: default avatarSigurður Ásgeirsson <siggi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770587}
parent 53d7e068
...@@ -228,8 +228,10 @@ void TabLoadingFrameNavigationScheduler::StopThrottling( ...@@ -228,8 +228,10 @@ void TabLoadingFrameNavigationScheduler::StopThrottling(
// a StopThrottling notification. // a StopThrottling notification.
auto* scheduler = FromWebContents(contents); auto* scheduler = FromWebContents(contents);
// There is a race between renavigations and policy messages. Only dispatch // There is a race between renavigations and policy messages. Only dispatch
// this if its intended for the appropriate navigation ID. // this if the contents is still being throttled (the logic in
if (scheduler->navigation_id_ != last_navigation_id) // MaybeCreateThrottleForNavigation can cause the scheduler to be deleted),
// and if its intended for the appropriate navigation ID.
if (!scheduler || scheduler->navigation_id_ != last_navigation_id)
return; return;
scheduler->StopThrottlingImpl(); scheduler->StopThrottlingImpl();
} }
......
...@@ -150,10 +150,10 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, ...@@ -150,10 +150,10 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
// false. // false.
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents)) EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents))
.WillOnce(testing::Invoke([&run_loop](content::WebContents*) -> bool { .WillOnce([&run_loop](content::WebContents*) -> bool {
run_loop.Quit(); run_loop.Quit();
return false; return false;
})); });
StartNavigation(contents, url); StartNavigation(contents, url);
run_loop.Run(); run_loop.Run();
auto* scheduler = GetScheduler(contents); auto* scheduler = GetScheduler(contents);
...@@ -177,10 +177,10 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, ...@@ -177,10 +177,10 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents1)) EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents1))
.WillOnce(testing::Invoke([&run_loop](content::WebContents*) -> bool { .WillOnce([&run_loop](content::WebContents*) -> bool {
run_loop.Quit(); run_loop.Quit();
return true; return true;
})); });
StartNavigation(contents1, url1); StartNavigation(contents1, url1);
run_loop.Run(); run_loop.Run();
auto* scheduler = GetScheduler(contents1); auto* scheduler = GetScheduler(contents1);
...@@ -192,10 +192,10 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, ...@@ -192,10 +192,10 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents2)) EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents2))
.WillOnce(testing::Invoke([&run_loop](content::WebContents*) -> bool { .WillOnce([&run_loop](content::WebContents*) -> bool {
run_loop.Quit(); run_loop.Quit();
return true; return true;
})); });
StartNavigation(contents2, url2); StartNavigation(contents2, url2);
run_loop.Run(); run_loop.Run();
auto* scheduler = GetScheduler(contents2); auto* scheduler = GetScheduler(contents2);
...@@ -225,16 +225,15 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, ...@@ -225,16 +225,15 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
base::RunLoop run_loop1; base::RunLoop run_loop1;
base::RunLoop run_loop2; base::RunLoop run_loop2;
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents)) EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents))
.WillOnce(testing::Invoke([&run_loop1](content::WebContents*) -> bool { .WillOnce([&run_loop1](content::WebContents*) -> bool {
run_loop1.Quit(); run_loop1.Quit();
return true; return true;
})); });
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleNavigation(testing::_)) EXPECT_CALL(mock_policy_delegate_, ShouldThrottleNavigation(testing::_))
.WillOnce( .WillOnce([&run_loop2](content::NavigationHandle*) -> bool {
testing::Invoke([&run_loop2](content::NavigationHandle*) -> bool { run_loop2.Quit();
run_loop2.Quit(); return true;
return true; });
}));
// Start the navigation, and expect scheduler to have been created. // Start the navigation, and expect scheduler to have been created.
StartNavigation(contents, url); StartNavigation(contents, url);
...@@ -262,6 +261,68 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, ...@@ -262,6 +261,68 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
WaitForLoad(contents); WaitForLoad(contents);
} }
IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
NavigationCancelsThrottling) {
GURL url(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html"));
auto* contents = shell()->web_contents();
// Throttle the navigation, and throttle the child frame.
base::RunLoop run_loop1;
base::RunLoop run_loop2;
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents))
.WillOnce([&run_loop1](content::WebContents*) -> bool {
run_loop1.Quit();
return true;
});
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleNavigation(testing::_))
.WillOnce([&run_loop2](content::NavigationHandle*) -> bool {
run_loop2.Quit();
return true;
});
// Start the navigation, and expect scheduler to have been created.
StartNavigation(contents, url);
run_loop1.Run();
auto* scheduler = GetScheduler(contents);
EXPECT_NE(nullptr, scheduler);
EXPECT_EQ(0u, scheduler->GetThrottleCountForTesting());
int64_t original_navigation_id = scheduler->GetNavigationIdForTesting();
// Wait for the child navigation to have started. We'll know once
// the policy function has been invoked, which will quit the runloop.
run_loop2.Run();
// At this point the child frame navigation should be throttled, waiting for
// the policy object to notify that the throttles should be removed.
EXPECT_EQ(1u, scheduler->GetThrottleCountForTesting());
// Reuse the contents for another navigation. This should result in another
// call to ShouldThrottleWebContents (which returns false), and the
// scheduler should be deleted.
url = embedded_test_server()->GetURL("b.com", "/b.html");
base::RunLoop run_loop3;
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents))
.WillOnce([&run_loop3](content::WebContents* contents) -> bool {
run_loop3.Quit();
return false;
});
StartNavigation(contents, url);
run_loop3.Run();
scheduler = GetScheduler(contents);
EXPECT_EQ(nullptr, scheduler);
// Simulate a delayed arrival of a policy message for the previous navigation
// and expect it to do nothing.
TabLoadingFrameNavigationScheduler::StopThrottling(contents,
original_navigation_id);
scheduler = GetScheduler(contents);
EXPECT_EQ(nullptr, scheduler);
// Wait for the load to finish so that it's not ongoing while the test
// fixture tears down.
WaitForLoad(contents);
}
IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
NavigationInterruptsThrottling) { NavigationInterruptsThrottling) {
GURL url(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html")); GURL url(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html"));
...@@ -271,16 +332,15 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, ...@@ -271,16 +332,15 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
base::RunLoop run_loop1; base::RunLoop run_loop1;
base::RunLoop run_loop2; base::RunLoop run_loop2;
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents)) EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents))
.WillOnce(testing::Invoke([&run_loop1](content::WebContents*) -> bool { .WillOnce([&run_loop1](content::WebContents*) -> bool {
run_loop1.Quit(); run_loop1.Quit();
return true; return true;
})); });
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleNavigation(testing::_)) EXPECT_CALL(mock_policy_delegate_, ShouldThrottleNavigation(testing::_))
.WillOnce( .WillOnce([&run_loop2](content::NavigationHandle*) -> bool {
testing::Invoke([&run_loop2](content::NavigationHandle*) -> bool { run_loop2.Quit();
run_loop2.Quit(); return true;
return true; });
}));
// Start the navigation, and expect scheduler to have been created. // Start the navigation, and expect scheduler to have been created.
StartNavigation(contents, url); StartNavigation(contents, url);
...@@ -288,6 +348,7 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, ...@@ -288,6 +348,7 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
auto* scheduler = GetScheduler(contents); auto* scheduler = GetScheduler(contents);
EXPECT_NE(nullptr, scheduler); EXPECT_NE(nullptr, scheduler);
EXPECT_EQ(0u, scheduler->GetThrottleCountForTesting()); EXPECT_EQ(0u, scheduler->GetThrottleCountForTesting());
int64_t original_navigation_id = scheduler->GetNavigationIdForTesting();
// Wait for the child navigation to have started. We'll know once // Wait for the child navigation to have started. We'll know once
// the policy function has been invoked, which will quit the runloop. // the policy function has been invoked, which will quit the runloop.
...@@ -303,17 +364,24 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest, ...@@ -303,17 +364,24 @@ IN_PROC_BROWSER_TEST_F(TabLoadingFrameNavigationSchedulerTest,
url = embedded_test_server()->GetURL("b.com", "/b.html"); url = embedded_test_server()->GetURL("b.com", "/b.html");
base::RunLoop run_loop3; base::RunLoop run_loop3;
EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents)) EXPECT_CALL(mock_policy_delegate_, ShouldThrottleWebContents(contents))
.WillOnce( .WillOnce([&run_loop3](content::WebContents* contents) -> bool {
testing::Invoke([&run_loop3](content::WebContents* contents) -> bool { run_loop3.Quit();
run_loop3.Quit(); return true;
return true; });
}));
StartNavigation(contents, url); StartNavigation(contents, url);
run_loop3.Run(); run_loop3.Run();
scheduler = GetScheduler(contents); scheduler = GetScheduler(contents);
EXPECT_NE(nullptr, scheduler); EXPECT_NE(nullptr, scheduler);
EXPECT_EQ(0u, scheduler->GetThrottleCountForTesting()); EXPECT_EQ(0u, scheduler->GetThrottleCountForTesting());
// Simulate a delayed arrival of a policy message for the previous navigation
// and expect it to do nothing.
TabLoadingFrameNavigationScheduler::StopThrottling(contents,
original_navigation_id);
auto* scheduler2 = GetScheduler(contents);
EXPECT_EQ(scheduler, scheduler2);
EXPECT_EQ(0u, scheduler2->GetThrottleCountForTesting());
// Wait for the load to finish so that it's not ongoing while the test // Wait for the load to finish so that it's not ongoing while the test
// fixture tears down. // fixture tears down.
WaitForLoad(contents); WaitForLoad(contents);
......
...@@ -64,6 +64,7 @@ class TabLoadingFrameNavigationScheduler ...@@ -64,6 +64,7 @@ class TabLoadingFrameNavigationScheduler
static bool IsMechanismRegisteredForTesting(); static bool IsMechanismRegisteredForTesting();
void StopThrottlingForTesting() { StopThrottlingImpl(); } void StopThrottlingForTesting() { StopThrottlingImpl(); }
size_t GetThrottleCountForTesting() const { return throttles_.size(); } size_t GetThrottleCountForTesting() const { return throttles_.size(); }
int64_t GetNavigationIdForTesting() const { return navigation_id_; }
private: private:
friend class content::WebContentsUserData<TabLoadingFrameNavigationScheduler>; friend class content::WebContentsUserData<TabLoadingFrameNavigationScheduler>;
......
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