Chromium Code Reviews| Index: components/sessions/core/tab_restore_service_helper.cc |
| diff --git a/components/sessions/core/tab_restore_service_helper.cc b/components/sessions/core/tab_restore_service_helper.cc |
| index 73a4c72f6530d3dd4003e016178feb103c6fffc6..cc3f2ae80af6260108bdefebf3fcb4a74d5119bc 100644 |
| --- a/components/sessions/core/tab_restore_service_helper.cc |
| +++ b/components/sessions/core/tab_restore_service_helper.cc |
| @@ -10,6 +10,7 @@ |
| #include <iterator> |
| #include "base/logging.h" |
| +#include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram.h" |
| #include "base/stl_util.h" |
| #include "components/sessions/core/live_tab.h" |
| @@ -52,7 +53,6 @@ TabRestoreServiceHelper::TabRestoreServiceHelper( |
| TabRestoreServiceHelper::~TabRestoreServiceHelper() { |
| FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, |
| TabRestoreServiceDestroyed(tab_restore_service_)); |
| - STLDeleteElements(&entries_); |
| } |
| void TabRestoreServiceHelper::AddObserver( |
| @@ -74,48 +74,39 @@ void TabRestoreServiceHelper::CreateHistoricalTab(LiveTab* live_tab, |
| if (closing_contexts_.find(context) != closing_contexts_.end()) |
| return; |
| - std::unique_ptr<Tab> local_tab(new Tab()); |
| + auto local_tab = base::MakeUnique<Tab>(); |
| PopulateTab(local_tab.get(), index, context, live_tab); |
| if (local_tab->navigations.empty()) |
| return; |
| - AddEntry(local_tab.release(), true, true); |
| + AddEntry(std::move(local_tab), true, true); |
| } |
| void TabRestoreServiceHelper::BrowserClosing(LiveTabContext* context) { |
| closing_contexts_.insert(context); |
| - std::unique_ptr<Window> window(new Window()); |
| + auto window = base::MakeUnique<Window>(); |
| window->selected_tab_index = context->GetSelectedIndex(); |
| window->timestamp = TimeNow(); |
| window->app_name = context->GetAppName(); |
| - // Don't use std::vector::resize() because it will push copies of an empty tab |
| - // into the vector, which will give all tabs in a window the same ID. |
| - for (int i = 0; i < context->GetTabCount(); ++i) { |
| - window->tabs.push_back(Tab()); |
| - } |
| - size_t entry_index = 0; |
| for (int tab_index = 0; tab_index < context->GetTabCount(); ++tab_index) { |
| - PopulateTab(&(window->tabs[entry_index]), tab_index, context, |
| + auto tab = base::MakeUnique<Tab>(); |
| + PopulateTab(tab.get(), tab_index, context, |
| context->GetLiveTabAt(tab_index)); |
| - if (window->tabs[entry_index].navigations.empty()) { |
| - window->tabs.erase(window->tabs.begin() + entry_index); |
| - } else { |
| - window->tabs[entry_index].browser_id = context->GetSessionID().id(); |
| - entry_index++; |
| + if (!tab->navigations.empty()) { |
| + tab->browser_id = context->GetSessionID().id(); |
| + window->tabs.push_back(std::move(tab)); |
| } |
| } |
| if (window->tabs.size() == 1 && window->app_name.empty()) { |
| // Short-circuit creating a Window if only 1 tab was present. This fixes |
| - // http://crbug.com/56744. Copy the Tab because it's owned by an object on |
| - // the stack. |
| - AddEntry(new Tab(window->tabs[0]), true, true); |
| + // http://crbug.com/56744. |
| + AddEntry(std::move(window->tabs[0]), true, true); |
| } else if (!window->tabs.empty()) { |
| - window->selected_tab_index = |
| - std::min(static_cast<int>(window->tabs.size() - 1), |
| - window->selected_tab_index); |
| - AddEntry(window.release(), true, true); |
| + window->selected_tab_index = std::min( |
| + static_cast<int>(window->tabs.size() - 1), window->selected_tab_index); |
| + AddEntry(std::move(window), true, true); |
| } |
| } |
| @@ -126,7 +117,7 @@ void TabRestoreServiceHelper::BrowserClosed(LiveTabContext* context) { |
| void TabRestoreServiceHelper::ClearEntries() { |
| if (observer_) |
| observer_->OnClearEntries(); |
| - STLDeleteElements(&entries_); |
| + entries_.clear(); |
| NotifyTabsChanged(); |
| } |
| @@ -141,17 +132,16 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreMostRecentEntry( |
| return RestoreEntryById(context, entries_.front()->id, UNKNOWN); |
| } |
| -TabRestoreService::Tab* TabRestoreServiceHelper::RemoveTabEntryById( |
| - SessionID::id_type id) { |
| - Entries::iterator it = GetEntryIteratorById(id); |
| +std::unique_ptr<TabRestoreService::Tab> |
| +TabRestoreServiceHelper::RemoveTabEntryById(SessionID::id_type id) { |
| + auto it = GetEntryIteratorById(id); |
| if (it == entries_.end()) |
| return nullptr; |
| - Entry* entry = *it; |
| - if (entry->type != TabRestoreService::TAB) |
| + if ((*it)->type != TabRestoreService::TAB) |
| return nullptr; |
| - Tab* tab = static_cast<Tab*>(entry); |
| + auto tab = std::unique_ptr<Tab>(static_cast<Tab*>(it->release())); |
| entries_.erase(it); |
| return tab; |
| } |
| @@ -169,97 +159,99 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById( |
| if (observer_) |
| observer_->OnRestoreEntryById(id, entry_iterator); |
| restoring_ = true; |
| - Entry* entry = *entry_iterator; |
| + auto& entry = **entry_iterator; |
| // If the entry's ID does not match the ID that is being restored, then the |
| // entry is a window from which a single tab will be restored. |
| - bool restoring_tab_in_window = entry->id != id; |
| - |
| - if (!restoring_tab_in_window) { |
| - entries_.erase(entry_iterator); |
| - entry_iterator = entries_.end(); |
| - } |
| + bool restoring_tab_in_window = entry.id != id; |
| // |context| will be NULL in cases where one isn't already available (eg, |
| // when invoked on Mac OS X with no windows open). In this case, create a |
| // new browser into which we restore the tabs. |
| std::vector<LiveTab*> live_tabs; |
| - if (entry->type == TabRestoreService::TAB) { |
| - Tab* tab = static_cast<Tab*>(entry); |
| - LiveTab* restored_tab = nullptr; |
| - context = RestoreTab(*tab, context, disposition, &restored_tab); |
| - live_tabs.push_back(restored_tab); |
| - context->ShowBrowserWindow(); |
| - } else if (entry->type == TabRestoreService::WINDOW) { |
| - LiveTabContext* current_context = context; |
| - Window* window = static_cast<Window*>(entry); |
| - |
| - // When restoring a window, either the entire window can be restored, or a |
| - // single tab within it. If the entry's ID matches the one to restore, then |
| - // the entire window will be restored. |
| - if (!restoring_tab_in_window) { |
| - context = client_->CreateLiveTabContext(window->app_name); |
| - for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { |
| - const Tab& tab = window->tabs[tab_i]; |
| - LiveTab* restored_tab = context->AddRestoredTab( |
| - tab.navigations, context->GetTabCount(), |
| - tab.current_navigation_index, tab.extension_app_id, |
| - static_cast<int>(tab_i) == window->selected_tab_index, tab.pinned, |
| - tab.from_last_session, tab.platform_data.get(), |
| - tab.user_agent_override); |
| - if (restored_tab) { |
| - restored_tab->LoadIfNecessary(); |
| - client_->OnTabRestored( |
| - tab.navigations.at(tab.current_navigation_index).virtual_url()); |
| - live_tabs.push_back(restored_tab); |
| + switch (entry.type) { |
| + case TabRestoreService::TAB: { |
| + auto& tab = static_cast<const Tab&>(entry); |
| + LiveTab* restored_tab = nullptr; |
| + context = RestoreTab(tab, context, disposition, &restored_tab); |
| + live_tabs.push_back(restored_tab); |
| + context->ShowBrowserWindow(); |
| + break; |
| + } |
| + case TabRestoreService::WINDOW: { |
| + LiveTabContext* current_context = context; |
| + auto& window = static_cast<Window&>(entry); |
| + |
| + // When restoring a window, either the entire window can be restored, or a |
| + // single tab within it. If the entry's ID matches the one to restore, |
| + // then the entire window will be restored. |
| + if (!restoring_tab_in_window) { |
| + context = client_->CreateLiveTabContext(window.app_name); |
| + for (size_t tab_i = 0; tab_i < window.tabs.size(); ++tab_i) { |
| + const Tab& tab = *window.tabs[tab_i]; |
| + LiveTab* restored_tab = context->AddRestoredTab( |
| + tab.navigations, context->GetTabCount(), |
| + tab.current_navigation_index, tab.extension_app_id, |
| + static_cast<int>(tab_i) == window.selected_tab_index, tab.pinned, |
| + tab.from_last_session, tab.platform_data.get(), |
| + tab.user_agent_override); |
| + if (restored_tab) { |
| + restored_tab->LoadIfNecessary(); |
| + client_->OnTabRestored( |
| + tab.navigations.at(tab.current_navigation_index).virtual_url()); |
| + live_tabs.push_back(restored_tab); |
| + } |
| } |
| - } |
| - // All the window's tabs had the same former browser_id. |
| - if (window->tabs[0].has_browser()) { |
| - UpdateTabBrowserIDs(window->tabs[0].browser_id, |
| - context->GetSessionID().id()); |
| - } |
| - } else { |
| - // Restore a single tab from the window. Find the tab that matches the ID |
| - // in the window and restore it. |
| - for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); |
| - tab_i != window->tabs.end(); ++tab_i) { |
| - const Tab& tab = *tab_i; |
| - if (tab.id != id) |
| - continue; |
| - |
| - LiveTab* restored_tab = nullptr; |
| - context = RestoreTab(tab, context, disposition, &restored_tab); |
| - live_tabs.push_back(restored_tab); |
| - window->tabs.erase(tab_i); |
| - // If restoring the tab leaves the window with nothing else, delete it |
| - // as well. |
| - if (window->tabs.empty()) { |
| - entries_.erase(entry_iterator); |
| - delete entry; |
| - } else { |
| - // Update the browser ID of the rest of the tabs in the window so if |
| - // any one is restored, it goes into the same window as the tab |
| - // being restored now. |
| - UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id()); |
| - for (Tab& tab_j : window->tabs) |
| - tab_j.browser_id = context->GetSessionID().id(); |
| + // All the window's tabs had the same former browser_id. |
| + if (auto browser_id = window.tabs[0]->browser_id) { |
| + UpdateTabBrowserIDs(browser_id, context->GetSessionID().id()); |
| + } |
| + } else { |
| + // Restore a single tab from the window. Find the tab that matches the |
| + // ID |
| + // in the window and restore it. |
| + for (auto tab_i = window.tabs.begin(); tab_i != window.tabs.end(); |
| + ++tab_i) { |
| + SessionID::id_type restored_tab_browser_id; |
| + { |
| + const Tab& tab = **tab_i; |
| + if (tab.id != id) |
| + continue; |
| + |
| + restored_tab_browser_id = tab.browser_id; |
| + LiveTab* restored_tab = nullptr; |
| + context = RestoreTab(tab, context, disposition, &restored_tab); |
| + live_tabs.push_back(restored_tab); |
| + window.tabs.erase(tab_i); |
| + } |
|
Sidney San Martín
2016/08/04 04:24:57
I had a use-after free here, so I'm using a block
|
| + // If restoring the tab leaves the window with nothing else, delete it |
| + // as well. |
| + if (window.tabs.empty()) { |
| + entries_.erase(entry_iterator); |
| + } else { |
| + // Update the browser ID of the rest of the tabs in the window so if |
| + // any one is restored, it goes into the same window as the tab |
| + // being restored now. |
| + UpdateTabBrowserIDs(restored_tab_browser_id, |
| + context->GetSessionID().id()); |
| + for (auto& tab_j : window.tabs) |
| + tab_j->browser_id = context->GetSessionID().id(); |
| + } |
| + break; |
| } |
| - break; |
| } |
| - } |
| - context->ShowBrowserWindow(); |
| + context->ShowBrowserWindow(); |
| - if (disposition == CURRENT_TAB && current_context && |
| - current_context->GetActiveLiveTab()) { |
| - current_context->CloseTab(); |
| + if (disposition == CURRENT_TAB && current_context && |
| + current_context->GetActiveLiveTab()) { |
| + current_context->CloseTab(); |
| + } |
| + break; |
| } |
| - } else { |
| - NOTREACHED(); |
| } |
| if (!restoring_tab_in_window) { |
| - delete entry; |
| + entries_.erase(entry_iterator); |
| } |
| restoring_ = false; |
| @@ -277,18 +269,17 @@ void TabRestoreServiceHelper::NotifyLoaded() { |
| TabRestoreServiceLoaded(tab_restore_service_)); |
| } |
| -void TabRestoreServiceHelper::AddEntry(Entry* entry, |
| +void TabRestoreServiceHelper::AddEntry(std::unique_ptr<Entry> entry, |
| bool notify, |
| bool to_front) { |
| - if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) { |
| - delete entry; |
| + if (!FilterEntry(*entry) || (entries_.size() >= kMaxEntries && !to_front)) { |
| return; |
| } |
| if (to_front) |
| - entries_.push_front(entry); |
| + entries_.push_front(std::move(entry)); |
| else |
| - entries_.push_back(entry); |
| + entries_.push_back(std::move(entry)); |
| PruneEntries(); |
| @@ -302,19 +293,13 @@ void TabRestoreServiceHelper::AddEntry(Entry* entry, |
| void TabRestoreServiceHelper::PruneEntries() { |
| Entries new_entries; |
| - for (TabRestoreService::Entries::const_iterator iter = entries_.begin(); |
| - iter != entries_.end(); ++iter) { |
| - TabRestoreService::Entry* entry = *iter; |
| - |
| - if (FilterEntry(entry) && |
| - new_entries.size() < kMaxEntries) { |
| - new_entries.push_back(entry); |
| - } else { |
| - delete entry; |
| + for (auto& entry : entries_) { |
| + if (FilterEntry(*entry) && new_entries.size() < kMaxEntries) { |
| + new_entries.push_back(std::move(entry)); |
| } |
| } |
| - entries_ = new_entries; |
| + entries_ = std::move(new_entries); |
| } |
| TabRestoreService::Entries::iterator |
| @@ -326,10 +311,9 @@ TabRestoreServiceHelper::GetEntryIteratorById(SessionID::id_type id) { |
| // For Window entries, see if the ID matches a tab. If so, report the window |
| // as the Entry. |
| if ((*i)->type == TabRestoreService::WINDOW) { |
| - std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs; |
| - for (std::vector<Tab>::iterator j = tabs.begin(); |
| - j != tabs.end(); ++j) { |
| - if ((*j).id == id) { |
| + auto& window = static_cast<const Window&>(**i); |
| + for (const auto& tab : window.tabs) { |
| + if (tab->id == id) { |
| return i; |
| } |
| } |
| @@ -339,13 +323,13 @@ TabRestoreServiceHelper::GetEntryIteratorById(SessionID::id_type id) { |
| } |
| // static |
| -bool TabRestoreServiceHelper::ValidateEntry(Entry* entry) { |
| - if (entry->type == TabRestoreService::TAB) |
| - return ValidateTab(static_cast<Tab*>(entry)); |
| - |
| - if (entry->type == TabRestoreService::WINDOW) |
| - return ValidateWindow(static_cast<Window*>(entry)); |
| - |
| +bool TabRestoreServiceHelper::ValidateEntry(const Entry& entry) { |
| + switch (entry.type) { |
| + case TabRestoreService::TAB: |
| + return ValidateTab(static_cast<const Tab&>(entry)); |
| + case TabRestoreService::WINDOW: |
| + return ValidateWindow(static_cast<const Window&>(entry)); |
| + } |
| NOTREACHED(); |
| return false; |
| } |
| @@ -368,8 +352,6 @@ void TabRestoreServiceHelper::PopulateTab(Tab* tab, |
| } |
| tab->timestamp = TimeNow(); |
| tab->current_navigation_index = live_tab->GetCurrentEntryIndex(); |
| - if (tab->current_navigation_index == -1 && entry_count > 0) |
| - tab->current_navigation_index = 0; |
| tab->tabstrip_index = index; |
| tab->extension_app_id = client_->GetExtensionAppIDForTab(live_tab); |
| @@ -397,7 +379,7 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab( |
| tab.extension_app_id, tab.platform_data.get(), tab.user_agent_override); |
| } else { |
| // We only respsect the tab's original browser if there's no disposition. |
| - if (disposition == UNKNOWN && tab.has_browser()) { |
| + if (disposition == UNKNOWN && tab.browser_id) { |
| context = client_->FindLiveTabContextWithID(tab.browser_id); |
| } |
| @@ -410,7 +392,7 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab( |
| tab_index = tab.tabstrip_index; |
| } else { |
| context = client_->CreateLiveTabContext(std::string()); |
| - if (tab.has_browser()) |
| + if (tab.browser_id) |
| UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id()); |
| } |
| @@ -436,86 +418,68 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab( |
| return context; |
| } |
| +bool TabRestoreServiceHelper::ValidateTab(const Tab& tab) { |
| + return !tab.navigations.empty() && |
| + static_cast<size_t>(tab.current_navigation_index) < |
| + tab.navigations.size(); |
| +} |
| -bool TabRestoreServiceHelper::ValidateTab(Tab* tab) { |
| - if (tab->navigations.empty()) |
| +bool TabRestoreServiceHelper::ValidateWindow(const Window& window) { |
| + if (static_cast<size_t>(window.selected_tab_index) >= window.tabs.size()) { |
| return false; |
| + } |
| - tab->current_navigation_index = |
| - std::max(0, std::min(tab->current_navigation_index, |
| - static_cast<int>(tab->navigations.size()) - 1)); |
| - |
| - return true; |
| -} |
| - |
| -bool TabRestoreServiceHelper::ValidateWindow(Window* window) { |
| - window->selected_tab_index = |
| - std::max(0, std::min(window->selected_tab_index, |
| - static_cast<int>(window->tabs.size() - 1))); |
| - |
| - int i = 0; |
| - for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); |
| - tab_i != window->tabs.end();) { |
| - if (!ValidateTab(&(*tab_i))) { |
| - tab_i = window->tabs.erase(tab_i); |
| - if (i < window->selected_tab_index) |
| - window->selected_tab_index--; |
| - else if (i == window->selected_tab_index) |
| - window->selected_tab_index = 0; |
| - } else { |
| - ++tab_i; |
| - ++i; |
| + for (const auto& tab : window.tabs) { |
| + if (!ValidateTab(*tab)) { |
| + return false; |
| } |
| } |
| - if (window->tabs.empty()) |
| - return false; |
| - |
| return true; |
| } |
| -bool TabRestoreServiceHelper::IsTabInteresting(const Tab* tab) { |
| - if (tab->navigations.empty()) |
| +bool TabRestoreServiceHelper::IsTabInteresting(const Tab& tab) { |
| + if (tab.navigations.empty()) |
| return false; |
| - if (tab->navigations.size() > 1) |
| + if (tab.navigations.size() > 1) |
| return true; |
| - return tab->pinned || |
| - tab->navigations.at(0).virtual_url() != client_->GetNewTabURL(); |
| + return tab.pinned || |
| + tab.navigations.at(0).virtual_url() != client_->GetNewTabURL(); |
| } |
| -bool TabRestoreServiceHelper::IsWindowInteresting(const Window* window) { |
| - if (window->tabs.empty()) |
| +bool TabRestoreServiceHelper::IsWindowInteresting(const Window& window) { |
| + if (window.tabs.empty()) |
| return false; |
| - if (window->tabs.size() > 1) |
| + if (window.tabs.size() > 1) |
| return true; |
| - return IsTabInteresting(&window->tabs[0]); |
| + return IsTabInteresting(*window.tabs[0]); |
| } |
| -bool TabRestoreServiceHelper::FilterEntry(Entry* entry) { |
| +bool TabRestoreServiceHelper::FilterEntry(const Entry& entry) { |
| if (!ValidateEntry(entry)) |
| return false; |
| - if (entry->type == TabRestoreService::TAB) |
| - return IsTabInteresting(static_cast<Tab*>(entry)); |
| - else if (entry->type == TabRestoreService::WINDOW) |
| - return IsWindowInteresting(static_cast<Window*>(entry)); |
| - |
| + switch (entry.type) { |
| + case TabRestoreService::TAB: |
| + return IsTabInteresting(static_cast<const Tab&>(entry)); |
| + case TabRestoreService::WINDOW: |
| + return IsWindowInteresting(static_cast<const Window&>(entry)); |
| + } |
| NOTREACHED(); |
| return false; |
| } |
| void TabRestoreServiceHelper::UpdateTabBrowserIDs(SessionID::id_type old_id, |
| SessionID::id_type new_id) { |
| - for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { |
| - Entry* entry = *i; |
| + for (const auto& entry : entries_) { |
| if (entry->type == TabRestoreService::TAB) { |
| - Tab* tab = static_cast<Tab*>(entry); |
| - if (tab->browser_id == old_id) |
| - tab->browser_id = new_id; |
| + auto& tab = static_cast<Tab&>(*entry); |
| + if (tab.browser_id == old_id) |
| + tab.browser_id = new_id; |
| } |
| } |
| } |