diff options
author | dmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-22 08:35:52 +0000 |
---|---|---|
committer | dmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-22 08:35:52 +0000 |
commit | a732cec70e194fb770c0eee12430fcc416843364 (patch) | |
tree | 7ceafca7e48d4a5da68ef28f4b77f1b7ba21c2f3 | |
parent | 02871872970e86b2255049ebe66c7f54ef50c721 (diff) | |
download | chromium_src-a732cec70e194fb770c0eee12430fcc416843364.zip chromium_src-a732cec70e194fb770c0eee12430fcc416843364.tar.gz chromium_src-a732cec70e194fb770c0eee12430fcc416843364.tar.bz2 |
Add GetLiveVars to PPB_Testing_Dev. Fix leaks it uncovered.
BUG=108308,108314
TEST=
Review URL: http://codereview.chromium.org/8982006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115503 0039d316-1c4b-4281-b951-d872f2087c98
40 files changed, 424 insertions, 71 deletions
diff --git a/ppapi/api/dev/ppb_testing_dev.idl b/ppapi/api/dev/ppb_testing_dev.idl index 9e51b42..fa63fce 100644 --- a/ppapi/api/dev/ppb_testing_dev.idl +++ b/ppapi/api/dev/ppb_testing_dev.idl @@ -12,7 +12,8 @@ label Chrome { M14 = 0.7, M15 = 0.8, - M17 = 0.9 + M17 = 0.9, + M18 = 0.91 }; interface PPB_Testing_Dev { @@ -114,4 +115,16 @@ interface PPB_Testing_Dev { [version=0.9] PP_Var GetDocumentURL([in] PP_Instance instance, [out] PP_URLComponents_Dev components); + + /** + * Fetches up to |array_size| active PP_Vars in the tracker. Returns the + * number of vars in the tracker. The active vars are written to |live_vars| + * contiguously starting at index 0. The vars are not in any particular order. + * If the number of live vars is greater than |array_size|, then an arbitrary + * subset of |array_size| vars is written to |live_vars|. The reference count + * of the returned PP_Vars will *not* be affected by this call. + */ + [version=0.91] + uint32_t GetLiveVars([size_as=array_size] PP_Var[] live_vars, + [in] uint32_t array_size); }; diff --git a/ppapi/c/dev/ppb_testing_dev.h b/ppapi/c/dev/ppb_testing_dev.h index c892f6b..e52eeb2 100644 --- a/ppapi/c/dev/ppb_testing_dev.h +++ b/ppapi/c/dev/ppb_testing_dev.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* From dev/ppb_testing_dev.idl modified Wed Dec 14 12:58:12 2011. */ +/* From dev/ppb_testing_dev.idl modified Fri Dec 16 16:08:07 2011. */ #ifndef PPAPI_C_DEV_PPB_TESTING_DEV_H_ #define PPAPI_C_DEV_PPB_TESTING_DEV_H_ @@ -20,7 +20,8 @@ #define PPB_TESTING_DEV_INTERFACE_0_7 "PPB_Testing(Dev);0.7" #define PPB_TESTING_DEV_INTERFACE_0_8 "PPB_Testing(Dev);0.8" #define PPB_TESTING_DEV_INTERFACE_0_9 "PPB_Testing(Dev);0.9" -#define PPB_TESTING_DEV_INTERFACE PPB_TESTING_DEV_INTERFACE_0_9 +#define PPB_TESTING_DEV_INTERFACE_0_91 "PPB_Testing(Dev);0.91" +#define PPB_TESTING_DEV_INTERFACE PPB_TESTING_DEV_INTERFACE_0_91 /** * @file @@ -124,6 +125,15 @@ struct PPB_Testing_Dev { */ struct PP_Var (*GetDocumentURL)(PP_Instance instance, struct PP_URLComponents_Dev* components); + /** + * Fetches up to |array_size| active PP_Vars in the tracker. Returns the + * number of vars in the tracker. The active vars are written to |live_vars| + * contiguously starting at index 0. The vars are not in any particular order. + * If the number of live vars is greater than |array_size|, then an arbitrary + * subset of |array_size| vars is written to |live_vars|. The reference count + * of the returned PP_Vars will *not* be affected by this call. + */ + uint32_t (*GetLiveVars)(struct PP_Var live_vars[], uint32_t array_size); }; struct PPB_Testing_Dev_0_7 { @@ -146,6 +156,19 @@ struct PPB_Testing_Dev_0_8 { PP_Bool (*IsOutOfProcess)(); void (*SimulateInputEvent)(PP_Instance instance, PP_Resource input_event); }; + +struct PPB_Testing_Dev_0_9 { + PP_Bool (*ReadImageData)(PP_Resource device_context_2d, + PP_Resource image, + const struct PP_Point* top_left); + void (*RunMessageLoop)(PP_Instance instance); + void (*QuitMessageLoop)(PP_Instance instance); + uint32_t (*GetLiveObjectsForInstance)(PP_Instance instance); + PP_Bool (*IsOutOfProcess)(); + void (*SimulateInputEvent)(PP_Instance instance, PP_Resource input_event); + struct PP_Var (*GetDocumentURL)(PP_Instance instance, + struct PP_URLComponents_Dev* components); +}; /** * @} */ diff --git a/ppapi/cpp/dev/var_array_buffer_dev.cc b/ppapi/cpp/dev/var_array_buffer_dev.cc index 4ce6215..61f697e 100644 --- a/ppapi/cpp/dev/var_array_buffer_dev.cc +++ b/ppapi/cpp/dev/var_array_buffer_dev.cc @@ -32,6 +32,7 @@ VarArrayBuffer_Dev::VarArrayBuffer_Dev(uint32_t size_in_bytes) : buffer_(NULL) { if (has_interface<PPB_VarArrayBuffer_Dev>()) { var_ = get_interface<PPB_VarArrayBuffer_Dev>()->Create(size_in_bytes); + needs_release_ = true; buffer_ = Map(); } else { PP_NOTREACHED(); diff --git a/ppapi/cpp/var.cc b/ppapi/cpp/var.cc index 2b52f04..512fd00 100644 --- a/ppapi/cpp/var.cc +++ b/ppapi/cpp/var.cc @@ -104,7 +104,7 @@ Var::Var(const std::string& utf8_str) { Var::Var(const Var& other) { var_ = other.var_; if (NeedsRefcounting(var_)) { - if (has_interface<PPB_Var>()) { + if (has_interface<PPB_Var_1_0>()) { needs_release_ = true; get_interface<PPB_Var_1_0>()->AddRef(var_); } else { @@ -117,7 +117,7 @@ Var::Var(const Var& other) { } Var::~Var() { - if (needs_release_ && has_interface<PPB_Var>()) + if (needs_release_ && has_interface<PPB_Var_1_0>()) get_interface<PPB_Var_1_0>()->Release(var_); } @@ -132,8 +132,8 @@ Var& Var::operator=(const Var& other) { // object to itself by addrefing the new one before releasing the old one. bool old_needs_release = needs_release_; if (NeedsRefcounting(other.var_)) { - // Assume we already has_interface<PPB_Var> for refcounted vars or else we - // couldn't have created them in the first place. + // Assume we already has_interface<PPB_Var_1_0> for refcounted vars or else + // we couldn't have created them in the first place. needs_release_ = true; get_interface<PPB_Var_1_0>()->AddRef(other.var_); } else { @@ -203,7 +203,7 @@ std::string Var::AsString() const { return std::string(); } - if (!has_interface<PPB_Var>()) + if (!has_interface<PPB_Var_1_0>()) return std::string(); uint32_t len; const char* str = get_interface<PPB_Var_1_0>()->VarToUtf8(var_, &len); @@ -213,18 +213,18 @@ std::string Var::AsString() const { std::string Var::DebugString() const { char buf[256]; if (is_undefined()) { - snprintf(buf, sizeof(buf), "Var<UNDEFINED>"); + snprintf(buf, sizeof(buf), "Var(UNDEFINED)"); } else if (is_null()) { - snprintf(buf, sizeof(buf), "Var<NULL>"); + snprintf(buf, sizeof(buf), "Var(NULL)"); } else if (is_bool()) { - snprintf(buf, sizeof(buf), AsBool() ? "Var<true>" : "Var<false>"); + snprintf(buf, sizeof(buf), AsBool() ? "Var(true)" : "Var(false)"); } else if (is_int()) { // Note that the following static_cast is necessary because // NativeClient's int32_t is actually "long". // TODO(sehr,polina): remove this after newlib is changed. - snprintf(buf, sizeof(buf), "Var<%d>", static_cast<int>(AsInt())); + snprintf(buf, sizeof(buf), "Var(%d)", static_cast<int>(AsInt())); } else if (is_double()) { - snprintf(buf, sizeof(buf), "Var<%f>", AsDouble()); + snprintf(buf, sizeof(buf), "Var(%f)", AsDouble()); } else if (is_string()) { char format[] = "Var<'%s'>"; size_t decoration = sizeof(format) - 2; // The %s is removed. @@ -235,8 +235,12 @@ std::string Var::DebugString() const { str.append("..."); } snprintf(buf, sizeof(buf), format, str.c_str()); + } else if (is_array_buffer()) { + // TODO(dmichael): We could make this dump hex. Maybe DebugString should be + // virtual? + snprintf(buf, sizeof(buf), "Var(ARRAY_BUFFER)"); } else if (is_object()) { - snprintf(buf, sizeof(buf), "Var<OBJECT>"); + snprintf(buf, sizeof(buf), "Var(OBJECT)"); } return buf; } diff --git a/ppapi/native_client/src/shared/ppapi_proxy/browser_ppb_messaging_rpc_server.cc b/ppapi/native_client/src/shared/ppapi_proxy/browser_ppb_messaging_rpc_server.cc index 08b525b..d2d35e5 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/browser_ppb_messaging_rpc_server.cc +++ b/ppapi/native_client/src/shared/ppapi_proxy/browser_ppb_messaging_rpc_server.cc @@ -13,6 +13,7 @@ #endif using ppapi_proxy::PPBMessagingInterface; +using ppapi_proxy::PPBVarInterface; using ppapi_proxy::DebugPrintf; using ppapi_proxy::DeserializeTo; @@ -30,6 +31,11 @@ void PpbMessagingRpcServer::PPB_Messaging_PostMessage( return; PPBMessagingInterface()->PostMessage(instance, message); + + // In the case of a string, DeserializeTo creates a PP_Var with a reference- + // count of 1. We must release the var, or it will stay in the browser's map. + PPBVarInterface()->Release(message); + DebugPrintf("PPB_Messaging::PostMessage: instance=%"NACL_PRIu32"\n", instance); diff --git a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb.cc b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb.cc index ab894f7..d4d2511 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb.cc +++ b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb.cc @@ -83,9 +83,8 @@ InterfaceMapElement interface_map[] = { { PPB_SCROLLBAR_DEV_INTERFACE, PluginScrollbar::GetInterface(), true }, { PPB_TCPSOCKET_PRIVATE_INTERFACE, PluginTCPSocketPrivate::GetInterface(), true }, - { PPB_TESTING_DEV_INTERFACE_0_7, PluginTesting::GetInterface(), true }, - { PPB_TESTING_DEV_INTERFACE_0_8, PluginTesting::GetInterface(), true }, { PPB_TESTING_DEV_INTERFACE_0_9, PluginTesting::GetInterface(), true }, + { PPB_TESTING_DEV_INTERFACE, PluginTesting::GetInterface(), true }, { PPB_UDPSOCKET_PRIVATE_INTERFACE, PluginUDPSocketPrivate::GetInterface(), true }, { PPB_URLLOADER_INTERFACE, PluginURLLoader::GetInterface(), true }, diff --git a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_testing.cc b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_testing.cc index 5c81a2a..dbd01b44 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_testing.cc +++ b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_testing.cc @@ -6,12 +6,14 @@ #include <cstddef> #include <new> +#include <vector> #include "native_client/src/include/nacl_scoped_ptr.h" #include "native_client/src/include/portability.h" #include "native_client/src/shared/ppapi_proxy/object_serialize.h" #include "native_client/src/shared/ppapi_proxy/plugin_globals.h" #include "native_client/src/shared/ppapi_proxy/plugin_callback.h" +#include "native_client/src/shared/ppapi_proxy/proxy_var_cache.h" #include "native_client/src/shared/ppapi_proxy/utility.h" #include "ppapi/c/dev/ppb_testing_dev.h" #include "ppapi/c/pp_completion_callback.h" @@ -145,6 +147,18 @@ struct PP_Var GetDocumentURL(PP_Instance instance, return url; } +// TODO(dmichael): Ideally we could get a way to check the number of vars in the +// host-side tracker when running NaCl, to make sure the proxy does not leak +// host-side vars. +uint32_t GetLiveVars(PP_Var live_vars[], uint32_t array_size) { + std::vector<PP_Var> vars = ProxyVarCache::GetInstance().GetLiveVars(); + for (size_t i = 0u; + i < std::min(static_cast<size_t>(array_size), vars.size()); + ++i) + live_vars[i] = vars[i]; + return vars.size(); +} + } // namespace const PPB_Testing_Dev* PluginTesting::GetInterface() { @@ -155,7 +169,8 @@ const PPB_Testing_Dev* PluginTesting::GetInterface() { GetLiveObjectsForInstance, IsOutOfProcess, SimulateInputEvent, - GetDocumentURL + GetDocumentURL, + GetLiveVars }; return &testing_interface; } diff --git a/ppapi/native_client/src/shared/ppapi_proxy/proxy_var_cache.cc b/ppapi/native_client/src/shared/ppapi_proxy/proxy_var_cache.cc index 636302c..b172869 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/proxy_var_cache.cc +++ b/ppapi/native_client/src/shared/ppapi_proxy/proxy_var_cache.cc @@ -16,6 +16,17 @@ namespace { pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; +// Convert the given SharedProxyVar to a PP_Var, incrementing the reference +// count by 1. +PP_Var GetPPVar(const SharedProxyVar& proxy_var) { + PP_Var var; + var.type = proxy_var->pp_var_type(); + var.padding = 0; + var.value.as_id = proxy_var->id(); + proxy_var->AddRef(); + return var; +} + } // namespace ProxyVarCache* ProxyVarCache::cache_singleton = NULL; @@ -86,4 +97,15 @@ SharedProxyVar ProxyVarCache::SharedProxyVarForVar(PP_Var pp_var) const { return proxy_var; } +std::vector<PP_Var> ProxyVarCache::GetLiveVars() { + std::vector<PP_Var> live_vars; + pthread_mutex_lock(&mu); + for (ProxyVarDictionary::const_iterator iter(proxy_var_cache_.begin()); + iter != proxy_var_cache_.end(); + ++iter) + live_vars.push_back(GetPPVar(iter->second)); + pthread_mutex_unlock(&mu); + return live_vars; +} + } // namespace ppapi_proxy diff --git a/ppapi/native_client/src/shared/ppapi_proxy/proxy_var_cache.h b/ppapi/native_client/src/shared/ppapi_proxy/proxy_var_cache.h index 41c8d0c..6cec6d4 100644 --- a/ppapi/native_client/src/shared/ppapi_proxy/proxy_var_cache.h +++ b/ppapi/native_client/src/shared/ppapi_proxy/proxy_var_cache.h @@ -6,6 +6,7 @@ #define NATIVE_CLIENT_SRC_SHARED_PPAPI_PROXY_PROXY_VAR_CACHE_H_ #include <map> +#include <vector> #include "native_client/src/include/nacl_memory.h" #include "native_client/src/shared/ppapi_proxy/proxy_var.h" @@ -48,6 +49,9 @@ class ProxyVarCache { // Find the object in the cache associated with |pp_var|. SharedProxyVar SharedProxyVarForVar(PP_Var pp_var) const; + // Return all live Vars in the tracker. Reference counts are incremented. + std::vector<PP_Var> GetLiveVars(); + private: // Return whether or not a var type is cached. // Note to implementers: be sure to add to this function when adding new diff --git a/ppapi/proxy/plugin_var_serialization_rules.cc b/ppapi/proxy/plugin_var_serialization_rules.cc index 155c844..a4eea5b 100644 --- a/ppapi/proxy/plugin_var_serialization_rules.cc +++ b/ppapi/proxy/plugin_var_serialization_rules.cc @@ -136,6 +136,8 @@ void PluginVarSerializationRules::EndSendPassRef(const PP_Var& var, if (var.type == PP_VARTYPE_OBJECT) { var_tracker_->ReleaseHostObject( static_cast<PluginDispatcher*>(dispatcher), var); + } else if (var.type == PP_VARTYPE_STRING) { + var_tracker_->ReleaseVar(var); } } diff --git a/ppapi/proxy/ppb_testing_proxy.cc b/ppapi/proxy/ppb_testing_proxy.cc index 77d1af0..32d5215 100644 --- a/ppapi/proxy/ppb_testing_proxy.cc +++ b/ppapi/proxy/ppb_testing_proxy.cc @@ -95,6 +95,19 @@ PP_Var GetDocumentURL(PP_Instance instance, PP_URLComponents_Dev* components) { return enter.functions()->GetDocumentURL(instance, components); } +// TODO(dmichael): Ideally we could get a way to check the number of vars in the +// host-side tracker when running out-of-process, to make sure the proxy does +// not leak host-side vars. +uint32_t GetLiveVars(PP_Var live_vars[], uint32_t array_size) { + std::vector<PP_Var> vars = + PpapiGlobals::Get()->GetVarTracker()->GetLiveVars(); + for (size_t i = 0u; + i < std::min(static_cast<size_t>(array_size), vars.size()); + ++i) + live_vars[i] = vars[i]; + return vars.size(); +} + const PPB_Testing_Dev testing_interface = { &ReadImageData, &RunMessageLoop, @@ -102,7 +115,8 @@ const PPB_Testing_Dev testing_interface = { &GetLiveObjectsForInstance, &IsOutOfProcess, &SimulateInputEvent, - &GetDocumentURL + &GetDocumentURL, + &GetLiveVars }; InterfaceProxy* CreateTestingProxy(Dispatcher* dispatcher) { diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc index b892daf..f9d59e5 100644 --- a/ppapi/proxy/serialized_var.cc +++ b/ppapi/proxy/serialized_var.cc @@ -411,7 +411,7 @@ PP_Var* SerializedVarVectorReceiveInput::Get(Dispatcher* dispatcher, uint32_t* array_size) { deserialized_.resize(serialized_.size()); for (size_t i = 0; i < serialized_.size(); i++) { - // The vector must be able to clean themselves up after this call is + // The vectors must be able to clean themselves up after this call is // torn down. serialized_[i].inner_->set_serialization_rules( dispatcher->serialization_rules()); diff --git a/ppapi/proxy/serialized_var.h b/ppapi/proxy/serialized_var.h index e75f480..c0cb1ac 100644 --- a/ppapi/proxy/serialized_var.h +++ b/ppapi/proxy/serialized_var.h @@ -184,7 +184,7 @@ class PPAPI_PROXY_EXPORT SerializedVar { // void MyFunctionProxy(PP_Var param) { // Send(new MyFunctionMsg(SerializedVarSendInput(dispatcher, param)); // } -class SerializedVarSendInput : public SerializedVar { +class PPAPI_PROXY_EXPORT SerializedVarSendInput : public SerializedVar { public: SerializedVarSendInput(Dispatcher* dispatcher, const PP_Var& var); @@ -243,7 +243,7 @@ class PPAPI_PROXY_EXPORT ReceiveSerializedVarReturnValue // ReceiveSerializedException se(dispatcher(), exception) // Send(new PpapiHostMsg_Foo(&se)); // } -class ReceiveSerializedException : public SerializedVar { +class PPAPI_PROXY_EXPORT ReceiveSerializedException : public SerializedVar { public: ReceiveSerializedException(Dispatcher* dispatcher, PP_Var* exception); ~ReceiveSerializedException(); @@ -274,7 +274,7 @@ class ReceiveSerializedException : public SerializedVar { // ReceiveSerializedVarVectorOutParam vect(dispatcher, count, vars); // Send(new MyMsg(vect.OutParam())); // } -class ReceiveSerializedVarVectorOutParam { +class PPAPI_PROXY_EXPORT ReceiveSerializedVarVectorOutParam { public: ReceiveSerializedVarVectorOutParam(Dispatcher* dispatcher, uint32_t* output_count, @@ -333,7 +333,7 @@ class PPAPI_PROXY_EXPORT SerializedVarReceiveInput { // PP_Var* array = vector.Get(dispatcher, &size); // MyFunction(size, array); // } -class SerializedVarVectorReceiveInput { +class PPAPI_PROXY_EXPORT SerializedVarVectorReceiveInput { public: SerializedVarVectorReceiveInput(const std::vector<SerializedVar>& serialized); ~SerializedVarVectorReceiveInput(); @@ -415,7 +415,7 @@ class PPAPI_PROXY_EXPORT SerializedVarOutParam { // For returning an array of PP_Vars to the other side and transferring // ownership. // -class SerializedVarVectorOutParam { +class PPAPI_PROXY_EXPORT SerializedVarVectorOutParam { public: SerializedVarVectorOutParam(std::vector<SerializedVar>* serialized); ~SerializedVarVectorOutParam(); diff --git a/ppapi/proxy/serialized_var_unittest.cc b/ppapi/proxy/serialized_var_unittest.cc index 8ad6c99..150f5e7 100644 --- a/ppapi/proxy/serialized_var_unittest.cc +++ b/ppapi/proxy/serialized_var_unittest.cc @@ -11,13 +11,6 @@ namespace proxy { namespace { -PP_Var MakeStringVar(int64_t string_id) { - PP_Var ret; - ret.type = PP_VARTYPE_STRING; - ret.value.as_id = string_id; - return ret; -} - PP_Var MakeObjectVar(int64_t object_id) { PP_Var ret; ret.type = PP_VARTYPE_OBJECT; @@ -34,6 +27,95 @@ class SerializedVarTest : public PluginProxyTest { // Tests output arguments in the plugin. This is when the host calls into the // plugin and the plugin returns something via an out param, like an exception. +TEST_F(SerializedVarTest, PluginSerializedVarInOutParam) { + PP_Var host_object = MakeObjectVar(0x31337); + + PP_Var plugin_object; + { + // Receive the object param, we should be tracking it with no refcount, and + // no messages sent. + SerializedVarTestConstructor input(host_object); + SerializedVarReceiveInput receive_input(input); + plugin_object = receive_input.Get(plugin_dispatcher()); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0u, sink().message_count()); + + SerializedVar sv; + { + // The "OutParam" does its work in its destructor, it will write the + // information to the SerializedVar we passed in the constructor. + SerializedVarOutParam out_param(&sv); + // An out-param needs to pass a reference to the caller, so it's the + // responsibility of the plugin to bump the ref-count on an input + // parameter. + var_tracker().AddRefVar(plugin_object); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + // We should have informed the host that a reference was taken. + EXPECT_EQ(1u, sink().message_count()); + *out_param.OutParam(plugin_dispatcher()) = plugin_object; + } + + // The object should have transformed the plugin object back to the host + // object ID. Nothing in the var tracker should have changed yet, and no + // messages should have been sent. + SerializedVarTestReader reader(sv); + EXPECT_EQ(host_object.value.as_id, reader.GetIncompleteVar().value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(1u, sink().message_count()); + } + + // The out param should have done an "end receive caller owned" on the plugin + // var serialization rules, which should have released the "track-with-no- + // reference" count in the var tracker as well as the 1 reference we passed + // back to the host, so the object should no longer be in the tracker. The + // reference we added has been removed, so another message should be sent to + // the host to tell it we're done with the object. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(2u, sink().message_count()); +} + +// Tests output strings in the plugin. This is when the host calls into the +// plugin with a string and the plugin returns it via an out param. +TEST_F(SerializedVarTest, PluginSerializedStringVarInOutParam) { + PP_Var plugin_string; + const std::string kTestString("elite"); + { + // Receive the string param. We should track it with 1 refcount. + SerializedVarTestConstructor input(kTestString); + SerializedVarReceiveInput receive_input(input); + plugin_string = receive_input.Get(plugin_dispatcher()); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_string)); + EXPECT_EQ(0u, sink().message_count()); + + SerializedVar sv; + { + // The "OutParam" does its work in its destructor, it will write the + // information to the SerializedVar we passed in the constructor. + SerializedVarOutParam out_param(&sv); + // An out-param needs to pass a reference to the caller, so it's the + // responsibility of the plugin to bump the ref-count of an input + // parameter. + var_tracker().AddRefVar(plugin_string); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string)); + EXPECT_EQ(0u, sink().message_count()); + *out_param.OutParam(plugin_dispatcher()) = plugin_string; + } + + // The SerializedVar should have set the string value internally. Nothing in + // the var tracker should have changed yet, and no messages should have been + // sent. + SerializedVarTestReader reader(sv); + EXPECT_EQ(kTestString, reader.GetString()); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string)); + EXPECT_EQ(0u, sink().message_count()); + } + // The reference the string had initially should be gone, and the reference we + // passed to the host should also be gone, so the string should be removed. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_string)); + EXPECT_EQ(0u, sink().message_count()); +} + +// Tests receiving an argument and passing it back out as an output parameter. TEST_F(SerializedVarTest, PluginSerializedVarOutParam) { PP_Var host_object = MakeObjectVar(0x31337); @@ -111,6 +193,72 @@ TEST_F(SerializedVarTest, PluginReceiveInput) { EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); } +// Tests the case that the plugin receives the same vars twice as an input +// parameter (not passing ownership) within a vector. +TEST_F(SerializedVarTest, PluginVectorReceiveInput) { + PP_Var host_object = MakeObjectVar(0x31337); + + PP_Var* plugin_objects; + PP_Var* plugin_objects2; + { + // Receive the params. The object should be tracked with no refcount and + // no messages sent. The string should is plugin-side only and should have + // a reference-count of 1. + std::vector<SerializedVar> input1; + input1.push_back(SerializedVarTestConstructor(host_object)); + input1.push_back(SerializedVarTestConstructor("elite")); + SerializedVarVectorReceiveInput receive_input(input1); + uint32_t array_size = 0; + plugin_objects = receive_input.Get(plugin_dispatcher(), &array_size); + ASSERT_EQ(2u, array_size); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1])); + EXPECT_EQ(0u, sink().message_count()); + + // Receive the second param, it should be resolved to the same plugin + // object and there should still be no refcount. + std::vector<SerializedVar> input2; + input2.push_back(SerializedVarTestConstructor(host_object)); + input2.push_back(SerializedVarTestConstructor("elite")); + SerializedVarVectorReceiveInput receive_input2(input2); + uint32_t array_size2 = 0; + plugin_objects2 = receive_input2.Get(plugin_dispatcher(), &array_size2); + ASSERT_EQ(2u, array_size2); + EXPECT_EQ(plugin_objects[0].value.as_id, plugin_objects2[0].value.as_id); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); + // Strings get re-created with a new ID. We don't try to reuse strings in + // the tracker, so the string should get a new ID. + EXPECT_NE(plugin_objects[1].value.as_id, plugin_objects2[1].value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects2[1])); + EXPECT_EQ(0u, sink().message_count()); + + // Take a reference to the object, as if the plugin was using it, and then + // release it, we should still be tracking the object since the + // ReceiveInputs keep the "track_with_no_reference_count" alive until + // they're destroyed. + var_tracker().AddRefVar(plugin_objects[0]); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[0])); + var_tracker().ReleaseVar(plugin_objects[0]); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); + EXPECT_EQ(2u, sink().message_count()); + + // Take a reference to a string and then release it. Make sure no messages + // are sent. + uint32_t old_message_count = sink().message_count(); + var_tracker().AddRefVar(plugin_objects[1]); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_objects[1])); + var_tracker().ReleaseVar(plugin_objects[1]); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1])); + EXPECT_EQ(old_message_count, sink().message_count()); + } + + // Since we didn't keep any refs to the objects or strings, so they should + // have been freed. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[0])); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[1])); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects2[1])); +} + // Tests the plugin receiving a var as a return value from the browser // two different times (passing ownership). TEST_F(SerializedVarTest, PluginReceiveReturn) { diff --git a/ppapi/shared_impl/var_tracker.cc b/ppapi/shared_impl/var_tracker.cc index 287e7b1..58c715c 100644 --- a/ppapi/shared_impl/var_tracker.cc +++ b/ppapi/shared_impl/var_tracker.cc @@ -149,6 +149,17 @@ PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes) { return array_buffer->GetPPVar(); } +std::vector<PP_Var> VarTracker::GetLiveVars() { + std::vector<PP_Var> var_vector; + var_vector.reserve(live_vars_.size()); + for (VarMap::const_iterator iter = live_vars_.begin(); + iter != live_vars_.end(); + ++iter) { + var_vector.push_back(iter->second.var->GetPPVar()); + } + return var_vector; +} + void VarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator obj) { // Anybody using tracked objects should override this. NOTREACHED(); diff --git a/ppapi/shared_impl/var_tracker.h b/ppapi/shared_impl/var_tracker.h index a2debe0..4dc8a2d 100644 --- a/ppapi/shared_impl/var_tracker.h +++ b/ppapi/shared_impl/var_tracker.h @@ -5,6 +5,8 @@ #ifndef PPAPI_SHARED_IMPL_VAR_TRACKER_H_ #define PPAPI_SHARED_IMPL_VAR_TRACKER_H_ +#include <vector> + #include "base/basictypes.h" #include "base/hash_tables.h" #include "base/memory/ref_counted.h" @@ -60,6 +62,12 @@ class PPAPI_SHARED_EXPORT VarTracker { // that references it and has an initial reference-count of 1. PP_Var MakeArrayBufferPPVar(uint32 size_in_bytes); + // Return a vector containing all PP_Vars that are in the tracker. This is + // to help implement PPB_Testing_Dev.GetLiveVars and should generally not be + // used in production code. The PP_Vars are returned in no particular order, + // and their reference counts are unaffected. + std::vector<PP_Var> GetLiveVars(); + protected: struct VarInfo { VarInfo(); diff --git a/ppapi/tests/test_case.cc b/ppapi/tests/test_case.cc index bcee6c3..e6164e0 100644 --- a/ppapi/tests/test_case.cc +++ b/ppapi/tests/test_case.cc @@ -13,6 +13,10 @@ TestCase::TestCase(TestingInstance* instance) : instance_(instance), testing_interface_(NULL), force_async_(false) { + // Get the testing_interface_ if it is available, so that we can do Resource + // and Var checks on shutdown (see CheckResourcesAndVars). If it is not + // available, testing_interface_ will be NULL. Some tests do not require it. + testing_interface_ = GetTestingInterface(); } TestCase::~TestCase() { @@ -50,6 +54,20 @@ pp::VarPrivate TestCase::GetTestObject() { } #endif +bool TestCase::CheckTestingInterface() { + testing_interface_ = GetTestingInterface(); + if (!testing_interface_) { + // Give a more helpful error message for the testing interface being gone + // since that needs special enabling in Chrome. + instance_->AppendError("This test needs the testing interface, which is " + "not currently available. In Chrome, use " + "--enable-pepper-testing when launching."); + return false; + } + + return true; +} + void TestCase::HandleMessage(const pp::Var& message_data) { } @@ -66,20 +84,6 @@ pp::deprecated::ScriptableObject* TestCase::CreateTestObject() { } #endif -bool TestCase::InitTestingInterface() { - testing_interface_ = GetTestingInterface(); - if (!testing_interface_) { - // Give a more helpful error message for the testing interface being gone - // since that needs special enabling in Chrome. - instance_->AppendError("This test needs the testing interface, which is " - "not currently available. In Chrome, use " - "--enable-pepper-testing when launching."); - return false; - } - - return true; -} - bool TestCase::EnsureRunningOverHTTP() { if (instance_->protocol() != "http:") { instance_->AppendError("This test needs to be run over HTTP."); @@ -94,3 +98,44 @@ bool TestCase::MatchesFilter(const std::string& test_name, return filter.empty() || (test_name == filter); } +std::string TestCase::CheckResourcesAndVars() { + std::string errors; + if (testing_interface_) { + // TODO(dmichael): Fix tests that leak resources and enable the following: + /* + uint32_t leaked_resources = + testing_interface_->GetLiveObjectsForInstance(instance_->pp_instance()); + if (leaked_resources) { + std::ostringstream output; + output << "FAILED: Test leaked " << leaked_resources << " resources.\n"; + errors += output.str(); + } + */ + const uint32_t kVarsToPrint = 10; + PP_Var vars[kVarsToPrint]; + uint32_t leaked_vars = testing_interface_->GetLiveVars(vars, kVarsToPrint); + uint32_t tracked_vars = leaked_vars; +#if !(defined __native_client__) + // Don't count test_object_ as a leak. + if (test_object_.pp_var().type > PP_VARTYPE_DOUBLE) + --leaked_vars; +#endif + if (leaked_vars) { + std::ostringstream output; + output << "Test leaked " << leaked_vars << " vars (printing at most " + << kVarsToPrint <<"):<p>"; + errors += output.str(); + for (uint32_t i = 0; i < std::min(tracked_vars, kVarsToPrint); ++i) { + pp::Var leaked_var(pp::Var::PassRef(), vars[i]); +#if (defined __native_client__) + errors += leaked_var.DebugString() + "<p>"; +#else + if (!(leaked_var == test_object_)) + errors += leaked_var.DebugString() + "<p>"; +#endif + } + } + } + return errors; +} + diff --git a/ppapi/tests/test_case.h b/ppapi/tests/test_case.h index 8ea3aef..75cafda 100644 --- a/ppapi/tests/test_case.h +++ b/ppapi/tests/test_case.h @@ -80,8 +80,10 @@ class TestCase { virtual pp::deprecated::ScriptableObject* CreateTestObject(); #endif - // Initializes the testing interface. - bool InitTestingInterface(); + // Checks whether the testing interface is available. Returns true if it is, + // false otherwise. If it is not available, adds a descriptive error. This is + // for use by tests that require the testing interface. + bool CheckTestingInterface(); // Makes sure the test is run over HTTP. bool EnsureRunningOverHTTP(); @@ -90,6 +92,11 @@ class TestCase { // (a) filter is empty or (b) test_name and filter match exactly. bool MatchesFilter(const std::string& test_name, const std::string& filter); + // Check for leaked resources and vars at the end of the test. If any exist, + // return a string with some information about the error. Otherwise, return + // an empty string. + std::string CheckResourcesAndVars(); + // Pointer to the instance that owns us. TestingInstance* instance_; @@ -150,7 +157,10 @@ class TestCaseFactory { #define RUN_TEST(name, test_filter) \ if (MatchesFilter(#name, test_filter)) { \ force_async_ = false; \ - instance_->LogTest(#name, Test##name()); \ + std::string error_message = Test##name(); \ + if (error_message.empty()) \ + error_message = CheckResourcesAndVars(); \ + instance_->LogTest(#name, error_message); \ } #define RUN_TEST_WITH_REFERENCE_CHECK(name, test_filter) \ diff --git a/ppapi/tests/test_directory_reader.cc b/ppapi/tests/test_directory_reader.cc index 3823f29..254a355 100644 --- a/ppapi/tests/test_directory_reader.cc +++ b/ppapi/tests/test_directory_reader.cc @@ -72,7 +72,7 @@ int32_t DeleteDirectoryRecursively(pp::FileRef* dir, } // namespace bool TestDirectoryReader::Init() { - return InitTestingInterface() && EnsureRunningOverHTTP(); + return CheckTestingInterface() && EnsureRunningOverHTTP(); } void TestDirectoryReader::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_file_io.cc b/ppapi/tests/test_file_io.cc index 057fdef..f5235e1 100644 --- a/ppapi/tests/test_file_io.cc +++ b/ppapi/tests/test_file_io.cc @@ -109,7 +109,7 @@ int32_t WriteEntireBuffer(PP_Instance instance, } // namespace bool TestFileIO::Init() { - return InitTestingInterface() && EnsureRunningOverHTTP(); + return CheckTestingInterface() && EnsureRunningOverHTTP(); } void TestFileIO::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_file_ref.cc b/ppapi/tests/test_file_ref.cc index b17450d..0e42d1c 100644 --- a/ppapi/tests/test_file_ref.cc +++ b/ppapi/tests/test_file_ref.cc @@ -41,7 +41,7 @@ std::string ReportMismatch(const std::string& method_name, } // namespace bool TestFileRef::Init() { - return InitTestingInterface() && EnsureRunningOverHTTP(); + return CheckTestingInterface() && EnsureRunningOverHTTP(); } void TestFileRef::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_file_system.cc b/ppapi/tests/test_file_system.cc index 2b5a0c5..8c05d42 100644 --- a/ppapi/tests/test_file_system.cc +++ b/ppapi/tests/test_file_system.cc @@ -14,7 +14,7 @@ REGISTER_TEST_CASE(FileSystem); bool TestFileSystem::Init() { - return InitTestingInterface() && EnsureRunningOverHTTP(); + return CheckTestingInterface() && EnsureRunningOverHTTP(); } void TestFileSystem::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_flash_fullscreen.cc b/ppapi/tests/test_flash_fullscreen.cc index f7f122b..0d49605 100644 --- a/ppapi/tests/test_flash_fullscreen.cc +++ b/ppapi/tests/test_flash_fullscreen.cc @@ -46,7 +46,7 @@ TestFlashFullscreen::TestFlashFullscreen(TestingInstance* instance) } bool TestFlashFullscreen::Init() { - return InitTestingInterface(); + return CheckTestingInterface(); } void TestFlashFullscreen::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_fullscreen.cc b/ppapi/tests/test_fullscreen.cc index c531c02..f2b204e 100644 --- a/ppapi/tests/test_fullscreen.cc +++ b/ppapi/tests/test_fullscreen.cc @@ -71,7 +71,7 @@ bool TestFullscreen::Init() { instance_->AppendError("Failed to initialize graphics2d_"); return false; } - return InitTestingInterface(); + return CheckTestingInterface(); } void TestFullscreen::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_graphics_2d.cc b/ppapi/tests/test_graphics_2d.cc index 63cfc42..86de406 100644 --- a/ppapi/tests/test_graphics_2d.cc +++ b/ppapi/tests/test_graphics_2d.cc @@ -38,7 +38,7 @@ bool TestGraphics2D::Init() { image_data_interface_ = static_cast<const PPB_ImageData*>( pp::Module::Get()->GetBrowserInterface(PPB_IMAGEDATA_INTERFACE)); return graphics_2d_interface_ && image_data_interface_ && - InitTestingInterface(); + CheckTestingInterface(); } void TestGraphics2D::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_graphics_3d.cc b/ppapi/tests/test_graphics_3d.cc index 75b4d68..aa26dff 100644 --- a/ppapi/tests/test_graphics_3d.cc +++ b/ppapi/tests/test_graphics_3d.cc @@ -18,7 +18,7 @@ REGISTER_TEST_CASE(Graphics3D); bool TestGraphics3D::Init() { opengl_es2_ = static_cast<const PPB_OpenGLES2*>( pp::Module::Get()->GetBrowserInterface(PPB_OPENGLES2_INTERFACE)); - return opengl_es2_ && InitTestingInterface(); + return opengl_es2_ && CheckTestingInterface(); } void TestGraphics3D::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_input_event.cc b/ppapi/tests/test_input_event.cc index cdd4939..8ac9a8fd 100644 --- a/ppapi/tests/test_input_event.cc +++ b/ppapi/tests/test_input_event.cc @@ -73,7 +73,7 @@ bool TestInputEvent::Init() { mouse_input_event_interface_ && wheel_input_event_interface_ && keyboard_input_event_interface_ && - InitTestingInterface(); + CheckTestingInterface(); // Set up a listener for our message that signals that all input events have // been received. diff --git a/ppapi/tests/test_memory.cc b/ppapi/tests/test_memory.cc index 4acbd5f..ea612a4 100644 --- a/ppapi/tests/test_memory.cc +++ b/ppapi/tests/test_memory.cc @@ -21,7 +21,7 @@ REGISTER_TEST_CASE(Memory); bool TestMemory::Init() { memory_dev_interface_ = static_cast<const PPB_Memory_Dev*>( pp::Module::Get()->GetBrowserInterface(PPB_MEMORY_DEV_INTERFACE)); - return memory_dev_interface_ && InitTestingInterface(); + return memory_dev_interface_ && CheckTestingInterface(); } void TestMemory::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc index 665dad7..6edd422 100644 --- a/ppapi/tests/test_post_message.cc +++ b/ppapi/tests/test_post_message.cc @@ -69,7 +69,7 @@ TestPostMessage::~TestPostMessage() { } bool TestPostMessage::Init() { - bool success = InitTestingInterface(); + bool success = CheckTestingInterface(); // Set up a special listener that only responds to a FINISHED_WAITING string. // This is for use by WaitForMessages. @@ -179,6 +179,7 @@ std::string TestPostMessage::TestSendInInit() { ASSERT_EQ(message_data_.size(), 1); ASSERT_TRUE(message_data_.back().is_string()); ASSERT_EQ(message_data_.back().AsString(), kTestString); + message_data_.clear(); PASS(); } @@ -236,6 +237,7 @@ std::string TestPostMessage::TestSendingData() { ASSERT_EQ(WaitForMessages(), 1); ASSERT_TRUE(message_data_.back().is_null()); + message_data_.clear(); ASSERT_TRUE(ClearListeners()); PASS(); @@ -296,6 +298,7 @@ std::string TestPostMessage::TestSendingArrayBuffer() { for (size_t i = 0; i < test_data.ByteLength(); ++i) ASSERT_EQ(buff[i], received_buff[i]); + message_data_.clear(); ASSERT_TRUE(ClearListeners()); PASS(); @@ -361,6 +364,9 @@ std::string TestPostMessage::TestMessageEvent() { ASSERT_DOUBLE_EQ(double_vec[1], 2.0); ASSERT_DOUBLE_EQ(double_vec[2], 3.0); + message_data_.clear(); + ASSERT_TRUE(ClearListeners()); + PASS(); } @@ -392,6 +398,8 @@ std::string TestPostMessage::TestExtraParam() { ASSERT_EQ(WaitForMessages(), 0); ASSERT_TRUE(message_data_.empty()); + ASSERT_TRUE(ClearListeners()); + PASS(); } @@ -448,6 +456,9 @@ std::string TestPostMessage::TestNonMainThread() { } ASSERT_EQ(received_counts, expected_counts); + message_data_.clear(); + ASSERT_TRUE(ClearListeners()); + PASS(); } diff --git a/ppapi/tests/test_scrollbar.cc b/ppapi/tests/test_scrollbar.cc index 61345d0..b005db7 100644 --- a/ppapi/tests/test_scrollbar.cc +++ b/ppapi/tests/test_scrollbar.cc @@ -23,7 +23,7 @@ TestScrollbar::TestScrollbar(TestingInstance* instance) } bool TestScrollbar::Init() { - return InitTestingInterface(); + return CheckTestingInterface(); } void TestScrollbar::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_tcp_socket_private_shared.cc b/ppapi/tests/test_tcp_socket_private_shared.cc index 013aa89..6df6cd5 100644 --- a/ppapi/tests/test_tcp_socket_private_shared.cc +++ b/ppapi/tests/test_tcp_socket_private_shared.cc @@ -31,7 +31,7 @@ bool TestTCPSocketPrivateShared::Init() { return tcp_socket_private_interface_ && init_host_port && - InitTestingInterface(); + CheckTestingInterface(); } void TestTCPSocketPrivateShared::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_transport.cc b/ppapi/tests/test_transport.cc index c5ea69c..52d072e 100644 --- a/ppapi/tests/test_transport.cc +++ b/ppapi/tests/test_transport.cc @@ -105,7 +105,7 @@ TestTransport::~TestTransport() { bool TestTransport::Init() { transport_interface_ = static_cast<const PPB_Transport_Dev*>( pp::Module::Get()->GetBrowserInterface(PPB_TRANSPORT_DEV_INTERFACE)); - return transport_interface_ && InitTestingInterface(); + return transport_interface_ && CheckTestingInterface(); } void TestTransport::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_udp_socket_private_shared.cc b/ppapi/tests/test_udp_socket_private_shared.cc index da97cae..2de64778 100644 --- a/ppapi/tests/test_udp_socket_private_shared.cc +++ b/ppapi/tests/test_udp_socket_private_shared.cc @@ -38,7 +38,7 @@ bool TestUDPSocketPrivateShared::Init() { return tcp_socket_private_interface_ && udp_socket_private_interface_ && init_host_port && - InitTestingInterface(); + CheckTestingInterface(); } void TestUDPSocketPrivateShared::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_url_loader.cc b/ppapi/tests/test_url_loader.cc index 630d00f..741d415 100644 --- a/ppapi/tests/test_url_loader.cc +++ b/ppapi/tests/test_url_loader.cc @@ -63,7 +63,7 @@ TestURLLoader::TestURLLoader(TestingInstance* instance) } bool TestURLLoader::Init() { - if (!InitTestingInterface()) { + if (!CheckTestingInterface()) { instance_->AppendError("Testing interface not available"); return false; } diff --git a/ppapi/tests/test_var.cc b/ppapi/tests/test_var.cc index 27c4882..0fedb13 100644 --- a/ppapi/tests/test_var.cc +++ b/ppapi/tests/test_var.cc @@ -27,7 +27,7 @@ REGISTER_TEST_CASE(Var); bool TestVar::Init() { var_interface_ = static_cast<const PPB_Var*>( pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); - return var_interface_ && InitTestingInterface(); + return var_interface_ && CheckTestingInterface(); } void TestVar::RunTests(const std::string& filter) { @@ -136,6 +136,7 @@ std::string TestVar::TestNullInputInUtf8Conversion() { if (result == NULL) { return "Expected a non-null result for 0-lengthed string from VarToUtf8."; } + var_interface_->Release(converted_string); // Should not crash, and make an empty string. const char* null_string = NULL; diff --git a/ppapi/tests/test_var_deprecated.cc b/ppapi/tests/test_var_deprecated.cc index 00585e6..23633ac 100644 --- a/ppapi/tests/test_var_deprecated.cc +++ b/ppapi/tests/test_var_deprecated.cc @@ -69,7 +69,7 @@ REGISTER_TEST_CASE(VarDeprecated); bool TestVarDeprecated::Init() { var_interface_ = static_cast<const PPB_Var_Deprecated*>( pp::Module::Get()->GetBrowserInterface(PPB_VAR_DEPRECATED_INTERFACE)); - return var_interface_ && InitTestingInterface(); + return var_interface_ && CheckTestingInterface(); } void TestVarDeprecated::RunTests(const std::string& filter) { @@ -179,6 +179,7 @@ std::string TestVarDeprecated::TestNullInputInUtf8Conversion() { if (result == NULL) { return "Expected a non-null result for 0-lengthed string from VarToUtf8."; } + var_interface_->Release(converted_string); // Should not crash, and make an empty string. const char* null_string = NULL; @@ -386,6 +387,10 @@ std::string TestVarDeprecated::TestPassReference() { ASSERT_TRUE(result.is_string()); ASSERT_TRUE(result.AsString() == "worksnice"); + // Reset var_from_page_ so it doesn't seem like a leak to the var leak + // checking code. + var_from_page_ = pp::Var(); + PASS(); } diff --git a/ppapi/tests/test_video_decoder.cc b/ppapi/tests/test_video_decoder.cc index eed14d8..0cee794 100644 --- a/ppapi/tests/test_video_decoder.cc +++ b/ppapi/tests/test_video_decoder.cc @@ -15,7 +15,7 @@ REGISTER_TEST_CASE(VideoDecoder); bool TestVideoDecoder::Init() { video_decoder_interface_ = static_cast<const PPB_VideoDecoder_Dev*>( pp::Module::Get()->GetBrowserInterface(PPB_VIDEODECODER_DEV_INTERFACE)); - return video_decoder_interface_ && InitTestingInterface(); + return video_decoder_interface_ && CheckTestingInterface(); } void TestVideoDecoder::RunTests(const std::string& filter) { diff --git a/ppapi/tests/test_websocket.cc b/ppapi/tests/test_websocket.cc index ae1db54..223331e 100644 --- a/ppapi/tests/test_websocket.cc +++ b/ppapi/tests/test_websocket.cc @@ -53,7 +53,7 @@ bool TestWebSocket::Init() { if (!websocket_interface_ || !var_interface_ || !core_interface_) return false; - return InitTestingInterface(); + return CheckTestingInterface(); } void TestWebSocket::RunTests(const std::string& filter) { diff --git a/webkit/plugins/ppapi/message_channel.cc b/webkit/plugins/ppapi/message_channel.cc index a6fafae..7eef69e 100644 --- a/webkit/plugins/ppapi/message_channel.cc +++ b/webkit/plugins/ppapi/message_channel.cc @@ -184,6 +184,7 @@ bool MessageChannelInvoke(NPObject* np_obj, NPIdentifier name, MessageChannel& message_channel(ToMessageChannel(np_obj)); PP_Var argument(NPVariantToPPVar(message_channel.instance(), &args[0])); message_channel.PostMessageToNative(argument); + PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(argument); return true; } // Other method calls we will pass to the passthrough object, if we have one. diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc index 3cb4c482..9934666 100644 --- a/webkit/plugins/ppapi/plugin_module.cc +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -247,6 +247,16 @@ PP_Var GetDocumentURL(PP_Instance instance, PP_URLComponents_Dev* components) { return plugin_instance->GetDocumentURL(instance, components); } +uint32_t GetLiveVars(PP_Var live_vars[], uint32_t array_size) { + std::vector<PP_Var> vars = + PpapiGlobals::Get()->GetVarTracker()->GetLiveVars(); + for (size_t i = 0u; + i < std::min(static_cast<size_t>(array_size), vars.size()); + ++i) + live_vars[i] = vars[i]; + return vars.size(); +} + const PPB_Testing_Dev testing_interface = { &ReadImageData, &RunMessageLoop, @@ -254,7 +264,8 @@ const PPB_Testing_Dev testing_interface = { &GetLiveObjectsForInstance, &IsOutOfProcess, &SimulateInputEvent, - &GetDocumentURL + &GetDocumentURL, + &GetLiveVars }; // GetInterface ---------------------------------------------------------------- @@ -351,8 +362,7 @@ const void* GetInterface(const char* name) { if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnablePepperTesting)) { if (strcmp(name, PPB_TESTING_DEV_INTERFACE) == 0 || - strcmp(name, PPB_TESTING_DEV_INTERFACE_0_7) == 0 || - strcmp(name, PPB_TESTING_DEV_INTERFACE_0_8) == 0) { + strcmp(name, PPB_TESTING_DEV_INTERFACE_0_9) == 0) { return &testing_interface; } } |