Commit 224cfac1 authored by pkasting@chromium.org's avatar pkasting@chromium.org

Fix read-after-free when loading two search engines with the same keyword.

BUG=232657
TEST=none
R=beaudoin@chromium.org

Review URL: https://codereview.chromium.org/23536053

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@223418 0039d316-1c4b-4281-b951-d872f2087c98
parent 45fabd32
...@@ -1535,25 +1535,37 @@ void TemplateURLService::AddToMaps(TemplateURL* template_url) { ...@@ -1535,25 +1535,37 @@ void TemplateURLService::AddToMaps(TemplateURL* template_url) {
} }
} }
void TemplateURLService::SetTemplateURLs(const TemplateURLVector& urls) { // Helper for partition() call in next function.
// Add mappings for the new items. bool HasValidID(TemplateURL* t_url) {
return t_url->id() != kInvalidTemplateURLID;
// First, add the items that already have id's, so that the next_id_ }
// gets properly set.
for (TemplateURLVector::const_iterator i = urls.begin(); i != urls.end(); void TemplateURLService::SetTemplateURLs(TemplateURLVector* urls) {
// Partition the URLs first, instead of implementing the loops below by simply
// scanning the input twice. While it's not supposed to happen normally, it's
// possible for corrupt databases to return multiple entries with the same
// keyword. In this case, the first loop may delete the first entry when
// adding the second. If this happens, the second loop must not attempt to
// access the deleted entry. Partitioning ensures this constraint.
TemplateURLVector::iterator first_invalid(
std::partition(urls->begin(), urls->end(), HasValidID));
// First, add the items that already have id's, so that the next_id_ gets
// properly set.
for (TemplateURLVector::const_iterator i = urls->begin(); i != first_invalid;
++i) { ++i) {
if ((*i)->id() != kInvalidTemplateURLID) { next_id_ = std::max(next_id_, (*i)->id());
next_id_ = std::max(next_id_, (*i)->id()); AddNoNotify(*i, false);
AddNoNotify(*i, false);
}
} }
// Next add the new items that don't have id's. // Next add the new items that don't have id's.
for (TemplateURLVector::const_iterator i = urls.begin(); i != urls.end(); for (TemplateURLVector::const_iterator i = first_invalid; i != urls->end();
++i) { ++i)
if ((*i)->id() == kInvalidTemplateURLID) AddNoNotify(*i, true);
AddNoNotify(*i, true);
} // Clear the input vector to reduce the chance callers will try to use a
// (possibly deleted) entry.
urls->clear();
} }
void TemplateURLService::ChangeToLoadedState() { void TemplateURLService::ChangeToLoadedState() {
...@@ -2533,7 +2545,7 @@ void TemplateURLService::AddTemplateURLsAndSetupDefaultEngine( ...@@ -2533,7 +2545,7 @@ void TemplateURLService::AddTemplateURLsAndSetupDefaultEngine(
PatchMissingSyncGUIDs(template_urls); PatchMissingSyncGUIDs(template_urls);
if (is_default_search_managed_) { if (is_default_search_managed_) {
SetTemplateURLs(*template_urls); SetTemplateURLs(template_urls);
if (TemplateURLsHaveSamePrefs(default_search_provider, if (TemplateURLsHaveSamePrefs(default_search_provider,
default_from_prefs.get())) { default_from_prefs.get())) {
...@@ -2581,7 +2593,7 @@ void TemplateURLService::AddTemplateURLsAndSetupDefaultEngine( ...@@ -2581,7 +2593,7 @@ void TemplateURLService::AddTemplateURLsAndSetupDefaultEngine(
default_search_provider_ = default_search_provider; default_search_provider_ = default_search_provider;
default_search_provider = NULL; default_search_provider = NULL;
} }
SetTemplateURLs(*template_urls); SetTemplateURLs(template_urls);
if (default_search_provider) { if (default_search_provider) {
// Note that this saves the default search provider to prefs. // Note that this saves the default search provider to prefs.
......
...@@ -425,7 +425,11 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -425,7 +425,11 @@ class TemplateURLService : public WebDataServiceConsumer,
// Sets the keywords. This is used once the keywords have been loaded. // Sets the keywords. This is used once the keywords have been loaded.
// This does NOT notify the delegate or the database. // This does NOT notify the delegate or the database.
void SetTemplateURLs(const TemplateURLVector& urls); //
// This transfers ownership of the elements in |urls| to |this|, and may
// delete some elements, so it's not safe for callers to access any elements
// after calling; to reinforce this, this function clears |urls| on exit.
void SetTemplateURLs(TemplateURLVector* urls);
// Transitions to the loaded state. // Transitions to the loaded state.
void ChangeToLoadedState(); void ChangeToLoadedState();
...@@ -615,6 +619,11 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -615,6 +619,11 @@ class TemplateURLService : public WebDataServiceConsumer,
// Adds |template_urls| to |template_urls_| and sets up the default search // Adds |template_urls| to |template_urls_| and sets up the default search
// provider. If |default_search_provider| is non-NULL, it must refer to one // provider. If |default_search_provider| is non-NULL, it must refer to one
// of the |template_urls|, and will be used as the new default. // of the |template_urls|, and will be used as the new default.
//
// This transfers ownership of the elements in |template_urls| to |this|, and
// may delete some elements, so it's not safe for callers to access any
// elements after calling; to reinforce this, this function clears
// |template_urls| on exit.
void AddTemplateURLsAndSetupDefaultEngine( void AddTemplateURLsAndSetupDefaultEngine(
TemplateURLVector* template_urls, TemplateURLVector* template_urls,
TemplateURL* default_search_provider); TemplateURL* default_search_provider);
......
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