2009-02-06 Anders Carlsson <andersca@apple.com>
authorandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Feb 2009 22:42:13 +0000 (22:42 +0000)
committerandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Feb 2009 22:42:13 +0000 (22:42 +0000)
        Reviewed by Sam Weinig.

        <rdar://problem/6562220>
        CrashTracer: [USER] 21 crashes in Safari at com.apple.WebKit • WebKit::NetscapePluginHostProxy::port

        Make the handling of crashes in the plug-in host more robust.

        * Plugins/Hosted/NetscapePluginHostProxy.h:
        Add m_portSet.

        * Plugins/Hosted/NetscapePluginHostProxy.mm:
        (WebKit::NetscapePluginHostProxy::NetscapePluginHostProxy):
        Initialize m_portSet.

        (WebKit::NetscapePluginHostProxy::~NetscapePluginHostProxy):
        Free m_portSet.

        (WebKit::NetscapePluginHostProxy::processRequests):
        Listen for messages on the port set. If we get a message to the port death notification port,
        then call pluginHostDied. Otherwise, process the message.

        * Plugins/Hosted/NetscapePluginInstanceProxy.h:
        * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
        (WebKit::NetscapePluginInstanceProxy::cleanup):
        Factor code that should be shared between destroy() and pluginHostDied() into cleanup.

        (WebKit::NetscapePluginInstanceProxy::destroy):
        Call cleanup().

        (WebKit::NetscapePluginInstanceProxy::pluginHostDied):
        Call cleanup().

        (WebKit::NetscapePluginInstanceProxy::processRequestsAndWaitForReply):
        Call NetscapePluginHostProxy::processRequests.

        * Plugins/Hosted/ProxyInstance.mm:
        (WebKit::ProxyInstance::invalidate):
        Add a null check for the host proxy.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@40733 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKit/mac/ChangeLog
WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.h
WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm
WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h
WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm
WebKit/mac/Plugins/Hosted/ProxyInstance.mm

index 7f4d89127e59b0f070e07eede7ec3b530c69ba90..6b8ffb3f4789ccd34ad9c3f3dae3dda9878ce90f 100644 (file)
@@ -1,3 +1,44 @@
+2009-02-06  Anders Carlsson  <andersca@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/6562220> 
+        CrashTracer: [USER] 21 crashes in Safari at com.apple.WebKit • WebKit::NetscapePluginHostProxy::port
+        
+        Make the handling of crashes in the plug-in host more robust.
+        
+        * Plugins/Hosted/NetscapePluginHostProxy.h:
+        Add m_portSet.
+        
+        * Plugins/Hosted/NetscapePluginHostProxy.mm:
+        (WebKit::NetscapePluginHostProxy::NetscapePluginHostProxy):
+        Initialize m_portSet.
+        
+        (WebKit::NetscapePluginHostProxy::~NetscapePluginHostProxy):
+        Free m_portSet.
+        
+        (WebKit::NetscapePluginHostProxy::processRequests):
+        Listen for messages on the port set. If we get a message to the port death notification port,
+        then call pluginHostDied. Otherwise, process the message.
+        
+        * Plugins/Hosted/NetscapePluginInstanceProxy.h:
+        * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
+        (WebKit::NetscapePluginInstanceProxy::cleanup):
+        Factor code that should be shared between destroy() and pluginHostDied() into cleanup.
+        
+        (WebKit::NetscapePluginInstanceProxy::destroy):
+        Call cleanup().
+        
+        (WebKit::NetscapePluginInstanceProxy::pluginHostDied):
+        Call cleanup().
+        
+        (WebKit::NetscapePluginInstanceProxy::processRequestsAndWaitForReply):
+        Call NetscapePluginHostProxy::processRequests.
+        
+        * Plugins/Hosted/ProxyInstance.mm:
+        (WebKit::ProxyInstance::invalidate):
+        Add a null check for the host proxy.
+
 2009-02-06  Dan Bernstein  <mitz@apple.com>
 
         - try to fix the Tiger build
index 8c552ccbf50faa78bd91a49bf7e4d93338a345d6..4676f475188f4dd5b0c6c3d333b6aa6a3d9cca06 100644 (file)
@@ -54,6 +54,8 @@ public:
 
     void applicationDidBecomeActive();
     
+    bool processRequests();
+    
 private:
     ~NetscapePluginHostProxy();
     void pluginHostDied();
@@ -67,6 +69,8 @@ private:
     PluginInstanceMap m_instances;
     
     mach_port_t m_clientPort;
+    mach_port_t m_portSet;
+    
 #ifdef USE_LIBDISPATCH
     dispatch_source_t m_clientPortSource;
 #else
index fa81a977cd2d17799a38447f2ad58cdd23879598..07d4208f22c698870f5c79a148d186914b27148e 100644 (file)
@@ -61,6 +61,7 @@ static PluginProxyMap& pluginProxyMap()
 
 NetscapePluginHostProxy::NetscapePluginHostProxy(mach_port_t clientPort, mach_port_t pluginHostPort, const ProcessSerialNumber& pluginHostPSN)
     : m_clientPort(clientPort)
+    , m_portSet(MACH_PORT_NULL)
     , m_pluginHostPort(pluginHostPort)
     , m_isModal(false)
     , m_menuBarIsVisible(true)
@@ -94,6 +95,13 @@ NetscapePluginHostProxy::NetscapePluginHostProxy(mach_port_t clientPort, mach_po
 NetscapePluginHostProxy::~NetscapePluginHostProxy()
 {
     pluginProxyMap().remove(m_clientPort);
+
+    // Free the port set
+    if (m_portSet) {
+        mach_port_extract_member(mach_task_self(), m_clientPort, m_portSet);
+        mach_port_extract_member(mach_task_self(), CFMachPortGetPort(m_deadNameNotificationPort.get()), m_portSet);
+        mach_port_destroy(mach_task_self(), m_portSet);
+    }
     
     ASSERT(m_clientPortSource);
 #ifdef USE_LIBDISPATCH
@@ -220,6 +228,51 @@ void NetscapePluginHostProxy::setModal(bool modal)
         endModal();
 }
     
+bool NetscapePluginHostProxy::processRequests()
+{
+    if (!m_portSet) {
+        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &m_portSet);
+        mach_port_insert_member(mach_task_self(), m_clientPort, m_portSet);
+        mach_port_insert_member(mach_task_self(), CFMachPortGetPort(m_deadNameNotificationPort.get()), m_portSet);
+    }
+    
+    char buffer[4096];
+    
+    mach_msg_header_t* msg = reinterpret_cast<mach_msg_header_t*>(buffer);
+    
+    kern_return_t kr = mach_msg(msg, MACH_RCV_MSG, 0, sizeof(buffer), m_portSet, 0, MACH_PORT_NULL);
+    
+    if (kr != KERN_SUCCESS) {
+        LOG_ERROR("Could not receive mach message, error %x", kr);
+        return false;
+    }
+    
+    if (msg->msgh_local_port == m_clientPort) {
+        __ReplyUnion__WKWebKitPluginClient_subsystem reply;
+        mach_msg_header_t* replyHeader = reinterpret_cast<mach_msg_header_t*>(&reply);
+        
+        if (WebKitPluginClient_server(msg, replyHeader) && replyHeader->msgh_remote_port != MACH_PORT_NULL) {
+            kr = mach_msg(replyHeader, MACH_SEND_MSG, replyHeader->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
+            
+            if (kr != KERN_SUCCESS) {
+                LOG_ERROR("Could not send mach message, error %x", kr);
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    if (msg->msgh_local_port == CFMachPortGetPort(m_deadNameNotificationPort.get())) {
+        ASSERT(msg->msgh_id == MACH_NOTIFY_DEAD_NAME);
+        pluginHostDied();
+        return false;
+    }
+    
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
 } // namespace WebKit
 
 using namespace WebKit;
index 2489522c0894219224ea88b24f9878748d8af28a..d81264243259092dc0af2a113a8854a658812e19 100644 (file)
@@ -222,6 +222,8 @@ private:
     void stopAllStreams();
     void processRequestsAndWaitForReply();
     
+    void cleanup();
+    
     NetscapePluginHostProxy* m_pluginHostProxy;
     WebHostedNetscapePluginView *m_pluginView;
 
index fae3ca1f4bda4cb5c3d39e8e383201c71cea83a2..b93746abf2460b4e8d2e40140c7df550f398cf3f 100644 (file)
@@ -126,16 +126,14 @@ void NetscapePluginInstanceProxy::stopAllStreams()
         streamsCopy[i]->stop();
 }
 
-void NetscapePluginInstanceProxy::destroy()
+void NetscapePluginInstanceProxy::cleanup()
 {
     stopAllStreams();
     
-    _WKPHDestroyPluginInstance(m_pluginHostProxy->port(), m_pluginID);
-    
     // Clear the object map, this will cause any outstanding JS objects that the plug-in had a reference to 
     // to go away when the next garbage collection takes place.
     m_objects.clear();
-
+    
     if (Frame* frame = core([m_pluginView webFrame]))
         frame->script()->cleanupScriptObjectsForPlugin(m_pluginView);
     
@@ -146,7 +144,14 @@ void NetscapePluginInstanceProxy::destroy()
     ProxyInstanceSet::const_iterator end = instances.end();
     for (ProxyInstanceSet::const_iterator it = instances.begin(); it != end; ++it)
         (*it)->invalidate();
-    
+}
+
+void NetscapePluginInstanceProxy::destroy()
+{
+    _WKPHDestroyPluginInstance(m_pluginHostProxy->port(), m_pluginID);
+
+    cleanup();
+
     m_pluginHostProxy->removePluginInstance(this);
     m_pluginHostProxy = 0;
 }
@@ -163,9 +168,9 @@ void NetscapePluginInstanceProxy::disconnectStream(HostedNetscapePluginStream* s
     
 void NetscapePluginInstanceProxy::pluginHostDied()
 {
-    stopAllStreams();
-
     m_pluginHostProxy = 0;
+
+    cleanup();
     
     [m_pluginView pluginHostDied];
     m_pluginView = nil;
@@ -467,8 +472,7 @@ NPError NetscapePluginInstanceProxy::loadRequest(NSURLRequest *request, const ch
 void NetscapePluginInstanceProxy::processRequestsAndWaitForReply()
 {
     while (!m_currentReply.get()) {
-        kern_return_t kr = mach_msg_server_once(WebKitPluginClient_server, WKWebKitPluginClient_subsystem.maxsize + MAX_TRAILER_SIZE, m_pluginHostProxy->clientPort(), 0);
-        if (kr != KERN_SUCCESS) {
+        if (!m_pluginHostProxy->processRequests()) {
             m_currentReply.reset();
             break;
         }
index 03904090f213b5bcb26c09e24f1ee3f29c630b03..20e415b9b4bbb263694b1311418e007a38b2de16 100644 (file)
@@ -311,8 +311,9 @@ void ProxyInstance::setFieldValue(ExecState* exec, const Field* field, JSValuePt
 
 void ProxyInstance::invalidate()
 {
-    _WKPHNPObjectRelease(m_instanceProxy->hostProxy()->port(),
-                         m_instanceProxy->pluginID(), m_objectID);
+    if (NetscapePluginHostProxy* hostProxy = m_instanceProxy->hostProxy())
+        _WKPHNPObjectRelease(hostProxy->port(),
+                             m_instanceProxy->pluginID(), m_objectID);
     m_instanceProxy = 0;
 }