mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 829557. Part 1: When calling into plugin code, identify situations where it is safe (or unsafe) to reenter Gecko from plugin code. r=bsmedberg
When Gecko is reentered from unsafe call sites, we allow the reentry, but we suppress execution of the refresh driver to minimize the danger. In this patch, we treat all sites as unsafe. --HG-- rename : toolkit/modules/Timer.jsm => browser/devtools/shared/Browser.jsm rename : toolkit/modules/tests/xpcshell/test_timer.js => browser/devtools/shared/test/browser_browser_basic.js rename : build/mach_bootstrap.py => mach extra : rebase_source : b83c1d09313bff62357eaa931eced0f72f838493
This commit is contained in:
parent
fffa15107b
commit
e170f559fb
@ -41,6 +41,7 @@ EXPORTS = \
|
||||
nsPluginsCID.h \
|
||||
nsNPAPIPluginInstance.h \
|
||||
nsPluginsDir.h \
|
||||
nsPluginSafety.h \
|
||||
nsPluginTags.h \
|
||||
nsPluginDirServiceProvider.h \
|
||||
nsPluginHost.h \
|
||||
|
@ -186,9 +186,9 @@ enum eNPPStreamTypeInternal {
|
||||
|
||||
static NS_DEFINE_IID(kMemoryCID, NS_MEMORY_CID);
|
||||
|
||||
PRIntervalTime NS_NotifyBeginPluginCall()
|
||||
PRIntervalTime NS_NotifyBeginPluginCall(NSPluginCallReentry aReentryState)
|
||||
{
|
||||
nsNPAPIPluginInstance::BeginPluginCall();
|
||||
nsNPAPIPluginInstance::BeginPluginCall(aReentryState);
|
||||
return PR_IntervalNow();
|
||||
}
|
||||
|
||||
@ -196,9 +196,9 @@ PRIntervalTime NS_NotifyBeginPluginCall()
|
||||
// registered to listen to the "experimental-notify-plugin-call" subject.
|
||||
// Each "experimental-notify-plugin-call" notification carries with it the run
|
||||
// time value in milliseconds that the call took to execute.
|
||||
void NS_NotifyPluginCall(PRIntervalTime startTime)
|
||||
void NS_NotifyPluginCall(PRIntervalTime startTime, NSPluginCallReentry aReentryState)
|
||||
{
|
||||
nsNPAPIPluginInstance::EndPluginCall();
|
||||
nsNPAPIPluginInstance::EndPluginCall(aReentryState);
|
||||
|
||||
PRIntervalTime endTime = PR_IntervalNow() - startTime;
|
||||
nsCOMPtr<nsIObserverService> notifyUIService =
|
||||
@ -789,7 +789,8 @@ nsPluginThreadRunnable::Run()
|
||||
if (mFunc) {
|
||||
PluginDestructionGuard guard(mInstance);
|
||||
|
||||
NS_TRY_SAFE_CALL_VOID(mFunc(mUserData), nullptr);
|
||||
NS_TRY_SAFE_CALL_VOID(mFunc(mUserData), nullptr,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -213,7 +213,7 @@ nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t nsNPAPIPluginInstance::gInPluginCalls = 0;
|
||||
uint32_t nsNPAPIPluginInstance::gInUnsafePluginCalls = 0;
|
||||
|
||||
void
|
||||
nsNPAPIPluginInstance::Destroy()
|
||||
@ -317,7 +317,8 @@ nsresult nsNPAPIPluginInstance::Stop()
|
||||
if (pluginFunctions->destroy) {
|
||||
NPSavedData *sdata = 0;
|
||||
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroy)(&mNPP, &sdata), this);
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroy)(&mNPP, &sdata), this,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("NPP Destroy called: this=%p, npp=%p, return=%d\n", this, &mNPP, error));
|
||||
@ -582,7 +583,8 @@ nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)
|
||||
NPPAutoPusher nppPusher(&mNPP);
|
||||
|
||||
DebugOnly<NPError> error;
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setwindow)(&mNPP, (NPWindow*)window), this);
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setwindow)(&mNPP, (NPWindow*)window), this,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
mInPluginInitCall = oldVal;
|
||||
|
||||
@ -650,7 +652,8 @@ nsresult nsNPAPIPluginInstance::Print(NPPrint* platformPrint)
|
||||
}
|
||||
|
||||
if (pluginFunctions->print)
|
||||
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->print)(&mNPP, thePrint), this);
|
||||
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->print)(&mNPP, thePrint), this,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("NPP PrintProc called: this=%p, pDC=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d]\n",
|
||||
@ -688,7 +691,8 @@ nsresult nsNPAPIPluginInstance::HandleEvent(void* event, int16_t* result)
|
||||
if (pluginFunctions->event) {
|
||||
mCurrentPluginEvent = event;
|
||||
#if defined(XP_WIN) || defined(XP_OS2)
|
||||
NS_TRY_SAFE_CALL_RETURN(tmpResult, (*pluginFunctions->event)(&mNPP, event), this);
|
||||
NS_TRY_SAFE_CALL_RETURN(tmpResult, (*pluginFunctions->event)(&mNPP, event), this,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
#else
|
||||
MAIN_THREAD_JNI_REF_GUARD;
|
||||
tmpResult = (*pluginFunctions->event)(&mNPP, event);
|
||||
@ -718,7 +722,8 @@ nsresult nsNPAPIPluginInstance::GetValueFromPlugin(NPPVariable variable, void* v
|
||||
PluginDestructionGuard guard(this);
|
||||
|
||||
NPError pluginError = NPERR_GENERIC_ERROR;
|
||||
NS_TRY_SAFE_CALL_RETURN(pluginError, (*pluginFunctions->getvalue)(&mNPP, variable, value), this);
|
||||
NS_TRY_SAFE_CALL_RETURN(pluginError, (*pluginFunctions->getvalue)(&mNPP, variable, value), this,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("NPP GetValue called: this=%p, npp=%p, var=%d, value=%d, return=%d\n",
|
||||
this, &mNPP, variable, value, pluginError));
|
||||
@ -1404,7 +1409,8 @@ nsNPAPIPluginInstance::PrivateModeStateChanged(bool enabled)
|
||||
|
||||
NPError error;
|
||||
NPBool value = static_cast<NPBool>(enabled);
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVprivateModeBool, &value), this);
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVprivateModeBool, &value), this,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,18 @@ const NPDrawingModel kDefaultDrawingModel = NPDrawingModelCoreGraphics;
|
||||
const NPDrawingModel kDefaultDrawingModel = static_cast<NPDrawingModel>(0);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used to indicate whether it's OK to reenter Gecko and repaint, flush frames,
|
||||
* run scripts, etc, during this plugin call.
|
||||
* When NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO is set, we try to avoid dangerous
|
||||
* Gecko activities when the plugin spins a nested event loop, on a best-effort
|
||||
* basis.
|
||||
*/
|
||||
enum NSPluginCallReentry {
|
||||
NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO
|
||||
};
|
||||
|
||||
class nsNPAPITimer
|
||||
{
|
||||
public:
|
||||
@ -273,12 +285,19 @@ public:
|
||||
// Returns the contents scale factor of the screen the plugin is drawn on.
|
||||
double GetContentsScaleFactor();
|
||||
|
||||
static bool InPluginCall() { return gInPluginCalls > 0; }
|
||||
static void BeginPluginCall() { ++gInPluginCalls; }
|
||||
static void EndPluginCall()
|
||||
static bool InPluginCallUnsafeForReentry() { return gInUnsafePluginCalls > 0; }
|
||||
static void BeginPluginCall(NSPluginCallReentry aReentryState)
|
||||
{
|
||||
NS_ASSERTION(InPluginCall(), "Must be in plugin call");
|
||||
--gInPluginCalls;
|
||||
if (aReentryState == NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO) {
|
||||
++gInUnsafePluginCalls;
|
||||
}
|
||||
}
|
||||
static void EndPluginCall(NSPluginCallReentry aReentryState)
|
||||
{
|
||||
if (aReentryState == NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO) {
|
||||
NS_ASSERTION(gInUnsafePluginCalls > 0, "Must be in plugin call");
|
||||
--gInUnsafePluginCalls;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -376,7 +395,7 @@ private:
|
||||
// is this instance Java and affected by bug 750480?
|
||||
bool mHaveJavaC2PJSObjectQuirk;
|
||||
|
||||
static uint32_t gInPluginCalls;
|
||||
static uint32_t gInUnsafePluginCalls;
|
||||
};
|
||||
|
||||
#endif // nsNPAPIPluginInstance_h_
|
||||
|
@ -235,7 +235,8 @@ nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NPError error;
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroystream)(npp, &mNPStreamWrapper->mNPStream, reason), mInst);
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroystream)(npp, &mNPStreamWrapper->mNPStream, reason), mInst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("NPP DestroyStream called: this=%p, npp=%p, reason=%d, return=%d, url=%s\n",
|
||||
@ -273,7 +274,8 @@ nsNPAPIPluginStreamListener::CallURLNotify(NPReason reason)
|
||||
NPP npp;
|
||||
mInst->GetNPP(&npp);
|
||||
|
||||
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlnotify)(npp, mNotifyURL, reason, mNPStreamWrapper->mNPStream.notifyData), mInst);
|
||||
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlnotify)(npp, mNotifyURL, reason, mNPStreamWrapper->mNPStream.notifyData), mInst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("NPP URLNotify called: this=%p, npp=%p, notify=%p, reason=%d, url=%s\n",
|
||||
@ -321,7 +323,8 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
|
||||
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, seekable, &streamType), mInst);
|
||||
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, seekable, &streamType), mInst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("NPP NewStream called: this=%p, npp=%p, mime=%s, seek=%d, type=%d, return=%d, url=%s\n",
|
||||
@ -563,7 +566,8 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsPluginStreamListenerPeer* streamP
|
||||
if (pluginFunctions->writeready) {
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NS_TRY_SAFE_CALL_RETURN(numtowrite, (*pluginFunctions->writeready)(npp, &mNPStreamWrapper->mNPStream), mInst);
|
||||
NS_TRY_SAFE_CALL_RETURN(numtowrite, (*pluginFunctions->writeready)(npp, &mNPStreamWrapper->mNPStream), mInst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPP WriteReady called: this=%p, npp=%p, "
|
||||
"return(towrite)=%d, url=%s\n",
|
||||
@ -612,7 +616,8 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsPluginStreamListenerPeer* streamP
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
int32_t writeCount = 0; // bytes consumed by plugin instance
|
||||
NS_TRY_SAFE_CALL_RETURN(writeCount, (*pluginFunctions->write)(npp, &mNPStreamWrapper->mNPStream, streamPosition, numtowrite, ptrStreamBuffer), mInst);
|
||||
NS_TRY_SAFE_CALL_RETURN(writeCount, (*pluginFunctions->write)(npp, &mNPStreamWrapper->mNPStream, streamPosition, numtowrite, ptrStreamBuffer), mInst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPP Write called: this=%p, npp=%p, pos=%d, len=%d, "
|
||||
@ -720,7 +725,8 @@ nsNPAPIPluginStreamListener::OnFileAvailable(nsPluginStreamListenerPeer* streamP
|
||||
NPP npp;
|
||||
mInst->GetNPP(&npp);
|
||||
|
||||
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->asfile)(npp, &mNPStreamWrapper->mNPStream, fileName), mInst);
|
||||
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->asfile)(npp, &mNPStreamWrapper->mNPStream, fileName), mInst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("NPP StreamAsFile called: this=%p, npp=%p, url=%s, file=%s\n",
|
||||
@ -862,7 +868,8 @@ nsNPAPIPluginStreamListener::HandleRedirectNotification(nsIChannel *oldChannel,
|
||||
NPP npp;
|
||||
mInst->GetNPP(&npp);
|
||||
#if defined(XP_WIN) || defined(XP_OS2)
|
||||
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlredirectnotify)(npp, spec.get(), static_cast<int32_t>(status), mNPStreamWrapper->mNPStream.notifyData), mInst);
|
||||
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlredirectnotify)(npp, spec.get(), static_cast<int32_t>(status), mNPStreamWrapper->mNPStream.notifyData), mInst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
#else
|
||||
MAIN_THREAD_JNI_REF_GUARD;
|
||||
(*pluginFunctions->urlredirectnotify)(npp, spec.get(), static_cast<int32_t>(status), mNPStreamWrapper->mNPStream.notifyData);
|
||||
|
@ -173,7 +173,8 @@ static bool ProcessFlashMessageDelayed(nsPluginNativeWindowOS2 * aWin,
|
||||
if (msg == sWM_FLASHBOUNCEMSG) {
|
||||
// See PluginWindowEvent::Run() below.
|
||||
NS_TRY_SAFE_CALL_VOID((aWin->GetWindowProc())(hWnd, WM_USER_FLASH, mp1, mp2),
|
||||
inst);
|
||||
inst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -309,9 +310,11 @@ static MRESULT EXPENTRY PluginWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM m
|
||||
|
||||
MRESULT res = (MRESULT)TRUE;
|
||||
if (win->mPluginType == nsPluginType_Java_vm)
|
||||
NS_TRY_SAFE_CALL_RETURN(res, ::WinDefWindowProc(hWnd, msg, mp1, mp2), inst);
|
||||
NS_TRY_SAFE_CALL_RETURN(res, ::WinDefWindowProc(hWnd, msg, mp1, mp2), inst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
else
|
||||
NS_TRY_SAFE_CALL_RETURN(res, (win->GetWindowProc())(hWnd, msg, mp1, mp2), inst);
|
||||
NS_TRY_SAFE_CALL_RETURN(res, (win->GetWindowProc())(hWnd, msg, mp1, mp2), inst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
if (inst) {
|
||||
// Popups are enabled (were enabled before the call to
|
||||
@ -397,7 +400,8 @@ NS_IMETHODIMP PluginWindowEvent::Run()
|
||||
// is more generic.
|
||||
NS_TRY_SAFE_CALL_VOID((win->GetWindowProc())
|
||||
(hWnd, GetMsg(), GetWParam(), GetLParam()),
|
||||
inst);
|
||||
inst,
|
||||
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
||||
|
||||
Clear();
|
||||
return NS_OK;
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include <prinrval.h>
|
||||
|
||||
enum NSPluginCallReentry;
|
||||
|
||||
// On Android, we need to guard against plugin code leaking entries in the local
|
||||
// JNI ref table. See https://bugzilla.mozilla.org/show_bug.cgi?id=780831#c21
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
@ -18,23 +20,23 @@
|
||||
#define MAIN_THREAD_JNI_REF_GUARD
|
||||
#endif
|
||||
|
||||
PRIntervalTime NS_NotifyBeginPluginCall();
|
||||
void NS_NotifyPluginCall(PRIntervalTime);
|
||||
PRIntervalTime NS_NotifyBeginPluginCall(NSPluginCallReentry aReentryState);
|
||||
void NS_NotifyPluginCall(PRIntervalTime aTime, NSPluginCallReentry aReentryState);
|
||||
|
||||
#define NS_TRY_SAFE_CALL_RETURN(ret, fun, pluginInst) \
|
||||
#define NS_TRY_SAFE_CALL_RETURN(ret, fun, pluginInst, pluginCallReentry) \
|
||||
PR_BEGIN_MACRO \
|
||||
MAIN_THREAD_JNI_REF_GUARD; \
|
||||
PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
|
||||
PRIntervalTime startTime = NS_NotifyBeginPluginCall(pluginCallReentry); \
|
||||
ret = fun; \
|
||||
NS_NotifyPluginCall(startTime); \
|
||||
NS_NotifyPluginCall(startTime, pluginCallReentry); \
|
||||
PR_END_MACRO
|
||||
|
||||
#define NS_TRY_SAFE_CALL_VOID(fun, pluginInst) \
|
||||
#define NS_TRY_SAFE_CALL_VOID(fun, pluginInst, pluginCallReentry) \
|
||||
PR_BEGIN_MACRO \
|
||||
MAIN_THREAD_JNI_REF_GUARD; \
|
||||
PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
|
||||
PRIntervalTime startTime = NS_NotifyBeginPluginCall(pluginCallReentry); \
|
||||
fun; \
|
||||
NS_NotifyPluginCall(startTime); \
|
||||
NS_NotifyPluginCall(startTime, pluginCallReentry); \
|
||||
PR_END_MACRO
|
||||
|
||||
#endif //nsPluginSafety_h_
|
||||
|
@ -820,7 +820,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
NS_PRECONDITION(!nsContentUtils::GetCurrentJSContext(),
|
||||
"Shouldn't have a JSContext on the stack");
|
||||
|
||||
if (nsNPAPIPluginInstance::InPluginCall()) {
|
||||
if (nsNPAPIPluginInstance::InPluginCallUnsafeForReentry()) {
|
||||
NS_ERROR("Refresh driver should not run during plugin call!");
|
||||
// Try to survive this by just ignoring the refresh tick.
|
||||
return;
|
||||
|
@ -2071,6 +2071,8 @@ nsObjectFrame::HandleEvent(nsPresContext* aPresContext,
|
||||
if (mInstanceOwner->SendNativeEvents() &&
|
||||
NS_IS_PLUGIN_EVENT(anEvent)) {
|
||||
*anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
|
||||
// Due to plugin code reentering Gecko, this frame may be dead at this
|
||||
// point.
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -2085,6 +2087,8 @@ nsObjectFrame::HandleEvent(nsPresContext* aPresContext,
|
||||
anEvent->message == NS_WHEEL_WHEEL) &&
|
||||
mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
|
||||
*anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
|
||||
// Due to plugin code reentering Gecko, this frame may be dead at this
|
||||
// point.
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user