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

Side by Side Diff: webkit/plugins/ppapi/resource_tracker.cc

Issue 6261017: Dynamically check types of PPAPI IDs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 11 months 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "webkit/plugins/ppapi/resource_tracker.h" 5 #include "webkit/plugins/ppapi/resource_tracker.h"
6 6
7 #include <limits> 7 #include <limits>
8 #include <set> 8 #include <set>
9 9
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/rand_util.h" 12 #include "base/rand_util.h"
13 #include "ppapi/c/pp_resource.h" 13 #include "ppapi/c/pp_resource.h"
14 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" 14 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
15 #include "webkit/plugins/ppapi/resource.h" 15 #include "webkit/plugins/ppapi/resource.h"
16 #include "webkit/plugins/ppapi/var.h" 16 #include "webkit/plugins/ppapi/var.h"
17 17
18 enum PPIdType {
19 PP_ID_TYPE_MODULE,
20 PP_ID_TYPE_INSTANCE,
21 PP_ID_TYPE_RESOURCE,
22 PP_ID_TYPE_VAR,
23 PP_ID_TYPE_COUNT
24 };
25
26 static const unsigned int kPPIdTypeBits = 2;
27 COMPILE_ASSERT(PP_ID_TYPE_COUNT <= (1<<kPPIdTypeBits),
28 kPPIdTypeBits_is_too_small_for_all_id_types);
29
30 template <typename T> static inline T MakeTypedId(T value, PPIdType type) {
31 return (value << kPPIdTypeBits) | static_cast<T>(type);
32 }
33
34 template <typename T> static inline bool CheckIdType(T id, PPIdType type) {
35 // 0 is a valid resource.
36 if (!id)
37 return true;
38 const T mask = (static_cast<T>(1) << kPPIdTypeBits) - 1;
39 return (id & mask) == type;
40 }
41
18 namespace webkit { 42 namespace webkit {
19 namespace ppapi { 43 namespace ppapi {
20 44
21 static base::LazyInstance<ResourceTracker> g_resource_tracker( 45 static base::LazyInstance<ResourceTracker> g_resource_tracker(
22 base::LINKER_INITIALIZED); 46 base::LINKER_INITIALIZED);
23 47
24 scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const { 48 scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const {
49 DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
50 << res << " is not a PP_Resource.";
25 ResourceMap::const_iterator result = live_resources_.find(res); 51 ResourceMap::const_iterator result = live_resources_.find(res);
26 if (result == live_resources_.end()) { 52 if (result == live_resources_.end()) {
27 return scoped_refptr<Resource>(); 53 return scoped_refptr<Resource>();
28 } 54 }
29 return result->second.first; 55 return result->second.first;
30 } 56 }
31 57
32 // static 58 // static
33 ResourceTracker* ResourceTracker::singleton_override_ = NULL; 59 ResourceTracker* ResourceTracker::singleton_override_ = NULL;
34 60
35 ResourceTracker::ResourceTracker() 61 ResourceTracker::ResourceTracker()
36 : last_resource_id_(0), 62 : last_resource_id_(0),
37 last_var_id_(0) { 63 last_var_id_(0) {
38 } 64 }
39 65
40 ResourceTracker::~ResourceTracker() { 66 ResourceTracker::~ResourceTracker() {
41 } 67 }
42 68
43 // static 69 // static
44 ResourceTracker* ResourceTracker::Get() { 70 ResourceTracker* ResourceTracker::Get() {
45 if (singleton_override_) 71 if (singleton_override_)
46 return singleton_override_; 72 return singleton_override_;
47 return g_resource_tracker.Pointer(); 73 return g_resource_tracker.Pointer();
48 } 74 }
49 75
50 PP_Resource ResourceTracker::AddResource(Resource* resource) { 76 PP_Resource ResourceTracker::AddResource(Resource* resource) {
51 // If the plugin manages to create 4 billion resources, don't do crazy stuff. 77 // If the plugin manages to create 1 billion resources, don't do crazy stuff.
52 if (last_resource_id_ == std::numeric_limits<PP_Resource>::max()) 78 if (last_resource_id_ ==
79 std::numeric_limits<PP_Resource>::max() >> kPPIdTypeBits)
brettw 2011/01/20 05:45:09 Can you add parens here to clarify the order of op
53 return 0; 80 return 0;
54 81
55 // Add the resource with plugin use-count 1. 82 // Add the resource with plugin use-count 1.
56 PP_Resource new_id = ++last_resource_id_; 83 PP_Resource new_id = MakeTypedId(++last_resource_id_, PP_ID_TYPE_RESOURCE);
57 live_resources_.insert(std::make_pair(new_id, std::make_pair(resource, 1))); 84 live_resources_.insert(std::make_pair(new_id, std::make_pair(resource, 1)));
58 instance_to_resources_[resource->instance()->pp_instance()].insert(new_id); 85 instance_to_resources_[resource->instance()->pp_instance()].insert(new_id);
59 return new_id; 86 return new_id;
60 } 87 }
61 88
62 int32 ResourceTracker::AddVar(Var* var) { 89 int32 ResourceTracker::AddVar(Var* var) {
63 // If the plugin manages to create 4B strings... 90 // If the plugin manages to create 1B strings...
64 if (last_var_id_ == std::numeric_limits<int32>::max()) { 91 if (last_var_id_ == std::numeric_limits<int32>::max() >> kPPIdTypeBits) {
65 return 0; 92 return 0;
66 } 93 }
67 // Add the resource with plugin use-count 1. 94 // Add the resource with plugin use-count 1.
68 ++last_var_id_; 95 int32 new_id = MakeTypedId(++last_var_id_, PP_ID_TYPE_VAR);
69 live_vars_.insert(std::make_pair(last_var_id_, 96 live_vars_.insert(std::make_pair(new_id, std::make_pair(var, 1)));
70 std::make_pair(var, 1))); 97 return new_id;
71 return last_var_id_;
72 } 98 }
73 99
74 bool ResourceTracker::AddRefResource(PP_Resource res) { 100 bool ResourceTracker::AddRefResource(PP_Resource res) {
101 DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
102 << res << " is not a PP_Resource.";
75 ResourceMap::iterator i = live_resources_.find(res); 103 ResourceMap::iterator i = live_resources_.find(res);
76 if (i != live_resources_.end()) { 104 if (i != live_resources_.end()) {
77 // We don't protect against overflow, since a plugin as malicious as to ref 105 // We don't protect against overflow, since a plugin as malicious as to ref
78 // once per every byte in the address space could have just as well unrefed 106 // once per every byte in the address space could have just as well unrefed
79 // one time too many. 107 // one time too many.
80 ++i->second.second; 108 ++i->second.second;
81 return true; 109 return true;
82 } else { 110 } else {
83 return false; 111 return false;
84 } 112 }
85 } 113 }
86 114
87 bool ResourceTracker::UnrefResource(PP_Resource res) { 115 bool ResourceTracker::UnrefResource(PP_Resource res) {
116 DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
117 << res << " is not a PP_Resource.";
88 ResourceMap::iterator i = live_resources_.find(res); 118 ResourceMap::iterator i = live_resources_.find(res);
89 if (i != live_resources_.end()) { 119 if (i != live_resources_.end()) {
90 if (!--i->second.second) { 120 if (!--i->second.second) {
91 Resource* to_release = i->second.first; 121 Resource* to_release = i->second.first;
92 to_release->LastPluginRefWasDeleted(false); 122 to_release->LastPluginRefWasDeleted(false);
93 123
94 ResourceSet& instance_resource_set = 124 ResourceSet& instance_resource_set =
95 instance_to_resources_[to_release->instance()->pp_instance()]; 125 instance_to_resources_[to_release->instance()->pp_instance()];
96 DCHECK(instance_resource_set.find(res) != instance_resource_set.end()); 126 DCHECK(instance_resource_set.find(res) != instance_resource_set.end());
97 instance_resource_set.erase(res); 127 instance_resource_set.erase(res);
98 128
99 live_resources_.erase(i); 129 live_resources_.erase(i);
100 } 130 }
101 return true; 131 return true;
102 } else { 132 } else {
103 return false; 133 return false;
104 } 134 }
105 } 135 }
106 136
107 void ResourceTracker::ForceDeletePluginResourceRefs(PP_Resource res) { 137 void ResourceTracker::ForceDeletePluginResourceRefs(PP_Resource res) {
138 DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
139 << res << " is not a PP_Resource.";
108 ResourceMap::iterator i = live_resources_.find(res); 140 ResourceMap::iterator i = live_resources_.find(res);
109 if (i == live_resources_.end()) 141 if (i == live_resources_.end())
110 return; // Nothing to do. 142 return; // Nothing to do.
111 143
112 i->second.second = 0; 144 i->second.second = 0;
113 Resource* resource = i->second.first; 145 Resource* resource = i->second.first;
114 146
115 // Must delete from the resource set first since the resource's instance 147 // Must delete from the resource set first since the resource's instance
116 // pointer will get zeroed out in LastPluginRefWasDeleted. 148 // pointer will get zeroed out in LastPluginRefWasDeleted.
117 ResourceSet& resource_set = instance_to_resources_[ 149 ResourceSet& resource_set = instance_to_resources_[
(...skipping 13 matching lines...) Expand all
131 // module->resource lookup to free resources when a module is unloaded. In 163 // module->resource lookup to free resources when a module is unloaded. In
132 // this case, this function can be implemented using that system. 164 // this case, this function can be implemented using that system.
133 uint32 count = 0; 165 uint32 count = 0;
134 for (ResourceMap::const_iterator i = live_resources_.begin(); 166 for (ResourceMap::const_iterator i = live_resources_.begin();
135 i != live_resources_.end(); ++i) 167 i != live_resources_.end(); ++i)
136 count++; 168 count++;
137 return count; 169 return count;
138 } 170 }
139 171
140 scoped_refptr<Var> ResourceTracker::GetVar(int32 var_id) const { 172 scoped_refptr<Var> ResourceTracker::GetVar(int32 var_id) const {
173 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
174 << var_id << " is not a PP_Var ID.";
141 VarMap::const_iterator result = live_vars_.find(var_id); 175 VarMap::const_iterator result = live_vars_.find(var_id);
142 if (result == live_vars_.end()) { 176 if (result == live_vars_.end()) {
143 return scoped_refptr<Var>(); 177 return scoped_refptr<Var>();
144 } 178 }
145 return result->second.first; 179 return result->second.first;
146 } 180 }
147 181
148 bool ResourceTracker::AddRefVar(int32 var_id) { 182 bool ResourceTracker::AddRefVar(int32 var_id) {
183 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
184 << var_id << " is not a PP_Var ID.";
149 VarMap::iterator i = live_vars_.find(var_id); 185 VarMap::iterator i = live_vars_.find(var_id);
150 if (i != live_vars_.end()) { 186 if (i != live_vars_.end()) {
151 // We don't protect against overflow, since a plugin as malicious as to ref 187 // We don't protect against overflow, since a plugin as malicious as to ref
152 // once per every byte in the address space could have just as well unrefed 188 // once per every byte in the address space could have just as well unrefed
153 // one time too many. 189 // one time too many.
154 ++i->second.second; 190 ++i->second.second;
155 return true; 191 return true;
156 } 192 }
157 return false; 193 return false;
158 } 194 }
159 195
160 bool ResourceTracker::UnrefVar(int32 var_id) { 196 bool ResourceTracker::UnrefVar(int32 var_id) {
197 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
198 << var_id << " is not a PP_Var ID.";
161 VarMap::iterator i = live_vars_.find(var_id); 199 VarMap::iterator i = live_vars_.find(var_id);
162 if (i != live_vars_.end()) { 200 if (i != live_vars_.end()) {
163 if (!--i->second.second) 201 if (!--i->second.second)
164 live_vars_.erase(i); 202 live_vars_.erase(i);
165 return true; 203 return true;
166 } 204 }
167 return false; 205 return false;
168 } 206 }
169 207
170 PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) { 208 PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) {
171 #ifndef NDEBUG 209 #ifndef NDEBUG
172 // Make sure we're not adding one more than once. 210 // Make sure we're not adding one more than once.
173 for (InstanceMap::const_iterator i = instance_map_.begin(); 211 for (InstanceMap::const_iterator i = instance_map_.begin();
174 i != instance_map_.end(); ++i) 212 i != instance_map_.end(); ++i)
175 DCHECK(i->second != instance); 213 DCHECK(i->second != instance);
176 #endif 214 #endif
177 215
178 // Use a random 64-bit number for the instance ID. This helps prevent some 216 // Use a random 64-bit number for the instance ID. This helps prevent some
179 // mischeif where you could misallocate resources if you gave a different 217 // mischeif where you could misallocate resources if you gave a different
180 // instance ID. 218 // instance ID.
181 // 219 //
182 // See also AddModule below. 220 // See also AddModule below.
183 // 221 //
184 // Need to make sure the random number isn't a duplicate or 0. 222 // Need to make sure the random number isn't a duplicate or 0.
185 PP_Instance new_instance; 223 PP_Instance new_instance;
186 do { 224 do {
187 new_instance = static_cast<PP_Instance>(base::RandUint64()); 225 new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()),
226 PP_ID_TYPE_INSTANCE);
188 } while (!new_instance || 227 } while (!new_instance ||
189 instance_map_.find(new_instance) != instance_map_.end()); 228 instance_map_.find(new_instance) != instance_map_.end());
190 instance_map_[new_instance] = instance; 229 instance_map_[new_instance] = instance;
191 return new_instance; 230 return new_instance;
192 } 231 }
193 232
194 void ResourceTracker::InstanceDeleted(PP_Instance instance) { 233 void ResourceTracker::InstanceDeleted(PP_Instance instance) {
234 DLOG_IF(ERROR, !CheckIdType(instance, PP_ID_TYPE_INSTANCE))
235 << instance << " is not a PP_Instance.";
195 // Force release all plugin references to resources associated with the 236 // Force release all plugin references to resources associated with the
196 // deleted instance. 237 // deleted instance.
197 ResourceSet& resource_set = instance_to_resources_[instance]; 238 ResourceSet& resource_set = instance_to_resources_[instance];
198 ResourceSet::iterator i = resource_set.begin(); 239 ResourceSet::iterator i = resource_set.begin();
199 while (i != resource_set.end()) { 240 while (i != resource_set.end()) {
200 // Iterators to a set are stable so we can iterate the set while the items 241 // Iterators to a set are stable so we can iterate the set while the items
201 // are being deleted as long as we're careful not to delete the item we're 242 // are being deleted as long as we're careful not to delete the item we're
202 // holding an iterator to. 243 // holding an iterator to.
203 ResourceSet::iterator current = i++; 244 ResourceSet::iterator current = i++;
204 ForceDeletePluginResourceRefs(*current); 245 ForceDeletePluginResourceRefs(*current);
205 } 246 }
206 DCHECK(resource_set.empty()); 247 DCHECK(resource_set.empty());
207 instance_to_resources_.erase(instance); 248 instance_to_resources_.erase(instance);
208 249
209 InstanceMap::iterator found = instance_map_.find(instance); 250 InstanceMap::iterator found = instance_map_.find(instance);
210 if (found == instance_map_.end()) { 251 if (found == instance_map_.end()) {
211 NOTREACHED(); 252 NOTREACHED();
212 return; 253 return;
213 } 254 }
214 instance_map_.erase(found); 255 instance_map_.erase(found);
215 } 256 }
216 257
217 PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) { 258 PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) {
259 DLOG_IF(ERROR, !CheckIdType(instance, PP_ID_TYPE_INSTANCE))
260 << instance << " is not a PP_Instance.";
218 InstanceMap::iterator found = instance_map_.find(instance); 261 InstanceMap::iterator found = instance_map_.find(instance);
219 if (found == instance_map_.end()) 262 if (found == instance_map_.end())
220 return NULL; 263 return NULL;
221 return found->second; 264 return found->second;
222 } 265 }
223 266
224 PP_Module ResourceTracker::AddModule(PluginModule* module) { 267 PP_Module ResourceTracker::AddModule(PluginModule* module) {
225 #ifndef NDEBUG 268 #ifndef NDEBUG
226 // Make sure we're not adding one more than once. 269 // Make sure we're not adding one more than once.
227 for (ModuleMap::const_iterator i = module_map_.begin(); 270 for (ModuleMap::const_iterator i = module_map_.begin();
228 i != module_map_.end(); ++i) 271 i != module_map_.end(); ++i)
229 DCHECK(i->second != module); 272 DCHECK(i->second != module);
230 #endif 273 #endif
231 274
232 // See AddInstance above. 275 // See AddInstance above.
233 PP_Module new_module; 276 PP_Module new_module;
234 do { 277 do {
235 new_module = static_cast<PP_Module>(base::RandUint64()); 278 new_module = MakeTypedId(static_cast<PP_Module>(base::RandUint64()),
279 PP_ID_TYPE_MODULE);
236 } while (!new_module || 280 } while (!new_module ||
237 module_map_.find(new_module) != module_map_.end()); 281 module_map_.find(new_module) != module_map_.end());
238 module_map_[new_module] = module; 282 module_map_[new_module] = module;
239 return new_module; 283 return new_module;
240 } 284 }
241 285
242 void ResourceTracker::ModuleDeleted(PP_Module module) { 286 void ResourceTracker::ModuleDeleted(PP_Module module) {
287 DLOG_IF(ERROR, !CheckIdType(module, PP_ID_TYPE_MODULE))
288 << module << " is not a PP_Module.";
243 ModuleMap::iterator found = module_map_.find(module); 289 ModuleMap::iterator found = module_map_.find(module);
244 if (found == module_map_.end()) { 290 if (found == module_map_.end()) {
245 NOTREACHED(); 291 NOTREACHED();
246 return; 292 return;
247 } 293 }
248 module_map_.erase(found); 294 module_map_.erase(found);
249 } 295 }
250 296
251 PluginModule* ResourceTracker::GetModule(PP_Module module) { 297 PluginModule* ResourceTracker::GetModule(PP_Module module) {
298 DLOG_IF(ERROR, !CheckIdType(module, PP_ID_TYPE_MODULE))
299 << module << " is not a PP_Module.";
252 ModuleMap::iterator found = module_map_.find(module); 300 ModuleMap::iterator found = module_map_.find(module);
253 if (found == module_map_.end()) 301 if (found == module_map_.end())
254 return NULL; 302 return NULL;
255 return found->second; 303 return found->second;
256 } 304 }
257 305
258 // static 306 // static
259 void ResourceTracker::SetSingletonOverride(ResourceTracker* tracker) { 307 void ResourceTracker::SetSingletonOverride(ResourceTracker* tracker) {
260 DCHECK(!singleton_override_); 308 DCHECK(!singleton_override_);
261 singleton_override_ = tracker; 309 singleton_override_ = tracker;
262 } 310 }
263 311
264 // static 312 // static
265 void ResourceTracker::ClearSingletonOverride() { 313 void ResourceTracker::ClearSingletonOverride() {
266 DCHECK(singleton_override_); 314 DCHECK(singleton_override_);
267 singleton_override_ = NULL; 315 singleton_override_ = NULL;
268 } 316 }
269 317
270 } // namespace ppapi 318 } // namespace ppapi
271 } // namespace webkit 319 } // namespace webkit
272 320
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698