зеркало из https://github.com/mozilla/pjs.git
Bug 544345: Kill plugins if they exceed the hang timeout. r=bsmedberg
--HG-- extra : transplant_source : K%BBb%8Dq%C8%26O%7Cj%10%0B%EE%05j%3C%0F%CA%C3%3A
This commit is contained in:
Родитель
3a405d5c52
Коммит
1e29088232
|
@ -36,20 +36,36 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "base/process_util.h"
|
||||
|
||||
#include "mozilla/ipc/SyncChannel.h"
|
||||
#include "mozilla/plugins/PluginModuleParent.h"
|
||||
#include "mozilla/plugins/BrowserStreamParent.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
|
||||
using mozilla::PluginLibrary;
|
||||
using base::KillProcess;
|
||||
|
||||
using mozilla::PluginLibrary;
|
||||
using mozilla::ipc::NPRemoteIdentifier;
|
||||
using mozilla::ipc::SyncChannel;
|
||||
|
||||
using namespace mozilla::plugins;
|
||||
|
||||
static const char kTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
|
||||
|
||||
PR_STATIC_ASSERT(sizeof(NPIdentifier) == sizeof(void*));
|
||||
|
||||
template<>
|
||||
struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent>
|
||||
{
|
||||
typedef mozilla::plugins::PluginModuleParent Class;
|
||||
static void RetainCallee(Class* obj) { }
|
||||
static void ReleaseCallee(Class* obj) { }
|
||||
};
|
||||
|
||||
class PluginCrashed : public nsRunnable
|
||||
{
|
||||
public:
|
||||
|
@ -80,6 +96,8 @@ PluginModuleParent::LoadModule(const char* aFilePath)
|
|||
parent->Open(parent->mSubprocess->GetChannel(),
|
||||
parent->mSubprocess->GetChildProcessHandle());
|
||||
|
||||
TimeoutChanged(kTimeoutPref, parent);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
@ -96,6 +114,8 @@ PluginModuleParent::PluginModuleParent(const char* aFilePath)
|
|||
if (!mValidIdentifiers.Init()) {
|
||||
NS_ERROR("Out of memory");
|
||||
}
|
||||
|
||||
nsContentUtils::RegisterPrefCallback(kTimeoutPref, TimeoutChanged, this);
|
||||
}
|
||||
|
||||
PluginModuleParent::~PluginModuleParent()
|
||||
|
@ -111,6 +131,8 @@ PluginModuleParent::~PluginModuleParent()
|
|||
mSubprocess->Delete();
|
||||
mSubprocess = nsnull;
|
||||
}
|
||||
|
||||
nsContentUtils::UnregisterPrefCallback(kTimeoutPref, TimeoutChanged, this);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -172,6 +194,58 @@ PluginModuleParent::WriteExtraDataForMinidump(nsIFile* dumpFile)
|
|||
stream->Close();
|
||||
}
|
||||
|
||||
int
|
||||
PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
|
||||
{
|
||||
AssertPluginThread();
|
||||
NS_ABORT_IF_FALSE(!strcmp(aPref, kTimeoutPref),
|
||||
"unexpected pref callback");
|
||||
|
||||
PRInt32 timeoutSecs = nsContentUtils::GetIntPref(kTimeoutPref, 0);
|
||||
int32 timeoutMs = (timeoutSecs > 0) ? (1000 * timeoutSecs) :
|
||||
SyncChannel::kNoTimeout;
|
||||
|
||||
static_cast<PluginModuleParent*>(aModule)->SetReplyTimeoutMs(timeoutMs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleParent::CleanupFromTimeout()
|
||||
{
|
||||
if (!mShutdown)
|
||||
Close();
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleParent::ShouldContinueFromReplyTimeout()
|
||||
{
|
||||
// FIXME/bug 544095: pop up a dialog asking the user what to do
|
||||
bool waitMoar = false;
|
||||
|
||||
if (!waitMoar) {
|
||||
// We can't depend on the IO thread notifying us of a channel
|
||||
// error, because there's an inherent race between killing the
|
||||
// subprocess and shutting down the socket. It would be nice
|
||||
// to call Close() here and do all the IPDL cleanup
|
||||
// immediately, but we might have arbitrary junk below us on
|
||||
// the stack. So, a compromise: enqueue an event now that
|
||||
// will Close(), *before* killing the child process. This
|
||||
// guarantees that the Close() event will be processed before
|
||||
// the IO error event, if it's delivered.
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &PluginModuleParent::CleanupFromTimeout));
|
||||
|
||||
// FIXME/bug 544095: kill the subprocess in a way that
|
||||
// triggers breakpad, and also capture a minidump for this
|
||||
// process
|
||||
KillProcess(ChildProcessHandle(), 1, false);
|
||||
}
|
||||
|
||||
|
||||
return waitMoar;
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
|
|
|
@ -112,6 +112,16 @@ public:
|
|||
*/
|
||||
static PluginLibrary* LoadModule(const char* aFilePath);
|
||||
|
||||
const NPNetscapeFuncs* GetNetscapeFuncs() {
|
||||
return mNPNIface;
|
||||
}
|
||||
|
||||
bool EnsureValidNPIdentifier(NPIdentifier aIdentifier);
|
||||
|
||||
protected:
|
||||
NS_OVERRIDE
|
||||
virtual bool ShouldContinueFromReplyTimeout();
|
||||
|
||||
virtual bool
|
||||
AnswerNPN_UserAgent(nsCString* userAgent);
|
||||
|
||||
|
@ -142,15 +152,9 @@ public:
|
|||
NPError* aError,
|
||||
bool* aBoolVal);
|
||||
|
||||
const NPNetscapeFuncs* GetNetscapeFuncs() {
|
||||
return mNPNIface;
|
||||
}
|
||||
|
||||
static PluginInstanceParent* InstCast(NPP instance);
|
||||
static BrowserStreamParent* StreamCast(NPP instance, NPStream* s);
|
||||
|
||||
bool EnsureValidNPIdentifier(NPIdentifier aIdentifier);
|
||||
|
||||
base::ProcessHandle ChildProcessHandle() { return mSubprocess->GetChildProcessHandle(); }
|
||||
private:
|
||||
void SetPluginFuncs(NPPluginFuncs* aFuncs);
|
||||
|
@ -215,6 +219,9 @@ private:
|
|||
void WriteExtraDataEntry(nsIFileOutputStream* stream,
|
||||
const char* key,
|
||||
const char* value);
|
||||
void CleanupFromTimeout();
|
||||
static int TimeoutChanged(const char* aPref, void* aModule);
|
||||
|
||||
PluginProcessParent* mSubprocess;
|
||||
bool mShutdown;
|
||||
const NPNetscapeFuncs* mNPNIface;
|
||||
|
|
|
@ -1215,6 +1215,17 @@ pref("editor.positioning.offset", 0);
|
|||
pref("dom.max_chrome_script_run_time", 20);
|
||||
pref("dom.max_script_run_time", 10);
|
||||
|
||||
// How long a plugin is allowed to process a synchronous IPC message
|
||||
// before we consider it "hung".
|
||||
//
|
||||
// NB: chosen to match dom.max_script_run_time by default
|
||||
#ifndef DEBUG
|
||||
pref("dom.ipc.plugins.timeoutSecs", 10);
|
||||
#else
|
||||
// No timeout in DEBUG builds
|
||||
pref("dom.ipc.plugins.timeoutSecs", 0);
|
||||
#endif
|
||||
|
||||
pref("svg.enabled", true);
|
||||
pref("svg.smil.enabled", true);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче