summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-18 19:41:30 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-18 19:41:30 +0000
commitedb5b05700f53fb7b1827727777cc15b50370ccb (patch)
tree4cc0fc0bf581503e6fd273a037a63353ca41bf9c /ppapi
parentdc20acdfb4026b23709beec34a187dfde58af437 (diff)
downloadchromium_src-edb5b05700f53fb7b1827727777cc15b50370ccb.zip
chromium_src-edb5b05700f53fb7b1827727777cc15b50370ccb.tar.gz
chromium_src-edb5b05700f53fb7b1827727777cc15b50370ccb.tar.bz2
Actually free plugin implement vars when running out of process when the
plugin holds a reference beyond the lifetime of the instance. Review URL: https://chromiumcodereview.appspot.com/10542150 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142787 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r--ppapi/c/dev/ppb_var_deprecated.h3
-rw-r--r--ppapi/proxy/plugin_var_tracker.cc90
-rw-r--r--ppapi/proxy/plugin_var_tracker.h77
-rw-r--r--ppapi/proxy/plugin_var_tracker_unittest.cc81
-rw-r--r--ppapi/proxy/ppb_var_deprecated_proxy.cc12
-rw-r--r--ppapi/proxy/ppp_class_proxy.cc38
-rw-r--r--ppapi/proxy/ppp_class_proxy.h5
-rw-r--r--ppapi/proxy/ppp_instance_proxy.cc6
-rw-r--r--ppapi/proxy/proxy_object_var.cc4
-rw-r--r--ppapi/proxy/proxy_object_var.h11
-rw-r--r--ppapi/shared_impl/test_globals.h2
-rw-r--r--ppapi/shared_impl/var_tracker.h4
12 files changed, 326 insertions, 7 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();