Chromium Code Reviews| Index: chrome/browser/search_engines/template_url_service.cc |
| =================================================================== |
| --- chrome/browser/search_engines/template_url_service.cc (revision 222964) |
| +++ chrome/browser/search_engines/template_url_service.cc (working copy) |
| @@ -1535,25 +1535,37 @@ |
| } |
| } |
| -void TemplateURLService::SetTemplateURLs(const TemplateURLVector& urls) { |
| - // Add mappings for the new items. |
| +// Helper for partition() call in next function. |
| +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)); |
|
beaudoin
2013/09/14 03:24:03
Clever use of partition!
|
| + |
| + // 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) { |
| - if ((*i)->id() != kInvalidTemplateURLID) { |
| - next_id_ = std::max(next_id_, (*i)->id()); |
| - AddNoNotify(*i, false); |
| - } |
| + next_id_ = std::max(next_id_, (*i)->id()); |
| + AddNoNotify(*i, false); |
| } |
| // Next add the new items that don't have id's. |
| - for (TemplateURLVector::const_iterator i = urls.begin(); i != urls.end(); |
| - ++i) { |
| - if ((*i)->id() == kInvalidTemplateURLID) |
| - AddNoNotify(*i, true); |
| - } |
| + for (TemplateURLVector::const_iterator i = first_invalid; i != urls->end(); |
| + ++i) |
| + 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() { |
| @@ -2533,7 +2545,7 @@ |
| PatchMissingSyncGUIDs(template_urls); |
| if (is_default_search_managed_) { |
| - SetTemplateURLs(*template_urls); |
| + SetTemplateURLs(template_urls); |
| if (TemplateURLsHaveSamePrefs(default_search_provider, |
| default_from_prefs.get())) { |
| @@ -2581,7 +2593,7 @@ |
| default_search_provider_ = default_search_provider; |
| default_search_provider = NULL; |
| } |
| - SetTemplateURLs(*template_urls); |
| + SetTemplateURLs(template_urls); |
| if (default_search_provider) { |
| // Note that this saves the default search provider to prefs. |