Fix resource destruction in proxy

This ensures that the resource on the plugin side is destroyed before we send
the message to the host, so that it has a chance to do proper cleanup.

Also, fix Surface3D destruction that could cause a write-after-free.

BUG=none
TEST=go to youtube with out-of-process pepper flash. click on fullscreen.
observe no hang, no crash

Review URL: http://codereview.chromium.org/6771042

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80188 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ppapi/proxy/plugin_resource_tracker.cc b/ppapi/proxy/plugin_resource_tracker.cc
index 0c4bdfb..2e9e32a 100644
--- a/ppapi/proxy/plugin_resource_tracker.cc
+++ b/ppapi/proxy/plugin_resource_tracker.cc
@@ -120,24 +120,25 @@
     return;
   found->second.ref_count--;
   if (found->second.ref_count == 0) {
-    PluginResource* plugin_resource = found->second.resource.get();
-    if (notify_browser_on_release)
-      SendReleaseResourceToHost(resource, plugin_resource);
-    host_resource_map_.erase(plugin_resource->host_resource());
+    // Keep a reference while removing in case the destructor ends up
+    // re-entering. That way, when the destructor is called, it's out of the
+    // maps.
+    linked_ptr<PluginResource> plugin_resource = found->second.resource;
+    PluginDispatcher* dispatcher =
+        PluginDispatcher::GetForInstance(plugin_resource->instance());
+    HostResource host_resource = plugin_resource->host_resource();
+    host_resource_map_.erase(host_resource);
     resource_map_.erase(found);
-  }
-}
+    plugin_resource.reset();
 
-void PluginResourceTracker::SendReleaseResourceToHost(
-    PP_Resource resource_id,
-    PluginResource* resource) {
-  PluginDispatcher* dispatcher =
-      PluginDispatcher::GetForInstance(resource->instance());
-  if (dispatcher) {
-    dispatcher->Send(new PpapiHostMsg_PPBCore_ReleaseResource(
-        INTERFACE_ID_PPB_CORE, resource->host_resource()));
-  } else {
-    NOTREACHED();
+    if (notify_browser_on_release) {
+      if (dispatcher) {
+        dispatcher->Send(new PpapiHostMsg_PPBCore_ReleaseResource(
+            INTERFACE_ID_PPB_CORE, host_resource));
+      } else {
+        NOTREACHED();
+      }
+    }
   }
 }