зеркало из https://github.com/mozilla/pjs.git
test for bug 550026
--HG-- extra : rebase_source : 4fde8da0a361a36da3540c9295762b4b744d1e5c
This commit is contained in:
Родитель
90f6790452
Коммит
a1e2d48349
|
@ -117,6 +117,7 @@ endif
|
|||
ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
|
||||
_MOCHITEST_FILES += \
|
||||
test_copyText.html \
|
||||
test_crash_nested_loop.html \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<head>
|
||||
<title>Plugin crashing in nested loop</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<body>
|
||||
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var iframe = document.getElementById('iframe1');
|
||||
|
||||
window.frameLoaded = function frameLoaded_toCrash() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var prefs = Components.classes['@mozilla.org/preferences-service;1']
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
if (!prefs.getBoolPref('dom.ipc.plugins.enabled')) {
|
||||
ok(true, "Skipping this test when IPC plugins are not enabled.");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var p = iframe.contentDocument.getElementById('plugin1');
|
||||
|
||||
try {
|
||||
p.crashInNestedLoop();
|
||||
ok(false, "p.crashInNestedLoop() should throw an exception");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "p.crashInNestedLoop() should throw an exception");
|
||||
}
|
||||
|
||||
// this test is for bug 550026, which is inherently
|
||||
// nondeterministic. if we hit that bug, the browser process
|
||||
// would have crashed by now. if not, we'll pass "spuriously"
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
|
@ -60,6 +60,8 @@
|
|||
#define PLUGIN_VERSION "1.0.0.0"
|
||||
|
||||
#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
|
||||
#define STATIC_ASSERT(condition) \
|
||||
extern void np_static_assert(int arg[(condition) ? 1 : -1])
|
||||
|
||||
//
|
||||
// Intentional crash
|
||||
|
@ -67,7 +69,7 @@
|
|||
|
||||
int gCrashCount = 0;
|
||||
|
||||
static void
|
||||
void
|
||||
NoteIntentionalCrash()
|
||||
{
|
||||
char* bloatLog = getenv("XPCOM_MEM_BLOAT_LOG");
|
||||
|
@ -157,6 +159,7 @@ static bool hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount
|
|||
static bool getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool reinitWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool propertyAndMethod(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
|
||||
static const NPUTF8* sPluginMethodIdentifierNames[] = {
|
||||
|
@ -200,10 +203,11 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = {
|
|||
"getClipboardText",
|
||||
"callOnDestroy",
|
||||
"reinitWidget",
|
||||
"crashInNestedLoop",
|
||||
"propertyAndMethod"
|
||||
};
|
||||
static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
|
||||
static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMethodIdentifierNames)] = {
|
||||
static const ScriptableFunction sPluginMethodFunctions[] = {
|
||||
npnEvaluateTest,
|
||||
npnInvokeTest,
|
||||
npnInvokeDefaultTest,
|
||||
|
@ -244,8 +248,13 @@ static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMetho
|
|||
getClipboardText,
|
||||
callOnDestroy,
|
||||
reinitWidget,
|
||||
crashPluginInNestedLoop,
|
||||
propertyAndMethod
|
||||
};
|
||||
|
||||
STATIC_ASSERT(ARRAY_LENGTH(sPluginMethodIdentifierNames) ==
|
||||
ARRAY_LENGTH(sPluginMethodFunctions));
|
||||
|
||||
static const NPUTF8* sPluginPropertyIdentifierNames[] = {
|
||||
"propertyAndMethod"
|
||||
};
|
||||
|
@ -2711,12 +2720,29 @@ getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args,
|
||||
uint32_t argCount, NPVariant* result)
|
||||
{
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
|
||||
return pluginCrashInNestedLoop(id);
|
||||
}
|
||||
|
||||
#else
|
||||
bool
|
||||
getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
||||
NPVariant* result)
|
||||
{
|
||||
/// XXX Not implemented!
|
||||
// XXX Not implemented!
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args,
|
||||
uint32_t argCount, NPVariant* result)
|
||||
{
|
||||
// XXX Not implemented!
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -127,4 +127,6 @@ typedef struct InstanceData {
|
|||
|
||||
void notifyDidPaint(InstanceData* instanceData);
|
||||
|
||||
void NoteIntentionalCrash();
|
||||
|
||||
#endif // nptest_h_
|
||||
|
|
|
@ -35,12 +35,15 @@
|
|||
|
||||
#include "nptest_platform.h"
|
||||
#include "npapi.h"
|
||||
#include <pthread.h>
|
||||
#include <gdk/gdk.h>
|
||||
#ifdef MOZ_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -635,3 +638,79 @@ pluginGetClipboardText(InstanceData* instanceData)
|
|||
|
||||
return retText;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// NB: this test is quite gross in that it's not only
|
||||
// nondeterministic, but dependent on the guts of the nested glib
|
||||
// event loop handling code in PluginModule. We first sleep long
|
||||
// enough to make sure that the "detection timer" will be pending when
|
||||
// we enter the nested glib loop, then similarly for the "process browser
|
||||
// events" timer. Then we "schedule" the crasher thread to run at about the
|
||||
// same time we expect that the PluginModule "process browser events" task
|
||||
// will run. If all goes well, the plugin process will crash and generate the
|
||||
// XPCOM "plugin crashed" task, and the browser will run that task while still
|
||||
// in the "process some events" loop.
|
||||
|
||||
static void*
|
||||
CrasherThread(void* data)
|
||||
{
|
||||
// Give the parent thread a chance to send the message.
|
||||
usleep(200);
|
||||
|
||||
// Exit (without running atexit hooks) rather than crashing with a signal
|
||||
// so as to make timing more reliable. The process terminates immediately
|
||||
// rather than waiting for a thread in the parent process to attach and
|
||||
// generate a minidump.
|
||||
_exit(1);
|
||||
|
||||
// not reached
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
pluginCrashInNestedLoop(InstanceData* instanceData)
|
||||
{
|
||||
// wait at least long enough for nested loop detector task to be pending ...
|
||||
sleep(1);
|
||||
|
||||
// Run the nested loop detector by processing all events that are waiting.
|
||||
bool found_event = false;
|
||||
while (g_main_context_iteration(NULL, FALSE)) {
|
||||
found_event = true;
|
||||
}
|
||||
if (!found_event) {
|
||||
g_warning("DetectNestedEventLoop did not fire");
|
||||
return true; // trigger a test failure
|
||||
}
|
||||
|
||||
// wait at least long enough for the "process browser events" task to be
|
||||
// pending ...
|
||||
sleep(1);
|
||||
|
||||
// we'll be crashing soon, note that fact now to avoid messing with
|
||||
// timing too much
|
||||
NoteIntentionalCrash();
|
||||
|
||||
// schedule the crasher thread ...
|
||||
pthread_t crasherThread;
|
||||
if (0 != pthread_create(&crasherThread, NULL, CrasherThread, NULL)) {
|
||||
g_warning("Failed to create thread");
|
||||
return true; // trigger a test failure
|
||||
}
|
||||
|
||||
// .. and hope it crashes at about the same time as the "process browser
|
||||
// events" task (that should run in this loop) is being processed in the
|
||||
// parent.
|
||||
found_event = false;
|
||||
while (g_main_context_iteration(NULL, FALSE)) {
|
||||
found_event = true;
|
||||
}
|
||||
if (found_event) {
|
||||
g_warning("Should have crashed in ProcessBrowserEvents");
|
||||
} else {
|
||||
g_warning("ProcessBrowserEvents did not fire");
|
||||
}
|
||||
|
||||
// if we get here without crashing, then we'll trigger a test failure
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -126,4 +126,12 @@ void pluginDoInternalConsistencyCheck(InstanceData* instanceData, std::string& e
|
|||
*/
|
||||
std::string pluginGetClipboardText(InstanceData* instanceData);
|
||||
|
||||
/**
|
||||
* Crash while in a nested event loop. The goal is to catch the
|
||||
* browser processing the XPCOM event generated from the plugin's
|
||||
* crash while other plugin code is still on the stack.
|
||||
* See https://bugzilla.mozilla.org/show_bug.cgi?id=550026.
|
||||
*/
|
||||
bool pluginCrashInNestedLoop(InstanceData* instanceData);
|
||||
|
||||
#endif // nptest_platform_h_
|
||||
|
|
Загрузка…
Ссылка в новой задаче