Commit 71878442 authored by jhoneycutt@apple.com's avatar jhoneycutt@apple.com

2008-01-24 Jon Honeycutt <jhoneycutt@apple.com>

        Reviewed by Anders.

        <rdar://problem/5588807> Crash in Flash when destroying plug-in (found
        using yahoo beta mail)

        Flash can dereference NULL in the call to NPP_URLNotify if a request
        made with NPN_PostURLNotify fails before NPP_NewStream is called.

        Work around this by creating a quirk, PluginQuirkFlashURLNotifyBug, and
        checking for this quirk before calling NPP_URLNotify for any request
        made with NPN_PostURLNotify. If the quirk is present, call NPP_NewStream
        and NPP_DestroyStream before calling NPP_URLNotify.

        * WebCore.vcproj/WebCore.vcproj:
        * plugins/PluginQuirkSet.h: Added. Moved quirks out of PluginViewWin so
        PluginViewWin and PluginStream could share it. Created a class,
        PluginQuirkSet, to store plug-in quirks
        (WebCore::):
        (WebCore::PluginQuirkSet::PluginQuirkSet):
        (WebCore::PluginQuirkSet::add):
        (WebCore::PluginQuirkSet::contains):
        * plugins/PluginStream.cpp:
        (WebCore::PluginStream::PluginStream): Copy the PluginQuirkSet for this
        plug-in
        (WebCore::PluginStream::destroyStream): Check for the FlashURLNotifyBug
        quirk
        * plugins/PluginStream.h:
        * plugins/win/PluginViewWin.cpp:
        (WebCore::PluginViewWin::performRequest): Pass the quirks when creating
        the PluginStream
        (WebCore::PluginViewWin::didReceiveResponse): Same
        (WebCore::PluginViewWin::wndProc): Use add / contains instead of
        bit ops
        (WebCore::PluginViewWin::userAgent): Same
        (WebCore::PluginViewWin::invalidateRect): Same
        (WebCore::PluginViewWin::~PluginViewWin): Same
        (WebCore::PluginViewWin::determineQuirks): Same
        (WebCore::PluginViewWin::setParameters): Same
        (WebCore::PluginViewWin::PluginViewWin): Same
        (WebCore::PluginViewWin::init): Same
        (WebCore::PluginViewWin::setCallingPlugin): Same
        * plugins/win/PluginViewWin.h:




git-svn-id: http://svn.webkit.org/repository/webkit/trunk@29778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent b3259243
2008-01-24 Jon Honeycutt <jhoneycutt@apple.com>
Reviewed by Anders.
<rdar://problem/5588807> Crash in Flash when destroying plug-in (found
using yahoo beta mail)
Flash can dereference NULL in the call to NPP_URLNotify if a request
made with NPN_PostURLNotify fails before NPP_NewStream is called.
Work around this by creating a quirk, PluginQuirkFlashURLNotifyBug, and
checking for this quirk before calling NPP_URLNotify for any request
made with NPN_PostURLNotify. If the quirk is present, call NPP_NewStream
and NPP_DestroyStream before calling NPP_URLNotify.
* WebCore.vcproj/WebCore.vcproj:
* plugins/PluginQuirkSet.h: Added. Moved quirks out of PluginViewWin so
PluginViewWin and PluginStream could share it. Created a class,
PluginQuirkSet, to store plug-in quirks
(WebCore::):
(WebCore::PluginQuirkSet::PluginQuirkSet):
(WebCore::PluginQuirkSet::add):
(WebCore::PluginQuirkSet::contains):
* plugins/PluginStream.cpp:
(WebCore::PluginStream::PluginStream): Copy the PluginQuirkSet for this
plug-in
(WebCore::PluginStream::destroyStream): Check for the FlashURLNotifyBug
quirk
* plugins/PluginStream.h:
* plugins/win/PluginViewWin.cpp:
(WebCore::PluginViewWin::performRequest): Pass the quirks when creating
the PluginStream
(WebCore::PluginViewWin::didReceiveResponse): Same
(WebCore::PluginViewWin::wndProc): Use add / contains instead of
bit ops
(WebCore::PluginViewWin::userAgent): Same
(WebCore::PluginViewWin::invalidateRect): Same
(WebCore::PluginViewWin::~PluginViewWin): Same
(WebCore::PluginViewWin::determineQuirks): Same
(WebCore::PluginViewWin::setParameters): Same
(WebCore::PluginViewWin::PluginViewWin): Same
(WebCore::PluginViewWin::init): Same
(WebCore::PluginViewWin::setCallingPlugin): Same
* plugins/win/PluginViewWin.h:
2008-01-24 David Hyatt <hyatt@apple.com>
http://bugs.webkit.org/show_bug.cgi?id=16982
......@@ -7932,6 +7932,10 @@
RelativePath="..\plugins\PluginDebug.h"
>
</File>
<File
RelativePath="..\plugins\PluginQuirkSet.h"
>
</File>
<File
RelativePath="..\plugins\PluginStream.cpp"
>
......
/*
* Copyright (C) 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PluginQuirkSet_h
#define PluginQuirkSet_h
namespace WebCore {
enum PluginQuirk {
PluginQuirkWantsMozillaUserAgent = 1 << 0,
PluginQuirkDeferFirstSetWindowCall = 1 << 1,
PluginQuirkThrottleInvalidate = 1 << 2,
PluginQuirkRemoveWindowlessVideoParam = 1 << 3,
PluginQuirkThrottleWMUserPlusOneMessages = 1 << 4,
PluginQuirkDontUnloadPlugin = 1 << 5,
PluginQuirkDontCallWndProcForSameMessageRecursively = 1 << 6,
PluginQuirkHasModalMessageLoop = 1 << 7,
PluginQuirkFlashURLNotifyBug = 1 << 8,
};
class PluginQuirkSet {
public:
PluginQuirkSet() : m_quirks(0) { }
void add(PluginQuirk quirk) { m_quirks |= quirk; }
bool contains(PluginQuirk quirk) const { return m_quirks & quirk; }
private:
unsigned m_quirks;
};
} // namespace WebCore
#endif // PluginQuirkSet_h
/*
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Collabora, Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -51,7 +51,7 @@ static StreamMap& streams()
return staticStreams;
}
PluginStream::PluginStream(PluginStreamClient* client, Frame* frame, const ResourceRequest& resourceRequest, bool sendNotification, void* notifyData, const NPPluginFuncs* pluginFuncs, NPP instance)
PluginStream::PluginStream(PluginStreamClient* client, Frame* frame, const ResourceRequest& resourceRequest, bool sendNotification, void* notifyData, const NPPluginFuncs* pluginFuncs, NPP instance, const PluginQuirkSet& quirks)
: m_resourceRequest(resourceRequest)
, m_client(client)
, m_frame(frame)
......@@ -64,6 +64,7 @@ PluginStream::PluginStream(PluginStreamClient* client, Frame* frame, const Resou
, m_tempFileHandle(invalidPlatformFileHandle)
, m_pluginFuncs(pluginFuncs)
, m_instance(instance)
, m_quirks(quirks)
{
ASSERT(m_instance);
......@@ -231,22 +232,42 @@ void PluginStream::destroyStream()
closeFile(m_tempFileHandle);
if (m_stream.ndata != 0) {
bool newStreamCalled = m_stream.ndata;
if (newStreamCalled) {
if (m_reason == NPRES_DONE && (m_transferMode == NP_ASFILE || m_transferMode == NP_ASFILEONLY)) {
ASSERT(!m_path.isNull());
m_pluginFuncs->asfile(m_instance, &m_stream, m_path.data());
}
NPError npErr;
npErr = m_pluginFuncs->destroystream(m_instance, &m_stream, m_reason);
NPError npErr = m_pluginFuncs->destroystream(m_instance, &m_stream, m_reason);
LOG_NPERROR(npErr);
m_stream.ndata = 0;
}
if (m_sendNotification)
if (m_sendNotification) {
// Flash 9 can dereference null if we call NPP_URLNotify without first calling NPP_NewStream
// for requests made with NPN_PostURLNotify; see <rdar://5588807>
if (!newStreamCalled && m_quirks.contains(PluginQuirkFlashURLNotifyBug) &&
equalIgnoringCase(m_resourceRequest.httpMethod(), "POST")) {
// Protect the stream if NPN_DestroyStream is called from NPP_NewStream
RefPtr<PluginStream> protect(this);
m_transferMode = NP_NORMAL;
m_stream.url = "";
m_stream.notifyData = m_notifyData;
m_pluginFuncs->newstream(m_instance, "", &m_stream, false, &m_transferMode);
m_pluginFuncs->destroystream(m_instance, &m_stream, m_reason);
// in successful requests, the URL is dynamically allocated and freed in our
// destructor, so reset it to 0
m_stream.url = 0;
}
m_pluginFuncs->urlnotify(m_instance, m_resourceRequest.url().deprecatedString().utf8(), m_reason, m_notifyData);
}
m_streamState = StreamStopped;
......
/*
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2008 Collabora, Ltd. All rights reserved.
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Collabora, Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -33,6 +33,7 @@
#include "npfunctions.h"
#include "NetscapePlugInStreamLoader.h"
#include "PlatformString.h"
#include "PluginQuirkSet.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "StringHash.h"
......@@ -56,7 +57,7 @@ namespace WebCore {
class PluginStream : public RefCounted<PluginStream>, private NetscapePlugInStreamLoaderClient {
public:
PluginStream(PluginStreamClient*, Frame*, const ResourceRequest&, bool sendNotification, void* notifyData, const NPPluginFuncs*, NPP instance);
PluginStream(PluginStreamClient*, Frame*, const ResourceRequest&, bool sendNotification, void* notifyData, const NPPluginFuncs*, NPP instance, const PluginQuirkSet&);
~PluginStream();
void start();
......@@ -107,6 +108,7 @@ namespace WebCore {
CString m_path;
NPReason m_reason;
NPStream m_stream;
PluginQuirkSet m_quirks;
};
} // namespace WebCore
......
/*
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Collabora, Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -282,12 +282,12 @@ LRESULT
PluginViewWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == m_lastMessage &&
(m_quirks & PluginQuirkDontCallWndProcForSameMessageRecursively) &&
m_quirks.contains(PluginQuirkDontCallWndProcForSameMessageRecursively) &&
m_isCallingPluginWndProc)
return 1;
if (message == WM_USER + 1 &&
(m_quirks & PluginQuirkThrottleWMUserPlusOneMessages)) {
m_quirks.contains(PluginQuirkThrottleWMUserPlusOneMessages)) {
if (!m_messageThrottler)
m_messageThrottler.set(new PluginMessageThrottlerWin(this));
......@@ -845,7 +845,7 @@ void PluginViewWin::performRequest(PluginRequestWin* request)
// if this is not a targeted request, create a stream for it. otherwise,
// just pass it off to the loader
if (targetFrameName.isEmpty()) {
PluginStream* stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance());
PluginStream* stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_quirks);
m_streams.add(stream);
stream->start();
} else {
......@@ -877,7 +877,7 @@ void PluginViewWin::performRequest(PluginRequestWin* request)
if (getString(parentFrame->scriptProxy(), result, resultString))
cstr = resultString.utf8();
RefPtr<PluginStream> stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance());
RefPtr<PluginStream> stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_quirks);
m_streams.add(stream);
stream->sendJavaScriptStream(requestURL, cstr);
}
......@@ -1246,7 +1246,7 @@ NPError PluginViewWin::destroyStream(NPStream* stream, NPReason reason)
const char* PluginViewWin::userAgent()
{
if (m_quirks & PluginQuirkWantsMozillaUserAgent)
if (m_quirks.contains(PluginQuirkWantsMozillaUserAgent))
return MozillaUserAgent;
if (m_userAgent.isNull())
......@@ -1344,7 +1344,7 @@ void PluginViewWin::invalidateRect(NPRect* rect)
RECT invalidRect(r);
InvalidateRect(m_window, &invalidRect, FALSE);
} else {
if (m_quirks & PluginQuirkThrottleInvalidate) {
if (m_quirks.contains(PluginQuirkThrottleInvalidate)) {
m_invalidRects.append(r);
if (!m_invalidateTimer.isActive())
m_invalidateTimer.startOneShot(0.001);
......@@ -1434,7 +1434,7 @@ PluginViewWin::~PluginViewWin()
m_parentFrame->cleanupScriptObjectsForPlugin(this);
if (m_plugin && !(m_quirks & PluginQuirkDontUnloadPlugin))
if (m_plugin && !m_quirks.contains(PluginQuirkDontUnloadPlugin))
m_plugin->unload();
}
......@@ -1449,48 +1449,49 @@ void PluginViewWin::determineQuirks(const String& mimeType)
{
// The flash plugin only requests windowless plugins if we return a mozilla user agent
if (mimeType == "application/x-shockwave-flash") {
m_quirks |= PluginQuirkWantsMozillaUserAgent;
m_quirks |= PluginQuirkThrottleInvalidate;
m_quirks |= PluginQuirkThrottleWMUserPlusOneMessages;
m_quirks.add(PluginQuirkWantsMozillaUserAgent);
m_quirks.add(PluginQuirkThrottleInvalidate);
m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages);
m_quirks.add(PluginQuirkFlashURLNotifyBug);
}
// The WMP plugin sets its size on the first NPP_SetWindow call and never updates its size, so
// call SetWindow when the plugin view has a correct size
if (m_plugin->name().contains("Microsoft") && m_plugin->name().contains("Windows Media")) {
m_quirks |= PluginQuirkDeferFirstSetWindowCall;
m_quirks.add(PluginQuirkDeferFirstSetWindowCall);
// Windowless mode does not work at all with the WMP plugin so just remove that parameter
// and don't pass it to the plug-in.
m_quirks |= PluginQuirkRemoveWindowlessVideoParam;
m_quirks.add(PluginQuirkRemoveWindowlessVideoParam);
// WMP has a modal message loop that it enters whenever we call it or
// ask it to paint. This modal loop can deliver messages to other
// windows in WebKit at times when they are not expecting them (for
// example, delivering a WM_PAINT message during a layout), and these
// can cause crashes.
m_quirks |= PluginQuirkHasModalMessageLoop;
m_quirks.add(PluginQuirkHasModalMessageLoop);
}
// The DivX plugin sets its size on the first NPP_SetWindow call and never updates its size, so
// call SetWindow when the plugin view has a correct size
if (mimeType == "video/divx")
m_quirks |= PluginQuirkDeferFirstSetWindowCall;
m_quirks.add(PluginQuirkDeferFirstSetWindowCall);
// FIXME: This is a workaround for a problem in our NPRuntime bindings; if a plug-in creates an
// NPObject and passes it to a function it's not possible to see what root object that NPObject belongs to.
// Thus, we don't know that the object should be invalidated when the plug-in instance goes away.
// See <rdar://problem/5487742>.
if (mimeType == "application/x-silverlight")
m_quirks |= PluginQuirkDontUnloadPlugin;
m_quirks.add(PluginQuirkDontUnloadPlugin);
// Because a single process cannot create multiple VMs, and we cannot reliably unload a
// Java VM, we cannot unload the Java plugin, or we'll lose reference to our only VM
if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType))
m_quirks |= PluginQuirkDontUnloadPlugin;
m_quirks.add(PluginQuirkDontUnloadPlugin);
// Prevent the Real plugin from calling the Window Proc recursively, causing the stack to overflow.
if (mimeType == "audio/x-pn-realaudio-plugin")
m_quirks |= PluginQuirkDontCallWndProcForSameMessageRecursively;
m_quirks.add(PluginQuirkDontCallWndProcForSameMessageRecursively);
}
void PluginViewWin::setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues)
......@@ -1504,7 +1505,7 @@ void PluginViewWin::setParameters(const Vector<String>& paramNames, const Vector
m_paramValues = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
for (unsigned i = 0; i < size; i++) {
if ((m_quirks & PluginQuirkRemoveWindowlessVideoParam) && equalIgnoringCase(paramNames[i], "windowlessvideo"))
if (m_quirks.contains(PluginQuirkRemoveWindowlessVideoParam) && equalIgnoringCase(paramNames[i], "windowlessvideo"))
continue;
m_paramNames[paramCount] = createUTF8String(paramNames[i]);
......@@ -1531,7 +1532,6 @@ PluginViewWin::PluginViewWin(Frame* parentFrame, const IntSize& size, PluginPack
, m_paramValues(0)
, m_window(0)
, m_pluginWndProc(0)
, m_quirks(0)
, m_isWindowed(true)
, m_isTransparent(false)
, m_isVisible(false)
......@@ -1605,7 +1605,7 @@ void PluginViewWin::init()
m_npWindow.window = 0;
}
if (!(m_quirks & PluginQuirkDeferFirstSetWindowCall))
if (!m_quirks.contains(PluginQuirkDeferFirstSetWindowCall))
setNPWindowRect(frameGeometry());
m_status = PluginStatusLoadedSuccessfully;
......@@ -1616,7 +1616,7 @@ void PluginViewWin::didReceiveResponse(const ResourceResponse& response)
ASSERT(m_loadManually);
ASSERT(!m_manualStream);
m_manualStream = new PluginStream(this, m_parentFrame, m_parentFrame->loader()->activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance());
m_manualStream = new PluginStream(this, m_parentFrame, m_parentFrame->loader()->activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance(), m_quirks);
m_manualStream->setLoadManually(true);
m_manualStream->didReceiveResponse(0, response);
......@@ -1648,7 +1648,7 @@ void PluginViewWin::didFail(const ResourceError& error)
void PluginViewWin::setCallingPlugin(bool b) const
{
if (!(m_quirks & PluginQuirkHasModalMessageLoop))
if (!m_quirks.contains(PluginQuirkHasModalMessageLoop))
return;
if (b)
......
/*
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Collabora, Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -35,6 +35,7 @@
#include "KURL.h"
#include "PlatformString.h"
#include "PluginStream.h"
#include "PluginQuirkSet.h"
#include "ResourceRequest.h"
#include "Timer.h"
#include "Widget.h"
......@@ -64,17 +65,6 @@ namespace WebCore {
class PluginStream;
class ResourceError;
class ResourceResponse;
enum PluginQuirks {
PluginQuirkWantsMozillaUserAgent = 1 << 0,
PluginQuirkDeferFirstSetWindowCall = 1 << 1,
PluginQuirkThrottleInvalidate = 1 << 2,
PluginQuirkRemoveWindowlessVideoParam = 1 << 3,
PluginQuirkThrottleWMUserPlusOneMessages = 1 << 4,
PluginQuirkDontUnloadPlugin = 1 << 5,
PluginQuirkDontCallWndProcForSameMessageRecursively = 1 << 6,
PluginQuirkHasModalMessageLoop = 1 << 7
};
enum PluginStatus {
PluginStatusCanNotFindPlugin,
......@@ -202,7 +192,7 @@ namespace WebCore {
HashSet<RefPtr<PluginStream> > m_streams;
Vector<PluginRequestWin*> m_requests;
int m_quirks;
PluginQuirkSet m_quirks;
bool m_isWindowed;
bool m_isTransparent;
bool m_isVisible;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment