diff options
-rw-r--r-- | ppapi/c/dev/ppb_var_deprecated.h | 3 | ||||
-rw-r--r-- | ppapi/proxy/plugin_var_tracker.cc | 90 | ||||
-rw-r--r-- | ppapi/proxy/plugin_var_tracker.h | 77 | ||||
-rw-r--r-- | ppapi/proxy/plugin_var_tracker_unittest.cc | 81 | ||||
-rw-r--r-- | ppapi/proxy/ppb_var_deprecated_proxy.cc | 12 | ||||
-rw-r--r-- | ppapi/proxy/ppp_class_proxy.cc | 38 | ||||
-rw-r--r-- | ppapi/proxy/ppp_class_proxy.h | 5 | ||||
-rw-r--r-- | ppapi/proxy/ppp_instance_proxy.cc | 6 | ||||
-rw-r--r-- | ppapi/proxy/proxy_object_var.cc | 4 | ||||
-rw-r--r-- | ppapi/proxy/proxy_object_var.h | 11 | ||||
-rw-r--r-- | ppapi/shared_impl/test_globals.h | 2 | ||||
-rw-r--r-- | ppapi/shared_impl/var_tracker.h | 4 | ||||
-rw-r--r-- | webkit/plugins/ppapi/host_globals.cc | 4 | ||||
-rw-r--r-- | webkit/plugins/ppapi/host_var_tracker.cc | 6 | ||||
-rw-r--r-- | webkit/plugins/ppapi/host_var_tracker.h | 7 |
15 files changed, 334 insertions, 16 deletions
diff --git a/ppapi/c/dev/ppb_var_deprecated.h b/ppapi/c/dev/ppb_var_deprecated.h index 70ea229..3970f47 100644 --- a/ppapi/c/dev/ppb_var_deprecated.h +++ b/ppapi/c/dev/ppb_var_deprecated.h @@ -206,7 +206,8 @@ struct PPB_Var_Deprecated { /** * Creates an object that the plugin implements. The plugin supplies a * pointer to the class interface it implements for that object, and its - * associated internal data that represents that object. + * associated internal data that represents that object. This object data + * must be unique among all "live" objects. * * The returned object will have a reference count of 1. When the reference * count reached 0, the class' Destruct function wlil be called. diff --git a/ppapi/proxy/plugin_var_tracker.cc b/ppapi/proxy/plugin_var_tracker.cc index 74cd557..52ecad8 100644 --- a/ppapi/proxy/plugin_var_tracker.cc +++ b/ppapi/proxy/plugin_var_tracker.cc @@ -6,6 +6,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/singleton.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" #include "ppapi/c/ppb_var.h" #include "ppapi/proxy/plugin_array_buffer_var.h" #include "ppapi/proxy/plugin_dispatcher.h" @@ -151,10 +152,79 @@ void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher, ReleaseVar(found->second); } +void PluginVarTracker::DidDeleteInstance(PP_Instance instance) { + // See the comment above user_data_to_plugin_ in the header file. We assume + // there aren't that many objects so a brute-force search is reasonable. + UserDataToPluginImplementedVarMap::iterator i = + user_data_to_plugin_.begin(); + while (i != user_data_to_plugin_.end()) { + if (i->second.instance == instance) { + if (!i->second.plugin_object_id) { + // This object is for the freed instance and the plugin is not holding + // any references to it. Deallocate immediately. + UserDataToPluginImplementedVarMap::iterator to_remove = i; + ++i; + to_remove->second.ppp_class->Deallocate(to_remove->first); + user_data_to_plugin_.erase(to_remove); + } else { + // The plugin is holding refs to this object. We don't want to call + // Deallocate since the plugin may be depending on those refs to keep + // its data alive. To avoid crashes in this case, just clear out the + // instance to mark it and continue. When the plugin refs go to 0, + // we'll notice there is no instance and call Deallocate. + i->second.instance = 0; + ++i; + } + } else { + ++i; + } + } +} + ArrayBufferVar* PluginVarTracker::CreateArrayBuffer(uint32 size_in_bytes) { return new PluginArrayBufferVar(size_in_bytes); } +void PluginVarTracker::PluginImplementedObjectCreated( + PP_Instance instance, + const PP_Var& created_var, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + PluginImplementedVar p; + p.ppp_class = ppp_class; + p.instance = instance; + p.plugin_object_id = created_var.value.as_id; + user_data_to_plugin_[ppp_class_data] = p; + + // Link the user data to the object. + ProxyObjectVar* object = GetVar(created_var)->AsProxyObjectVar(); + object->set_user_data(ppp_class_data); +} + +void PluginVarTracker::PluginImplementedObjectDestroyed(void* user_data) { + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(user_data); + if (found == user_data_to_plugin_.end()) { + NOTREACHED(); + return; + } + user_data_to_plugin_.erase(found); +} + +bool PluginVarTracker::IsPluginImplementedObjectAlive(void* user_data) { + return user_data_to_plugin_.find(user_data) != user_data_to_plugin_.end(); +} + +bool PluginVarTracker::ValidatePluginObjectCall( + const PPP_Class_Deprecated* ppp_class, + void* user_data) { + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(user_data); + if (found == user_data_to_plugin_.end()) + return false; + return found->second.ppp_class == ppp_class; +} + int32 PluginVarTracker::AddVarInternal(Var* var, AddVarRefMode mode) { // Normal adding. int32 new_id = VarTracker::AddVarInternal(var, mode); @@ -200,6 +270,26 @@ void PluginVarTracker::ObjectGettingZeroRef(VarMap::iterator iter) { DCHECK(iter->second.ref_count == 0); SendReleaseObjectMsg(*object); + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(object->user_data()); + if (found != user_data_to_plugin_.end()) { + // This object is implemented in the plugin. + if (found->second.instance == 0) { + // Instance is destroyed. This means that we'll never get a Deallocate + // call from the renderer and we should do so now. + found->second.ppp_class->Deallocate(found->first); + user_data_to_plugin_.erase(found); + } else { + // The plugin is releasing its last reference to an object it implements. + // Clear the tracking data that links our "plugin implemented object" to + // the var. If the instance is destroyed and there is no ID, we know that + // we should just call Deallocate on the object data. + // + // See the plugin_object_id declaration for more info. + found->second.plugin_object_id = 0; + } + } + // This will optionally delete the info from live_vars_. VarTracker::ObjectGettingZeroRef(iter); } diff --git a/ppapi/proxy/plugin_var_tracker.h b/ppapi/proxy/plugin_var_tracker.h index cafb3ab..3e287be 100644 --- a/ppapi/proxy/plugin_var_tracker.h +++ b/ppapi/proxy/plugin_var_tracker.h @@ -17,6 +17,7 @@ #include "ppapi/shared_impl/var_tracker.h" template<typename T> struct DefaultSingletonTraits; +struct PPP_Class_Deprecated; namespace ppapi { @@ -56,6 +57,28 @@ class PPAPI_PROXY_EXPORT PluginVarTracker : public VarTracker { void ReleaseHostObject(PluginDispatcher* dispatcher, const PP_Var& host_object); + // VarTracker public overrides. + void DidDeleteInstance(PP_Instance instance) OVERRIDE; + + // Notification that a plugin-implemented object (PPP_Class) was created by + // the plugin or deallocated by WebKit over IPC. + void PluginImplementedObjectCreated(PP_Instance instance, + const PP_Var& created_var, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data); + void PluginImplementedObjectDestroyed(void* ppp_class_data); + + // Returns true if there is an object implemented by the plugin with the + // given user_data that has not been deallocated yet. Call this when + // receiving a scripting call to the plugin to validate that the object + // receiving the call is still alive (see user_data_to_plugin_ below). + bool IsPluginImplementedObjectAlive(void* user_data); + + // Validates that the given class/user_data pair corresponds to a currently + // living plugin object. + bool ValidatePluginObjectCall(const PPP_Class_Deprecated* ppp_class, + void* user_data); + private: // VarTracker protected overrides. virtual int32 AddVarInternal(Var* var, AddVarRefMode mode) OVERRIDE; @@ -84,6 +107,32 @@ class PPAPI_PROXY_EXPORT PluginVarTracker : public VarTracker { int32 host_object_id; }; + struct PluginImplementedVar { + const PPP_Class_Deprecated* ppp_class; + + // The instance that created this Var. This will be 0 if the instance has + // been destroyed but the object is still alive. + PP_Instance instance; + + // Represents the plugin var ID for the var corresponding to this object. + // If the plugin does not have a ref to the object but it's still alive + // (the DOM could be holding a ref keeping it alive) this will be 0. + // + // There is an obscure corner case. If the plugin returns an object to the + // renderer and releases all of its refs, the object will still be alive + // but there will be no plugin refs. It's possible for the plugin to get + // this same object again through the DOM, and we'll lose the correlation + // between plugin implemented object and car. This means we won't know when + // the plugin releases its last refs and may call Deallocate when the + // plugin is still holding a ref. + // + // However, for the plugin to be depending on holding a ref to an object + // that it implements that it previously released but got again through + // indirect means would be extremely rare, and we only allow var scripting + // in limited cases anyway. + int32 plugin_object_id; + }; + // Returns the existing var ID for the given object var, creating and // assigning an ID to it if necessary. This does not affect the reference // count, so in the creation case the refcount will be 0. It's assumed in @@ -106,6 +155,34 @@ class PPAPI_PROXY_EXPORT PluginVarTracker : public VarTracker { typedef std::map<HostVar, int32> HostVarToPluginVarMap; HostVarToPluginVarMap host_var_to_plugin_var_; + // Maps "user data" for plugin implemented objects (PPP_Class) that are + // alive to various tracking info. + // + // This is tricky because there may not actually be any vars in the plugin + // associated with a plugin-implemented object, so they won't all have + // entries in our HostVarToPluginVarMap or the base class VarTracker's map. + // + // All objects that the plugin has created using CreateObject that have not + // yet been Deallocate()-ed by WebKit will be in this map. When the instance + // that created the object goes away, we know to call Deallocate on all + // remaining objects for that instance so that the data backing the object + // that the plugin owns is not leaked. We may not receive normal Deallocate + // calls from WebKit because the object could be leaked (attached to the DOM + // and outliving the plugin instance) or WebKit could send the deallocate + // after the out-of-process routing for that instance was torn down. + // + // There is an additional complexity. In WebKit, objects created by the + // plugin aren't actually bound to the plugin instance (for example, you + // could attach it to the DOM or send it to another plugin instance). It's + // possible that we could force deallocate an object when an instance id + // destroyed, but then another instance could get to that object somehow + // (like by reading it out of the DOM). We will then have deallocated the + // object and can't complete the call. We do not care about this case, and + // the calls will just fail. + typedef std::map<void*, PluginImplementedVar> + UserDataToPluginImplementedVarMap; + UserDataToPluginImplementedVarMap user_data_to_plugin_; + DISALLOW_COPY_AND_ASSIGN(PluginVarTracker); }; diff --git a/ppapi/proxy/plugin_var_tracker_unittest.cc b/ppapi/proxy/plugin_var_tracker_unittest.cc index ce2014f..089888c 100644 --- a/ppapi/proxy/plugin_var_tracker_unittest.cc +++ b/ppapi/proxy/plugin_var_tracker_unittest.cc @@ -3,9 +3,11 @@ // found in the LICENSE file. #include "ipc/ipc_test_sink.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" #include "ppapi/proxy/plugin_var_tracker.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/proxy/proxy_object_var.h" namespace ppapi { namespace proxy { @@ -19,6 +21,25 @@ PP_Var MakeObject(int32 object_id) { return ret; } +// A Deallocate() function for PPP_Class that just writes 1 to the given +// pointer so we know when Deallocate was called. +void MarkOnDeallocate(void* object) { + *static_cast<int*>(object) = 1; +} + +// A class that just implements MarkOnDeallocate on destruction. +PPP_Class_Deprecated mark_on_deallocate_class = { + NULL, // HasProperty, + NULL, // HasMethod, + NULL, // GetProperty, + NULL, // GetAllPropertyNames, + NULL, // SetProperty, + NULL, // RemoveProperty, + NULL, // Call, + NULL, // Construct, + &MarkOnDeallocate +}; + } // namespace class PluginVarTrackerTest : public PluginProxyTest { @@ -160,5 +181,65 @@ TEST_F(PluginVarTrackerTest, RecursiveTrackWithNoRef) { var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); } +// Tests that objects implemented by the plugin that have no references by +// the plugin get their Deallocate function called on destruction. +TEST_F(PluginVarTrackerTest, PluginObjectInstanceDeleted) { + PP_Var host_object = MakeObject(12345); + PP_Instance pp_instance = 0x12345; + + int deallocate_called = 0; + void* user_data = &deallocate_called; + + // Make a var with one reference. + scoped_refptr<ProxyObjectVar> object( + new ProxyObjectVar(plugin_dispatcher(), host_object.value.as_id)); + PP_Var plugin_var = MakeObject(var_tracker().AddVar(object)); + var_tracker().PluginImplementedObjectCreated(pp_instance, + plugin_var, + &mark_on_deallocate_class, + user_data); + + // Release the plugin ref to the var. WebKit hasn't called destroy so + // we won't get a destroy call. + object = NULL; + var_tracker().ReleaseVar(plugin_var); + EXPECT_FALSE(deallocate_called); + + // Synthesize an instance destuction, this should call Deallocate. + var_tracker().DidDeleteInstance(pp_instance); + EXPECT_TRUE(deallocate_called); +} + +// Tests what happens when a plugin keeps a ref to a plugin-implemented +// object var longer than the instance. We should not call the destructor until +// the plugin releases its last ref. +TEST_F(PluginVarTrackerTest, PluginObjectLeaked) { + PP_Var host_object = MakeObject(12345); + PP_Instance pp_instance = 0x12345; + + int deallocate_called = 0; + void* user_data = &deallocate_called; + + // Make a var with one reference. + scoped_refptr<ProxyObjectVar> object( + new ProxyObjectVar(plugin_dispatcher(), host_object.value.as_id)); + PP_Var plugin_var = MakeObject(var_tracker().AddVar(object)); + var_tracker().PluginImplementedObjectCreated(pp_instance, + plugin_var, + &mark_on_deallocate_class, + user_data); + + // Destroy the innstance. This should not call deallocate since the plugin + // still has a ref. + var_tracker().DidDeleteInstance(pp_instance); + EXPECT_FALSE(deallocate_called); + + // Release the plugin ref to the var. Since the instance is gone this should + // call deallocate. + object = NULL; + var_tracker().ReleaseVar(plugin_var); + EXPECT_TRUE(deallocate_called); +} + } // namespace proxy } // namespace ppapi diff --git a/ppapi/proxy/ppb_var_deprecated_proxy.cc b/ppapi/proxy/ppb_var_deprecated_proxy.cc index fbd6ef9..2cd5ed0 100644 --- a/ppapi/proxy/ppb_var_deprecated_proxy.cc +++ b/ppapi/proxy/ppb_var_deprecated_proxy.cc @@ -18,6 +18,7 @@ #include "ppapi/proxy/plugin_globals.h" #include "ppapi/proxy/plugin_resource_tracker.h" #include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/proxy_object_var.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppp_class_proxy.h" #include "ppapi/proxy/serialized_var.h" @@ -254,6 +255,10 @@ PP_Var CreateObject(PP_Instance instance, if (!dispatcher) return PP_MakeUndefined(); + PluginVarTracker* tracker = PluginGlobals::Get()->plugin_var_tracker(); + if (tracker->IsPluginImplementedObjectAlive(ppp_class_data)) + return PP_MakeUndefined(); // Object already exists with this user data. + ReceiveSerializedVarReturnValue result; int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class)); int64 data_int = @@ -261,7 +266,12 @@ PP_Var CreateObject(PP_Instance instance, dispatcher->Send(new PpapiHostMsg_PPBVar_CreateObjectDeprecated( API_ID_PPB_VAR_DEPRECATED, instance, class_int, data_int, &result)); - return result.Return(dispatcher); + PP_Var ret_var = result.Return(dispatcher); + + // Register this object as being implemented by the plugin. + tracker->PluginImplementedObjectCreated(instance, ret_var, + ppp_class, ppp_class_data); + return ret_var; } InterfaceProxy* CreateVarDeprecatedProxy(Dispatcher* dispatcher) { diff --git a/ppapi/proxy/ppp_class_proxy.cc b/ppapi/proxy/ppp_class_proxy.cc index 0d3f86a..35f55d6 100644 --- a/ppapi/proxy/ppp_class_proxy.cc +++ b/ppapi/proxy/ppp_class_proxy.cc @@ -6,10 +6,12 @@ #include "ppapi/c/dev/ppb_var_deprecated.h" #include "ppapi/c/dev/ppp_class_deprecated.h" +#include "ppapi/c/pp_var.h" #include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" #include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/shared_impl/api_id.h" namespace ppapi { @@ -244,6 +246,8 @@ void PPP_Class_Proxy::OnMsgHasProperty(int64 ppp_class, int64 object, SerializedVarReceiveInput property, SerializedVarOutParam exception, bool* result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasProperty, ToUserData(object), property.Get(dispatcher()), @@ -254,6 +258,8 @@ void PPP_Class_Proxy::OnMsgHasMethod(int64 ppp_class, int64 object, SerializedVarReceiveInput property, SerializedVarOutParam exception, bool* result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasMethod, ToUserData(object), property.Get(dispatcher()), @@ -264,6 +270,8 @@ void PPP_Class_Proxy::OnMsgGetProperty(int64 ppp_class, int64 object, SerializedVarReceiveInput property, SerializedVarOutParam exception, SerializedVarReturnValue result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; result.Return(dispatcher(), CallWhileUnlocked( ToPPPClass(ppp_class)->GetProperty, ToUserData(object), property.Get(dispatcher()), @@ -274,6 +282,8 @@ void PPP_Class_Proxy::OnMsgEnumerateProperties( int64 ppp_class, int64 object, std::vector<SerializedVar>* props, SerializedVarOutParam exception) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; NOTIMPLEMENTED(); // TODO(brettw) implement this. } @@ -282,6 +292,8 @@ void PPP_Class_Proxy::OnMsgSetProperty(int64 ppp_class, int64 object, SerializedVarReceiveInput property, SerializedVarReceiveInput value, SerializedVarOutParam exception) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; CallWhileUnlocked(ToPPPClass(ppp_class)->SetProperty, ToUserData(object), property.Get(dispatcher()), value.Get(dispatcher()), exception.OutParam(dispatcher())); @@ -290,6 +302,8 @@ void PPP_Class_Proxy::OnMsgSetProperty(int64 ppp_class, int64 object, void PPP_Class_Proxy::OnMsgRemoveProperty(int64 ppp_class, int64 object, SerializedVarReceiveInput property, SerializedVarOutParam exception) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; CallWhileUnlocked(ToPPPClass(ppp_class)->RemoveProperty, ToUserData(object), property.Get(dispatcher()), exception.OutParam(dispatcher())); @@ -301,6 +315,8 @@ void PPP_Class_Proxy::OnMsgCall( SerializedVarVectorReceiveInput arg_vector, SerializedVarOutParam exception, SerializedVarReturnValue result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; uint32_t arg_count = 0; PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); result.Return(dispatcher(), CallWhileUnlocked(ToPPPClass(ppp_class)->Call, @@ -313,6 +329,8 @@ void PPP_Class_Proxy::OnMsgConstruct( SerializedVarVectorReceiveInput arg_vector, SerializedVarOutParam exception, SerializedVarReturnValue result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; uint32_t arg_count = 0; PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); result.Return(dispatcher(), CallWhileUnlocked( @@ -321,8 +339,26 @@ void PPP_Class_Proxy::OnMsgConstruct( } void PPP_Class_Proxy::OnMsgDeallocate(int64 ppp_class, int64 object) { + if (!ValidateUserData(ppp_class, object, NULL)) + return; CallWhileUnlocked(ToPPPClass(ppp_class)->Deallocate, ToUserData(object)); } +bool PPP_Class_Proxy::ValidateUserData(int64 ppp_class, int64 class_data, + SerializedVarOutParam* exception) { + if (!PluginGlobals::Get()->plugin_var_tracker()->ValidatePluginObjectCall( + ToPPPClass(ppp_class), ToUserData(class_data))) { + // Set the exception. This is so the caller will know about the error and + // also that we won't assert that somebody forgot to call OutParam on the + // output parameter. Although this exception of "1" won't be very useful + // this shouldn't happen in normal usage, only when the renderer is being + // malicious. + if (exception) + *exception->OutParam(dispatcher()) = PP_MakeInt32(1); + return false; + } + return true; +} + } // namespace proxy } // namespace ppapi diff --git a/ppapi/proxy/ppp_class_proxy.h b/ppapi/proxy/ppp_class_proxy.h index 5ad0959..f890b3d 100644 --- a/ppapi/proxy/ppp_class_proxy.h +++ b/ppapi/proxy/ppp_class_proxy.h @@ -86,6 +86,11 @@ class PPP_Class_Proxy : public InterfaceProxy { SerializedVarReturnValue result); void OnMsgDeallocate(int64 ppp_class, int64 object); + // Returns true if the given class/data points to a plugin-implemented + // object. On failure, the exception, if non-NULL, will also be set. + bool ValidateUserData(int64 ppp_class, int64 class_data, + SerializedVarOutParam* exception); + DISALLOW_COPY_AND_ASSIGN(PPP_Class_Proxy); }; diff --git a/ppapi/proxy/ppp_instance_proxy.cc b/ppapi/proxy/ppp_instance_proxy.cc index 083cc91..27495bb 100644 --- a/ppapi/proxy/ppp_instance_proxy.cc +++ b/ppapi/proxy/ppp_instance_proxy.cc @@ -219,7 +219,11 @@ void PPP_Instance_Proxy::OnPluginMsgDidCreate( void PPP_Instance_Proxy::OnPluginMsgDidDestroy(PP_Instance instance) { combined_interface_->DidDestroy(instance); - PpapiGlobals::Get()->GetResourceTracker()->DidDeleteInstance(instance); + + PpapiGlobals* globals = PpapiGlobals::Get(); + globals->GetResourceTracker()->DidDeleteInstance(instance); + globals->GetVarTracker()->DidDeleteInstance(instance); + static_cast<PluginDispatcher*>(dispatcher())->DidDestroyInstance(instance); } diff --git a/ppapi/proxy/proxy_object_var.cc b/ppapi/proxy/proxy_object_var.cc index acd53f3..cc0054f 100644 --- a/ppapi/proxy/proxy_object_var.cc +++ b/ppapi/proxy/proxy_object_var.cc @@ -14,9 +14,9 @@ namespace ppapi { ProxyObjectVar::ProxyObjectVar(PluginDispatcher* dispatcher, int32 host_var_id) : dispatcher_(dispatcher), - host_var_id_(host_var_id) { + host_var_id_(host_var_id), + user_data_(NULL) { // Should be given valid objects or we'll crash later. - DCHECK(dispatcher_); DCHECK(host_var_id_); } diff --git a/ppapi/proxy/proxy_object_var.h b/ppapi/proxy/proxy_object_var.h index e9760f9..5b9caa3 100644 --- a/ppapi/proxy/proxy_object_var.h +++ b/ppapi/proxy/proxy_object_var.h @@ -6,6 +6,7 @@ #define PPAPI_PROXY_PROXY_OBJECT_VAR_H_ #include "base/compiler_specific.h" +#include "ppapi/proxy/ppapi_proxy_export.h" #include "ppapi/shared_impl/var.h" namespace ppapi { @@ -17,7 +18,7 @@ class PluginDispatcher; // Tracks a reference to an object var in the plugin side of the proxy. This // just stores the dispatcher and host var ID, and provides the interface for // integrating this with PP_Var creation. -class ProxyObjectVar : public Var { +class PPAPI_PROXY_EXPORT ProxyObjectVar : public Var { public: ProxyObjectVar(proxy::PluginDispatcher* dispatcher, int32 host_var_id); @@ -31,6 +32,9 @@ class ProxyObjectVar : public Var { proxy::PluginDispatcher* dispatcher() const { return dispatcher_; } int32 host_var_id() const { return host_var_id_; } + void* user_data() const { return user_data_; } + void set_user_data(void* ud) { user_data_ = ud; } + // Expose AssignVarID on Var so the PluginResourceTracker can call us when // it's creating IDs. void AssignVarID(int32 id); @@ -39,6 +43,11 @@ class ProxyObjectVar : public Var { proxy::PluginDispatcher* dispatcher_; int32 host_var_id_; + // When this object is created as representing a var implemented by the + // plugin, this stores the user data so that we can look it up later. See + // PluginVarTracker. + void* user_data_; + DISALLOW_COPY_AND_ASSIGN(ProxyObjectVar); }; diff --git a/ppapi/shared_impl/test_globals.h b/ppapi/shared_impl/test_globals.h index 2fa2192..3675347 100644 --- a/ppapi/shared_impl/test_globals.h +++ b/ppapi/shared_impl/test_globals.h @@ -20,6 +20,8 @@ class TestVarTracker : public VarTracker { virtual ArrayBufferVar* CreateArrayBuffer(uint32 size_in_bytes) OVERRIDE { return NULL; } + virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE { + } }; // Implementation of PpapiGlobals for tests that don't need either the host- or diff --git a/ppapi/shared_impl/var_tracker.h b/ppapi/shared_impl/var_tracker.h index 9ab22f2..b873250 100644 --- a/ppapi/shared_impl/var_tracker.h +++ b/ppapi/shared_impl/var_tracker.h @@ -11,6 +11,7 @@ #include "base/hash_tables.h" #include "base/memory/ref_counted.h" #include "base/threading/non_thread_safe.h" +#include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_module.h" #include "ppapi/c/pp_var.h" #include "ppapi/shared_impl/ppapi_shared_export.h" @@ -84,6 +85,9 @@ class PPAPI_SHARED_EXPORT VarTracker int GetRefCountForObject(const PP_Var& object); int GetTrackedWithNoReferenceCountForObject(const PP_Var& object); + // Called after an instance is deleted to do var cleanup. + virtual void DidDeleteInstance(PP_Instance instance) = 0; + protected: struct VarInfo { VarInfo(); diff --git a/webkit/plugins/ppapi/host_globals.cc b/webkit/plugins/ppapi/host_globals.cc index 610ff15..643ea8c 100644 --- a/webkit/plugins/ppapi/host_globals.cc +++ b/webkit/plugins/ppapi/host_globals.cc @@ -240,13 +240,13 @@ PP_Instance HostGlobals::AddInstance(PluginInstance* instance) { void HostGlobals::InstanceDeleted(PP_Instance instance) { resource_tracker_.DidDeleteInstance(instance); - host_var_tracker_.ForceFreeNPObjectsForInstance(instance); + host_var_tracker_.DidDeleteInstance(instance); instance_map_.erase(instance); } void HostGlobals::InstanceCrashed(PP_Instance instance) { resource_tracker_.DidDeleteInstance(instance); - host_var_tracker_.ForceFreeNPObjectsForInstance(instance); + host_var_tracker_.DidDeleteInstance(instance); } PluginInstance* HostGlobals::GetInstance(PP_Instance instance) { diff --git a/webkit/plugins/ppapi/host_var_tracker.cc b/webkit/plugins/ppapi/host_var_tracker.cc index 97db0fc..ed1b856 100644 --- a/webkit/plugins/ppapi/host_var_tracker.cc +++ b/webkit/plugins/ppapi/host_var_tracker.cc @@ -100,7 +100,7 @@ int HostVarTracker::GetLiveNPObjectVarsForInstance(PP_Instance instance) const { return static_cast<int>(found->second->size()); } -void HostVarTracker::ForceFreeNPObjectsForInstance(PP_Instance instance) { +void HostVarTracker::DidDeleteInstance(PP_Instance instance) { DCHECK(CalledOnValidThread()); InstanceMap::iterator found_instance = instance_map_.find(instance); @@ -130,8 +130,8 @@ void HostVarTracker::ForceFreeNPObjectsForInstance(PP_Instance instance) { void HostVarTracker::ForceReleaseNPObject( const base::WeakPtr< ::ppapi::NPObjectVar>& object) { // There's a chance that the object was already deleted before we got here. - // See ForceFreeNPObjectsForInstance for further explanation. If the object - // was deleted, the WeakPtr will return NULL. + // See DidDeleteInstance for further explanation. If the object was deleted, + // the WeakPtr will return NULL. if (!object.get()) return; object->InstanceDeleted(); diff --git a/webkit/plugins/ppapi/host_var_tracker.h b/webkit/plugins/ppapi/host_var_tracker.h index c6d79cb..510e860 100644 --- a/webkit/plugins/ppapi/host_var_tracker.h +++ b/webkit/plugins/ppapi/host_var_tracker.h @@ -56,12 +56,11 @@ class HostVarTracker : public ::ppapi::VarTracker { WEBKIT_PLUGINS_EXPORT int GetLiveNPObjectVarsForInstance( PP_Instance instance) const; - // Forcibly deletes all np object vars for the given instance. Used for - // instance cleanup. - void ForceFreeNPObjectsForInstance(PP_Instance instance); + // VarTracker public implementation. + virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE; private: - // VarTracker implementation. + // VarTracker private implementation. virtual ::ppapi::ArrayBufferVar* CreateArrayBuffer( uint32 size_in_bytes) OVERRIDE; |