[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

andersca at apple.com andersca at apple.com
Wed Dec 22 11:39:02 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit acc1eeb1f0f926e851a0d5b131417c51cf94eccb
Author: andersca at apple.com <andersca at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Aug 2 20:02:43 2010 +0000

    Protect the plug-in from being destroyed while in plug-in code
    https://bugs.webkit.org/show_bug.cgi?id=43370
    
    Reviewed by Sam Weinig.
    
    Add a PluginProtector to NPRuntimeObjectMap and use it in JSNPObject.
    
    * WebProcess/Plugins/JSNPObject.cpp:
    (WebKit::JSNPObject::callMethod):
    (WebKit::JSNPObject::callObject):
    (WebKit::JSNPObject::callConstructor):
    (WebKit::JSNPObject::put):
    (WebKit::JSNPObject::getOwnPropertyNames):
    (WebKit::JSNPObject::propertyGetter):
    Add PluginProtector declarations.
    
    * WebProcess/Plugins/NPRuntimeObjectMap.cpp:
    (WebKit::NPRuntimeObjectMap::PluginProtector::PluginProtector):
    Ref the plug-in view (unless it's being destroyed).
    
    (WebKit::NPRuntimeObjectMap::PluginProtector::~PluginProtector):
    * WebProcess/Plugins/NPRuntimeObjectMap.h:
    
    * WebProcess/Plugins/PluginView.cpp:
    (WebKit::PluginView::PluginView):
    Initialize m_isBeingDestroyed.
    
    (WebKit::PluginView::~PluginView):
    Set m_isBeingDestroyed to true.
    
    (WebKit::PluginView::scriptObject):
    Don't crash if the plug-in failed to initialize.
    
    (WebKit::PluginView::evaluate):
    Remove comment.
    
    * WebProcess/Plugins/PluginView.h:
    (WebKit::PluginView::isBeingDestroyed):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@64487 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebKit2/ChangeLog b/WebKit2/ChangeLog
index 35a3392..81836cc 100644
--- a/WebKit2/ChangeLog
+++ b/WebKit2/ChangeLog
@@ -62,6 +62,47 @@
 
         Reviewed by Sam Weinig.
 
+        Protect the plug-in from being destroyed while in plug-in code
+        https://bugs.webkit.org/show_bug.cgi?id=43370
+
+        Add a PluginProtector to NPRuntimeObjectMap and use it in JSNPObject.
+        
+        * WebProcess/Plugins/JSNPObject.cpp:
+        (WebKit::JSNPObject::callMethod):
+        (WebKit::JSNPObject::callObject):
+        (WebKit::JSNPObject::callConstructor):
+        (WebKit::JSNPObject::put):
+        (WebKit::JSNPObject::getOwnPropertyNames):
+        (WebKit::JSNPObject::propertyGetter):
+        Add PluginProtector declarations.
+
+        * WebProcess/Plugins/NPRuntimeObjectMap.cpp:
+        (WebKit::NPRuntimeObjectMap::PluginProtector::PluginProtector):
+        Ref the plug-in view (unless it's being destroyed).
+
+        (WebKit::NPRuntimeObjectMap::PluginProtector::~PluginProtector):
+        * WebProcess/Plugins/NPRuntimeObjectMap.h:
+
+        * WebProcess/Plugins/PluginView.cpp:
+        (WebKit::PluginView::PluginView):
+        Initialize m_isBeingDestroyed.
+
+        (WebKit::PluginView::~PluginView):
+        Set m_isBeingDestroyed to true.
+
+        (WebKit::PluginView::scriptObject):
+        Don't crash if the plug-in failed to initialize.
+
+        (WebKit::PluginView::evaluate):
+        Remove comment.
+
+        * WebProcess/Plugins/PluginView.h:
+        (WebKit::PluginView::isBeingDestroyed):
+
+2010-08-02  Anders Carlsson  <andersca at apple.com>
+
+        Reviewed by Sam Weinig.
+
         Cache JSNPObjects and fix bugs in the object map
         https://bugs.webkit.org/show_bug.cgi?id=43368
 
diff --git a/WebKit2/WebProcess/Plugins/JSNPObject.cpp b/WebKit2/WebProcess/Plugins/JSNPObject.cpp
index e13e920..bd89b2e 100644
--- a/WebKit2/WebProcess/Plugins/JSNPObject.cpp
+++ b/WebKit2/WebProcess/Plugins/JSNPObject.cpp
@@ -88,6 +88,11 @@ JSValue JSNPObject::callMethod(ExecState* exec, NPIdentifier methodName)
     for (size_t i = 0; i < argumentCount; ++i)
         m_objectMap->convertJSValueToNPVariant(exec, exec->argument(i), arguments[i]);
 
+    // Calling NPClass::invoke will call into plug-in code, and there's no telling what the plug-in can do.
+    // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until 
+    // the call has finished.
+    NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+
     bool returnValue;
     NPVariant result;
     VOID_TO_NPVARIANT(result);
@@ -95,9 +100,7 @@ JSValue JSNPObject::callMethod(ExecState* exec, NPIdentifier methodName)
     {
         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
         returnValue = m_npObject->_class->invoke(m_npObject, methodName, arguments.data(), argumentCount, &result);
-
-        // FIXME: Handle invoke setting an exception.
-        // FIXME: Find out what happens if calling invoke causes the plug-in to go away.
+        NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
     }
 
     // Release all arguments;
@@ -123,6 +126,11 @@ JSC::JSValue JSNPObject::callObject(JSC::ExecState* exec)
     // Convert all arguments to NPVariants.
     for (size_t i = 0; i < argumentCount; ++i)
         m_objectMap->convertJSValueToNPVariant(exec, exec->argument(i), arguments[i]);
+
+    // Calling NPClass::invokeDefault will call into plug-in code, and there's no telling what the plug-in can do.
+    // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until 
+    // the call has finished.
+    NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
     
     bool returnValue;
     NPVariant result;
@@ -131,9 +139,7 @@ JSC::JSValue JSNPObject::callObject(JSC::ExecState* exec)
     {
         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
         returnValue = m_npObject->_class->invokeDefault(m_npObject, arguments.data(), argumentCount, &result);
-        
-        // FIXME: Handle invokeDefault setting an exception.
-        // FIXME: Find out what happens if calling invokeDefault causes the plug-in to go away.
+        NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
     }
 
     // Release all arguments;
@@ -160,6 +166,11 @@ JSValue JSNPObject::callConstructor(ExecState* exec)
     for (size_t i = 0; i < argumentCount; ++i)
         m_objectMap->convertJSValueToNPVariant(exec, exec->argument(i), arguments[i]);
 
+    // Calling NPClass::construct will call into plug-in code, and there's no telling what the plug-in can do.
+    // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until 
+    // the call has finished.
+    NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+    
     bool returnValue;
     NPVariant result;
     VOID_TO_NPVARIANT(result);
@@ -168,8 +179,6 @@ JSValue JSNPObject::callConstructor(ExecState* exec)
         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
         returnValue = m_npObject->_class->construct(m_npObject, arguments.data(), argumentCount, &result);
         NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
-        
-        // FIXME: Find out what happens if calling construct causes the plug-in to go away.
     }
 
     if (!returnValue)
@@ -285,13 +294,18 @@ void JSNPObject::put(ExecState* exec, const Identifier& propertyName, JSValue va
 
     NPVariant variant;
     m_objectMap->convertJSValueToNPVariant(exec, value, variant);
+
+    // Calling NPClass::setProperty will call into plug-in code, and there's no telling what the plug-in can do.
+    // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until 
+    // the call has finished.
+    NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+
     {
         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
         m_npObject->_class->setProperty(m_npObject, npIdentifier, &variant);
 
         NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
 
-        // FIXME: Find out what happens if calling setProperty causes the plug-in to go away.
         // FIXME: Should we throw an exception if setProperty returns false?
     }
 
@@ -311,10 +325,14 @@ void JSNPObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propert
     NPIdentifier* identifiers = 0;
     uint32_t identifierCount = 0;
     
+    // Calling NPClass::enumerate will call into plug-in code, and there's no telling what the plug-in can do.
+    // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until 
+    // the call has finished.
+    NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+    
     {
         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
 
-        // FIXME: Find out what happens if calling enumerate causes the plug-in to go away.
         // FIXME: Should we throw an exception if enumerate returns false?
         if (!m_npObject->_class->enumerate(m_npObject, &identifiers, &identifierCount))
             return;
@@ -354,6 +372,11 @@ JSValue JSNPObject::propertyGetter(ExecState* exec, JSValue slotBase, const Iden
     NPVariant result;
     VOID_TO_NPVARIANT(result);
 
+    // Calling NPClass::getProperty will call into plug-in code, and there's no telling what the plug-in can do.
+    // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until 
+    // the call has finished.
+    NPRuntimeObjectMap::PluginProtector protector(thisObj->m_objectMap);
+    
     bool returnValue;
     {
         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
@@ -361,8 +384,6 @@ JSValue JSNPObject::propertyGetter(ExecState* exec, JSValue slotBase, const Iden
         returnValue = thisObj->m_npObject->_class->getProperty(thisObj->m_npObject, npIdentifier, &result);
         
         NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
-
-        // FIXME: Find out what happens if calling getProperty causes the plug-in to go away.
     }
 
     if (!returnValue)
diff --git a/WebKit2/WebProcess/Plugins/NPRuntimeObjectMap.cpp b/WebKit2/WebProcess/Plugins/NPRuntimeObjectMap.cpp
index bc61b44..bc09333 100644
--- a/WebKit2/WebProcess/Plugins/NPRuntimeObjectMap.cpp
+++ b/WebKit2/WebProcess/Plugins/NPRuntimeObjectMap.cpp
@@ -46,6 +46,17 @@ NPRuntimeObjectMap::NPRuntimeObjectMap(PluginView* pluginView)
 {
 }
 
+NPRuntimeObjectMap::PluginProtector::PluginProtector(NPRuntimeObjectMap* npRuntimeObjectMap)
+{
+    // If we're already in the plug-in view destructor, we shouldn't try to keep it alive.
+    if (!npRuntimeObjectMap->m_pluginView->isBeingDestroyed())
+        m_pluginView = npRuntimeObjectMap->m_pluginView;
+}
+
+NPRuntimeObjectMap::PluginProtector::~PluginProtector()
+{
+}
+
 NPObject* NPRuntimeObjectMap::getOrCreateNPObject(JSObject* jsObject)
 {
     // If this is a JSNPObject, we can just get its underlying NPObject.
diff --git a/WebKit2/WebProcess/Plugins/NPRuntimeObjectMap.h b/WebKit2/WebProcess/Plugins/NPRuntimeObjectMap.h
index 51bd0c6..2b8e49f 100644
--- a/WebKit2/WebProcess/Plugins/NPRuntimeObjectMap.h
+++ b/WebKit2/WebProcess/Plugins/NPRuntimeObjectMap.h
@@ -53,6 +53,15 @@ class NPRuntimeObjectMap {
 public:
     explicit NPRuntimeObjectMap(PluginView*);
 
+    class PluginProtector {
+    public:
+        explicit PluginProtector(NPRuntimeObjectMap* npRuntimeObjectMap);
+        ~PluginProtector();
+        
+    private:
+        RefPtr<PluginView> m_pluginView;
+    };
+
     // Returns an NPObject that wraps the given JSObject object. If there is already an NPObject that wraps this JSObject, it will
     // retain it and return it.
     NPObject* getOrCreateNPObject(JSC::JSObject*);
diff --git a/WebKit2/WebProcess/Plugins/PluginView.cpp b/WebKit2/WebProcess/Plugins/PluginView.cpp
index d8a72ae..e51e8be 100644
--- a/WebKit2/WebProcess/Plugins/PluginView.cpp
+++ b/WebKit2/WebProcess/Plugins/PluginView.cpp
@@ -217,6 +217,7 @@ PluginView::PluginView(WebCore::HTMLPlugInElement* pluginElement, PassRefPtr<Plu
     , m_parameters(parameters)
     , m_isInitialized(false)
     , m_isWaitingUntilMediaCanStart(false)
+    , m_isBeingDestroyed(false)
     , m_pendingURLRequestsTimer(RunLoop::main(), this, &PluginView::pendingURLRequestsTimerFired)
     , m_npRuntimeObjectMap(this)
 {
@@ -224,6 +225,8 @@ PluginView::PluginView(WebCore::HTMLPlugInElement* pluginElement, PassRefPtr<Plu
 
 PluginView::~PluginView()
 {
+    ASSERT(!m_isBeingDestroyed);
+
     if (m_isWaitingUntilMediaCanStart)
         m_pluginElement->document()->removeMediaCanStartListener(this);
 
@@ -232,8 +235,11 @@ PluginView::~PluginView()
     for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(), end = m_pendingFrameLoads.end(); it != end; ++it)
         it->first->setLoadListener(0);
 
-    if (m_plugin && m_isInitialized)
+    if (m_plugin && m_isInitialized) {
+        m_isBeingDestroyed = true;
         m_plugin->destroy();
+        m_isBeingDestroyed = false;
+    }
 
     // Invalidate the object map.
     m_npRuntimeObjectMap.invalidate();
@@ -284,6 +290,10 @@ void PluginView::initializePlugin()
 
 JSObject* PluginView::scriptObject(JSGlobalObject* globalObject)
 {
+    // The plug-in can be null here if it failed to initialize.
+    if (!m_plugin)
+        return 0;
+    
     NPObject* scriptableNPObject = m_plugin->pluginScriptableNPObject();
     if (!scriptableNPObject)
         return 0;
@@ -644,7 +654,6 @@ bool PluginView::evaluate(NPObject* npObject, const String&scriptString, NPVaria
     bool oldAllowPopups = frame()->script()->allowPopupsFromPlugin();
     frame()->script()->setAllowPopupsFromPlugin(allowPopups);
 
-    // FIXME: What happens if calling evaluate will cause the plug-in view to go away.
     bool returnValue = m_npRuntimeObjectMap.evaluate(npObject, scriptString, result);
 
     frame()->script()->setAllowPopupsFromPlugin(oldAllowPopups);
diff --git a/WebKit2/WebProcess/Plugins/PluginView.h b/WebKit2/WebProcess/Plugins/PluginView.h
index b39f6c2..c0e03f0 100644
--- a/WebKit2/WebProcess/Plugins/PluginView.h
+++ b/WebKit2/WebProcess/Plugins/PluginView.h
@@ -54,6 +54,8 @@ public:
 
     WebCore::Frame* frame();
 
+    bool isBeingDestroyed() const { return m_isBeingDestroyed; }
+
 private:
     PluginView(WebCore::HTMLPlugInElement*, PassRefPtr<Plugin>, const Plugin::Parameters& parameters);
     virtual ~PluginView();
@@ -116,6 +118,7 @@ private:
     
     bool m_isInitialized;
     bool m_isWaitingUntilMediaCanStart;
+    bool m_isBeingDestroyed;
 
     // Pending URLRequests that the plug-in has made.
     Deque<RefPtr<URLRequest> > m_pendingURLRequests;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list