Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: chrome/browser/extensions/component_loader.cc

Issue 2504333003: Fix DictionaryValue leak in component_loader.cc (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/component_loader.h" 5 #include "chrome/browser/extensions/component_loader.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 return !base::CommandLine::ForCurrentProcess()->HasSwitch( 104 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
105 chromeos::switches::kGuestSession) && 105 chromeos::switches::kGuestSession) &&
106 user_manager::UserManager::IsInitialized() && 106 user_manager::UserManager::IsInitialized() &&
107 user_manager::UserManager::Get()->IsUserLoggedIn(); 107 user_manager::UserManager::Get()->IsUserLoggedIn();
108 } 108 }
109 #endif // defined(OS_CHROMEOS) 109 #endif // defined(OS_CHROMEOS)
110 110
111 } // namespace 111 } // namespace
112 112
113 ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo( 113 ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo(
114 const base::DictionaryValue* manifest, const base::FilePath& directory) 114 std::unique_ptr<base::DictionaryValue> manifest_param,
Devlin 2016/11/17 16:02:54 optional nit: I'd prefer to just call this manifes
lazyboy 2016/11/17 22:50:38 The issue why I did this is when we use |manifest|
Devlin 2016/11/17 23:34:48 ah, makes sense, I'm good with this.
115 : manifest(manifest), 115 const base::FilePath& directory)
116 root_directory(directory) { 116 : manifest(std::move(manifest_param)), root_directory(directory) {
117 if (!root_directory.IsAbsolute()) { 117 if (!root_directory.IsAbsolute()) {
118 CHECK(PathService::Get(chrome::DIR_RESOURCES, &root_directory)); 118 CHECK(PathService::Get(chrome::DIR_RESOURCES, &root_directory));
119 root_directory = root_directory.Append(directory); 119 root_directory = root_directory.Append(directory);
120 } 120 }
121 extension_id = GenerateId(manifest, root_directory); 121 extension_id = GenerateId(manifest.get(), root_directory);
122 } 122 }
123 123
124 ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo(
125 ComponentExtensionInfo&& other)
126 : manifest(std::move(other.manifest)),
127 root_directory(std::move(other.root_directory)),
128 extension_id(std::move(other.extension_id)) {}
129
130 ComponentLoader::ComponentExtensionInfo&
131 ComponentLoader::ComponentExtensionInfo::operator=(
132 ComponentExtensionInfo&& other) {
133 manifest = std::move(other.manifest);
134 root_directory = std::move(other.root_directory);
135 extension_id = std::move(other.extension_id);
136 return *this;
137 }
138
139 ComponentLoader::ComponentExtensionInfo::~ComponentExtensionInfo() {}
140
124 ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service, 141 ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service,
125 PrefService* profile_prefs, 142 PrefService* profile_prefs,
126 PrefService* local_state, 143 PrefService* local_state,
127 Profile* profile) 144 Profile* profile)
128 : profile_prefs_(profile_prefs), 145 : profile_prefs_(profile_prefs),
129 local_state_(local_state), 146 local_state_(local_state),
130 profile_(profile), 147 profile_(profile),
131 extension_service_(extension_service), 148 extension_service_(extension_service),
132 ignore_whitelist_for_testing_(false), 149 ignore_whitelist_for_testing_(false),
133 weak_factory_(this) {} 150 weak_factory_(this) {}
134 151
135 ComponentLoader::~ComponentLoader() { 152 ComponentLoader::~ComponentLoader() {
136 ClearAllRegistered(); 153 ClearAllRegistered();
137 } 154 }
138 155
139 void ComponentLoader::LoadAll() { 156 void ComponentLoader::LoadAll() {
140 TRACE_EVENT0("browser,startup", "ComponentLoader::LoadAll"); 157 TRACE_EVENT0("browser,startup", "ComponentLoader::LoadAll");
141 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.LoadAllComponentTime"); 158 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.LoadAllComponentTime");
142 159
143 for (RegisteredComponentExtensions::iterator it = 160 for (RegisteredComponentExtensions::iterator it =
144 component_extensions_.begin(); 161 component_extensions_.begin();
145 it != component_extensions_.end(); ++it) { 162 it != component_extensions_.end(); ++it) {
146 Load(*it); 163 Load(*it);
147 } 164 }
148 } 165 }
149 166
150 base::DictionaryValue* ComponentLoader::ParseManifest( 167 std::unique_ptr<base::DictionaryValue> ComponentLoader::ParseManifest(
151 base::StringPiece manifest_contents) const { 168 base::StringPiece manifest_contents) const {
152 JSONStringValueDeserializer deserializer(manifest_contents); 169 JSONStringValueDeserializer deserializer(manifest_contents);
153 std::unique_ptr<base::Value> manifest = deserializer.Deserialize(NULL, NULL); 170 std::unique_ptr<base::Value> manifest = deserializer.Deserialize(NULL, NULL);
154 171
155 if (!manifest.get() || !manifest->IsType(base::Value::TYPE_DICTIONARY)) { 172 if (!manifest.get() || !manifest->IsType(base::Value::TYPE_DICTIONARY)) {
156 LOG(ERROR) << "Failed to parse extension manifest."; 173 LOG(ERROR) << "Failed to parse extension manifest.";
157 return NULL; 174 return std::unique_ptr<base::DictionaryValue>();
158 } 175 }
159 // Transfer ownership to the caller. 176 return base::WrapUnique(
160 return static_cast<base::DictionaryValue*>(manifest.release()); 177 static_cast<base::DictionaryValue*>(manifest.release()));
Devlin 2016/11/17 16:02:54 static casting base::Values isn't really preferred
lazyboy 2016/11/17 22:50:38 Done.
161 } 178 }
162 179
163 void ComponentLoader::ClearAllRegistered() { 180 void ComponentLoader::ClearAllRegistered() {
Devlin 2016/11/17 16:02:54 This is only called from the dtor, and component_e
lazyboy 2016/11/17 22:50:37 Correct. Done.
164 for (RegisteredComponentExtensions::iterator it =
165 component_extensions_.begin();
166 it != component_extensions_.end(); ++it) {
167 delete it->manifest;
168 }
169
170 component_extensions_.clear(); 181 component_extensions_.clear();
171 } 182 }
172 183
173 std::string ComponentLoader::GetExtensionID(
174 int manifest_resource_id,
175 const base::FilePath& root_directory) {
176 base::DictionaryValue* manifest =
177 ParseManifest(ResourceBundle::GetSharedInstance().GetRawDataResource(
178 manifest_resource_id));
179 if (!manifest)
180 return std::string();
181
182 ComponentExtensionInfo info(manifest, root_directory);
183 return info.extension_id;
184 }
185
186 std::string ComponentLoader::Add(int manifest_resource_id, 184 std::string ComponentLoader::Add(int manifest_resource_id,
187 const base::FilePath& root_directory) { 185 const base::FilePath& root_directory) {
188 if (!ignore_whitelist_for_testing_ && 186 if (!ignore_whitelist_for_testing_ &&
189 !IsComponentExtensionWhitelisted(manifest_resource_id)) 187 !IsComponentExtensionWhitelisted(manifest_resource_id))
190 return std::string(); 188 return std::string();
191 189
192 base::StringPiece manifest_contents = 190 base::StringPiece manifest_contents =
193 ResourceBundle::GetSharedInstance().GetRawDataResource( 191 ResourceBundle::GetSharedInstance().GetRawDataResource(
194 manifest_resource_id); 192 manifest_resource_id);
195 return Add(manifest_contents, root_directory, true); 193 return Add(manifest_contents, root_directory, true);
196 } 194 }
197 195
198 std::string ComponentLoader::Add(const base::StringPiece& manifest_contents, 196 std::string ComponentLoader::Add(const base::StringPiece& manifest_contents,
199 const base::FilePath& root_directory) { 197 const base::FilePath& root_directory) {
200 return Add(manifest_contents, root_directory, false); 198 return Add(manifest_contents, root_directory, false);
201 } 199 }
202 200
203 std::string ComponentLoader::Add(const base::StringPiece& manifest_contents, 201 std::string ComponentLoader::Add(const base::StringPiece& manifest_contents,
204 const base::FilePath& root_directory, 202 const base::FilePath& root_directory,
205 bool skip_whitelist) { 203 bool skip_whitelist) {
206 // The Value is kept for the lifetime of the ComponentLoader. This is 204 // The Value is kept for the lifetime of the ComponentLoader. This is
207 // required in case LoadAll() is called again. 205 // required in case LoadAll() is called again.
208 base::DictionaryValue* manifest = ParseManifest(manifest_contents); 206 std::unique_ptr<base::DictionaryValue> manifest =
207 ParseManifest(manifest_contents);
209 if (manifest) 208 if (manifest)
210 return Add(manifest, root_directory, skip_whitelist); 209 return Add(std::move(manifest), root_directory, skip_whitelist);
211 return std::string(); 210 return std::string();
212 } 211 }
213 212
214 std::string ComponentLoader::Add(const base::DictionaryValue* parsed_manifest, 213 std::string ComponentLoader::Add(
215 const base::FilePath& root_directory, 214 std::unique_ptr<base::DictionaryValue> parsed_manifest,
216 bool skip_whitelist) { 215 const base::FilePath& root_directory,
217 ComponentExtensionInfo info(parsed_manifest, root_directory); 216 bool skip_whitelist) {
217 ComponentExtensionInfo info(std::move(parsed_manifest), root_directory);
218 if (!ignore_whitelist_for_testing_ && 218 if (!ignore_whitelist_for_testing_ &&
219 !skip_whitelist && 219 !skip_whitelist &&
220 !IsComponentExtensionWhitelisted(info.extension_id)) 220 !IsComponentExtensionWhitelisted(info.extension_id))
221 return std::string(); 221 return std::string();
222 222
223 component_extensions_.push_back(info); 223 component_extensions_.push_back(std::move(info));
224 ComponentExtensionInfo& added_info = component_extensions_.back();
224 if (extension_service_->is_ready()) 225 if (extension_service_->is_ready())
225 Load(info); 226 Load(added_info);
226 return info.extension_id; 227 return added_info.extension_id;
227 } 228 }
228 229
229 std::string ComponentLoader::AddOrReplace(const base::FilePath& path) { 230 std::string ComponentLoader::AddOrReplace(const base::FilePath& path) {
230 base::FilePath absolute_path = base::MakeAbsoluteFilePath(path); 231 base::FilePath absolute_path = base::MakeAbsoluteFilePath(path);
231 std::string error; 232 std::string error;
232 std::unique_ptr<base::DictionaryValue> manifest( 233 std::unique_ptr<base::DictionaryValue> manifest(
233 file_util::LoadManifest(absolute_path, &error)); 234 file_util::LoadManifest(absolute_path, &error));
234 if (!manifest) { 235 if (!manifest) {
235 LOG(ERROR) << "Could not load extension from '" << 236 LOG(ERROR) << "Could not load extension from '" <<
236 absolute_path.value() << "'. " << error; 237 absolute_path.value() << "'. " << error;
237 return std::string(); 238 return std::string();
238 } 239 }
239 Remove(GenerateId(manifest.get(), absolute_path)); 240 Remove(GenerateId(manifest.get(), absolute_path));
240 241
241 // We don't check component extensions loaded by path because this is only 242 // We don't check component extensions loaded by path because this is only
242 // used by developers for testing. 243 // used by developers for testing.
243 return Add(manifest.release(), absolute_path, true); 244 return Add(std::move(manifest), absolute_path, true);
244 } 245 }
245 246
246 void ComponentLoader::Reload(const std::string& extension_id) { 247 void ComponentLoader::Reload(const std::string& extension_id) {
247 for (RegisteredComponentExtensions::iterator it = 248 for (RegisteredComponentExtensions::iterator it =
248 component_extensions_.begin(); it != component_extensions_.end(); 249 component_extensions_.begin(); it != component_extensions_.end();
249 ++it) { 250 ++it) {
250 if (it->extension_id == extension_id) { 251 if (it->extension_id == extension_id) {
251 Load(*it); 252 Load(*it);
252 break; 253 break;
253 } 254 }
254 } 255 }
255 } 256 }
256 257
257 void ComponentLoader::Load(const ComponentExtensionInfo& info) { 258 void ComponentLoader::Load(const ComponentExtensionInfo& info) {
258 std::string error; 259 std::string error;
259 scoped_refptr<const Extension> extension(CreateExtension(info, &error)); 260 scoped_refptr<const Extension> extension(CreateExtension(info, &error));
260 if (!extension.get()) { 261 if (!extension.get()) {
261 LOG(ERROR) << error; 262 LOG(ERROR) << error;
262 return; 263 return;
263 } 264 }
264 265
265 CHECK_EQ(info.extension_id, extension->id()) << extension->name(); 266 CHECK_EQ(info.extension_id, extension->id()) << extension->name();
266 extension_service_->AddComponentExtension(extension.get()); 267 extension_service_->AddComponentExtension(extension.get());
267 } 268 }
268 269
269 void ComponentLoader::Remove(const base::FilePath& root_directory) { 270 void ComponentLoader::Remove(const base::FilePath& root_directory) {
270 // Find the ComponentExtensionInfo for the extension. 271 // Find the ComponentExtensionInfo for the extension.
271 RegisteredComponentExtensions::iterator it = component_extensions_.begin(); 272 RegisteredComponentExtensions::iterator it = component_extensions_.begin();
Devlin 2016/11/17 16:02:54 drive-by - inline this in the loop
lazyboy 2016/11/17 22:50:38 Done.
272 for (; it != component_extensions_.end(); ++it) { 273 for (; it != component_extensions_.end(); ++it) {
273 if (it->root_directory == root_directory) { 274 if (it->root_directory == root_directory) {
274 Remove(GenerateId(it->manifest, root_directory)); 275 Remove(GenerateId(it->manifest.get(), root_directory));
275 break; 276 break;
276 } 277 }
277 } 278 }
278 } 279 }
279 280
280 void ComponentLoader::Remove(const std::string& id) { 281 void ComponentLoader::Remove(const std::string& id) {
281 RegisteredComponentExtensions::iterator it = component_extensions_.begin(); 282 RegisteredComponentExtensions::iterator it = component_extensions_.begin();
Devlin 2016/11/17 16:02:54 ditto (and below)
lazyboy 2016/11/17 22:50:38 Done.
282 for (; it != component_extensions_.end(); ++it) { 283 for (; it != component_extensions_.end(); ++it) {
283 if (it->extension_id == id) { 284 if (it->extension_id == id) {
284 UnloadComponent(&(*it)); 285 UnloadComponent(&(*it));
285 it = component_extensions_.erase(it); 286 it = component_extensions_.erase(it);
Devlin 2016/11/17 16:02:54 Drive-by - No reason to assign |it| here
lazyboy 2016/11/17 22:50:38 Done.
286 break; 287 break;
287 } 288 }
288 } 289 }
289 } 290 }
290 291
291 bool ComponentLoader::Exists(const std::string& id) const { 292 bool ComponentLoader::Exists(const std::string& id) const {
292 RegisteredComponentExtensions::const_iterator it = 293 RegisteredComponentExtensions::const_iterator it =
293 component_extensions_.begin(); 294 component_extensions_.begin();
294 for (; it != component_extensions_.end(); ++it) 295 for (; it != component_extensions_.end(); ++it)
295 if (it->extension_id == id) 296 if (it->extension_id == id)
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 if (!ignore_whitelist_for_testing_ && 394 if (!ignore_whitelist_for_testing_ &&
394 !IsComponentExtensionWhitelisted(manifest_resource_id)) 395 !IsComponentExtensionWhitelisted(manifest_resource_id))
395 return; 396 return;
396 397
397 base::StringPiece manifest_contents = 398 base::StringPiece manifest_contents =
398 ResourceBundle::GetSharedInstance().GetRawDataResource( 399 ResourceBundle::GetSharedInstance().GetRawDataResource(
399 manifest_resource_id); 400 manifest_resource_id);
400 401
401 // The Value is kept for the lifetime of the ComponentLoader. This is 402 // The Value is kept for the lifetime of the ComponentLoader. This is
402 // required in case LoadAll() is called again. 403 // required in case LoadAll() is called again.
403 base::DictionaryValue* manifest = ParseManifest(manifest_contents); 404 std::unique_ptr<base::DictionaryValue> manifest =
405 ParseManifest(manifest_contents);
404 406
405 if (manifest) { 407 if (manifest) {
406 manifest->SetString(manifest_keys::kName, name_string); 408 manifest->SetString(manifest_keys::kName, name_string);
407 manifest->SetString(manifest_keys::kDescription, description_string); 409 manifest->SetString(manifest_keys::kDescription, description_string);
408 Add(manifest, root_directory, true); 410 Add(std::move(manifest), root_directory, true);
409 } 411 }
410 } 412 }
411 413
412 void ComponentLoader::AddChromeApp() { 414 void ComponentLoader::AddChromeApp() {
413 #if BUILDFLAG(ENABLE_APP_LIST) 415 #if BUILDFLAG(ENABLE_APP_LIST)
414 AddWithNameAndDescription( 416 AddWithNameAndDescription(
415 IDR_CHROME_APP_MANIFEST, base::FilePath(FILE_PATH_LITERAL("chrome_app")), 417 IDR_CHROME_APP_MANIFEST, base::FilePath(FILE_PATH_LITERAL("chrome_app")),
416 l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME), 418 l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME),
417 l10n_util::GetStringUTF8(IDS_CHROME_SHORTCUT_DESCRIPTION)); 419 l10n_util::GetStringUTF8(IDS_CHROME_SHORTCUT_DESCRIPTION));
418 #endif 420 #endif
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 (command_line->HasSwitch(switches::kTestType) || 633 (command_line->HasSwitch(switches::kTestType) ||
632 command_line->HasSwitch( 634 command_line->HasSwitch(
633 switches::kDisableComponentExtensionsWithBackgroundPages))) { 635 switches::kDisableComponentExtensionsWithBackgroundPages))) {
634 return; 636 return;
635 } 637 }
636 638
637 AddHangoutServicesExtension(); 639 AddHangoutServicesExtension();
638 } 640 }
639 641
640 void ComponentLoader::UnloadComponent(ComponentExtensionInfo* component) { 642 void ComponentLoader::UnloadComponent(ComponentExtensionInfo* component) {
641 delete component->manifest;
642 if (extension_service_->is_ready()) { 643 if (extension_service_->is_ready()) {
643 extension_service_-> 644 extension_service_->
644 RemoveComponentExtension(component->extension_id); 645 RemoveComponentExtension(component->extension_id);
645 } 646 }
646 } 647 }
647 648
648 void ComponentLoader::EnableFileSystemInGuestMode(const std::string& id) { 649 void ComponentLoader::EnableFileSystemInGuestMode(const std::string& id) {
649 #if defined(OS_CHROMEOS) 650 #if defined(OS_CHROMEOS)
650 if (!IsNormalSession()) { 651 if (!IsNormalSession()) {
651 // TODO(dpolukhin): Hack to enable HTML5 temporary file system for 652 // TODO(dpolukhin): Hack to enable HTML5 temporary file system for
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 } 686 }
686 687
687 void ComponentLoader::FinishAddComponentFromDir( 688 void ComponentLoader::FinishAddComponentFromDir(
688 const base::FilePath& root_directory, 689 const base::FilePath& root_directory,
689 const char* extension_id, 690 const char* extension_id,
690 const base::Closure& done_cb, 691 const base::Closure& done_cb,
691 std::unique_ptr<base::DictionaryValue> manifest) { 692 std::unique_ptr<base::DictionaryValue> manifest) {
692 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 693 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
693 if (!manifest) 694 if (!manifest)
694 return; // Error already logged. 695 return; // Error already logged.
695 std::string actual_extension_id = Add( 696 std::string actual_extension_id =
696 manifest.release(), 697 Add(std::move(manifest), root_directory, false);
697 root_directory,
698 false);
699 CHECK_EQ(extension_id, actual_extension_id); 698 CHECK_EQ(extension_id, actual_extension_id);
700 if (!done_cb.is_null()) 699 if (!done_cb.is_null())
701 done_cb.Run(); 700 done_cb.Run();
702 } 701 }
703 #endif 702 #endif
704 703
705 } // namespace extensions 704 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/component_loader.h ('k') | chrome/browser/extensions/component_loader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698