Test for bug 535298, crashes which occur during NPP_New or NPP_Destroy
authorBenjamin Smedberg <benjamin@smedbergs.us>
Mon, 21 Dec 2009 12:37:32 -0500
changeset 46485 3d5dcaeba50f11bcbf0c3031d1510b5e5b13a1e3
parent 46484 afc656f387fef15ea39c5928ba67afcdb03a3cb6
child 46486 13dcc6e6558be4387342a638b961f08f284517ee
push id14210
push userdougt@mozilla.com
push dateThu, 01 Jul 2010 06:28:42 +0000
treeherdermozilla-central@3aff97777291 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs535298
milestone1.9.3a1pre
Test for bug 535298, crashes which occur during NPP_New or NPP_Destroy
modules/plugin/test/mochitest/Makefile.in
modules/plugin/test/mochitest/test_crashing2.html
modules/plugin/test/testplugin/nptest.cpp
modules/plugin/test/testplugin/nptest.h
--- a/modules/plugin/test/mochitest/Makefile.in
+++ b/modules/plugin/test/mochitest/Makefile.in
@@ -67,16 +67,17 @@ include $(topsrcdir)/config/rules.mk
 		test_streamNotify.html \
 		$(NULL)
 
 #		test_npruntime_npnsetexception.html \ Disabled for e10s
 
 ifdef MOZ_IPC
 _MOCHITEST_FILES += \
 		test_crashing.html \
+		test_crashing2.html \
 		crashing_subpage.html \
 		$(NULL)
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 _MOCHITEST_FILES += \
  		test_windowed_invalidate.html \
         $(NULL)
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/mochitest/test_crashing2.html
@@ -0,0 +1,71 @@
+<head>
+  <title>Plugin crashing</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 onload="mainLoaded()">
+  <iframe id="iframe1" src="about:blank" width="600" height="600"></iframe>
+
+  <script class="testbody" type="application/javascript">
+  SimpleTest.waitForExplicitFinish();
+
+  var iframe = document.getElementById('iframe1');
+
+  function mainLoaded() {
+    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.createElement('embed');
+    p.setAttribute('id', 'plugin1');
+    p.setAttribute('type', 'application/x-test');
+    p.setAttribute('width', '400');
+    p.setAttribute('height', '400');
+    p.setAttribute('drawmode', 'solid');
+    p.setAttribute('color', 'FF00FFFF');
+    p.setAttribute('newCrash', 'true');
+    iframe.contentDocument.body.appendChild(p);
+
+    try {
+      p.setColor('FFFF0000');
+      ok(false, "plugin crashes on creation");
+    }
+    catch (e) {
+      ok(true, "plugin crashes on creation");
+    }
+
+    window.frameLoaded = reloaded1;
+    iframe.contentWindow.location.replace('crashing_subpage.html');
+  }
+
+  function reloaded1() {
+    var p = iframe.contentDocument.getElementById('plugin1');
+    try {
+      p.setColor('FF00FF00');
+      ok(true, "Reloading worked");
+    }
+    catch (e) {
+      ok(false, "Reloading didn't give us a usable plugin");
+    }
+    p.crashOnDestroy();
+    window.frameLoaded = reloaded2;
+    iframe.contentWindow.location.reload();
+  }
+
+  function reloaded2() {
+    var p = iframe.contentDocument.getElementById('plugin1');
+    try {
+      p.setColor('FF00FF00');
+      ok(true, "Reloading worked");
+    }
+    catch (e) {
+      ok(false, "Reloading didn't give us a usable plugin");
+    }
+    SimpleTest.finish();
+  }
+  </script>
--- a/modules/plugin/test/testplugin/nptest.cpp
+++ b/modules/plugin/test/testplugin/nptest.cpp
@@ -54,16 +54,42 @@
 
 #define PLUGIN_NAME        "Test Plug-in"
 #define PLUGIN_DESCRIPTION "Plug-in for testing purposes."
 #define PLUGIN_VERSION     "1.0.0.0"
 
 #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
 
 //
+// Intentional crash
+//
+
+static void
+Crash()
+{
+  char* bloatLog = getenv("XPCOM_MEM_BLOAT_LOG");
+  if (bloatLog) {
+    char* logExt = strstr(bloatLog, ".log");
+    if (logExt) {
+      bloatLog[strlen(bloatLog) - strlen(logExt)] = '\0';
+    }
+    ostringstream bloatName;
+    bloatName << bloatLog << "_plugin_pid" << getpid();
+    if (logExt) {
+      bloatName << ".log";
+    }
+    FILE* processfd = fopen(bloatName.str().c_str(), "a");
+    fprintf(processfd, "==> process %d will purposefully crash\n", getpid());
+    fclose(processfd);
+  }
+  void (*funcptr)() = NULL;
+  funcptr(); // Crash calling null function pointer
+}
+
+//
 // static data
 //
 
 static NPNetscapeFuncs* sBrowserFuncs = NULL;
 static NPClass sNPClass;
 
 static void
 testplugin_URLNotify(NPP instance, const char* url, NPReason reason,
@@ -98,16 +124,17 @@ static bool getPaintCount(NPObject* npob
 static bool getError(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool doInternalConsistencyCheck(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool setColor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool throwExceptionNextInvoke(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool convertPointX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool convertPointY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool streamTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool crashPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool crashOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 
 static const NPUTF8* sPluginMethodIdentifierNames[] = {
   "npnEvaluateTest",
   "npnInvokeTest",
   "npnInvokeDefaultTest",
   "setUndefinedValueTest",
   "identifierToStringTest",
   "timerTest",
@@ -127,16 +154,17 @@ static const NPUTF8* sPluginMethodIdenti
   "getError",
   "doInternalConsistencyCheck",
   "setColor",
   "throwExceptionNextInvoke",
   "convertPointX",
   "convertPointY",
   "streamTest",
   "crash",
+  "crashOnDestroy",
 };
 static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
 static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMethodIdentifierNames)] = {
   npnEvaluateTest,
   npnInvokeTest,
   npnInvokeDefaultTest,
   setUndefinedValueTest,
   identifierToStringTest,
@@ -157,16 +185,17 @@ static const ScriptableFunction sPluginM
   getError,
   doInternalConsistencyCheck,
   setColor,
   throwExceptionNextInvoke,
   convertPointX,
   convertPointY,
   streamTest,
   crashPlugin,
+  crashOnDestroy,
 };
 
 struct URLNotifyData
 {
   const char* cookie;
   NPObject* callback;
   uint32_t size;
   char* data;
@@ -495,16 +524,17 @@ NPP_New(NPMIMEType pluginType, NPP insta
   instanceData->fileBufSize = 0;
   instanceData->throwOnNextInvoke = false;
   instanceData->testrange = NULL;
   instanceData->hasWidget = false;
   instanceData->npnNewStream = false;
   instanceData->writeCount = 0;
   instanceData->writeReadyCount = 0;
   memset(&instanceData->window, 0, sizeof(instanceData->window));
+  instanceData->crashOnDestroy = false;
   instance->pdata = instanceData;
 
   TestNPObject* scriptableObject = (TestNPObject*)NPN_CreateObject(instance, &sNPClass);
   if (!scriptableObject) {
     printf("NPN_CreateObject failed to create an object, can't create a plugin instance\n");
     free(instanceData);
     return NPERR_GENERIC_ERROR;
   }
@@ -590,16 +620,19 @@ NPP_New(NPMIMEType pluginType, NPP insta
         semicolon = range.find(';');
       }
       if (range.length()) addRange(instanceData, range.c_str());
     }
     if (strcmp(argn[i], "newstream") == 0 &&
         strcmp(argv[i], "true") == 0) {
       instanceData->npnNewStream = true;
     }
+    if (strcmp(argn[i], "newcrash") == 0) {
+      Crash();
+    }
   }
 
   if (!browserSupportsWindowless || !pluginSupportsWindowlessMode()) {
     requestWindow = true;
   } else if (!pluginSupportsWindowMode()) {
     requestWindow = false;
   }
   if (requestWindow) {
@@ -669,16 +702,19 @@ NPP_New(NPMIMEType pluginType, NPP insta
 }
 
 NPError
 NPP_Destroy(NPP instance, NPSavedData** save)
 {
   printf("NPP_Destroy\n");
   InstanceData* instanceData = (InstanceData*)(instance->pdata);
 
+  if (instanceData->crashOnDestroy)
+    Crash();
+
   if (instanceData->streamBuf) {
     free(instanceData->streamBuf);
   }
   if (instanceData->fileBuf) {
     free(instanceData->fileBuf);
   }
 
   TestRange* currentrange = instanceData->testrange;
@@ -2023,33 +2059,29 @@ streamTest(NPObject* npobj, const NPVari
   }
 
   return true;
 }
 
 static bool
 crashPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
 {
-  char* bloatLog = getenv("XPCOM_MEM_BLOAT_LOG");
-  if (bloatLog) {
-    char* logExt = strstr(bloatLog, ".log");
-    if (logExt) {
-      bloatLog[strlen(bloatLog) - strlen(logExt)] = '\0';    
-    }
-    ostringstream bloatName;
-    bloatName << bloatLog << "_plugin_pid" << getpid();
-    if (logExt) {
-      bloatName << ".log";    
-    }
-    FILE* processfd = fopen(bloatName.str().c_str(), "a");
-    fprintf(processfd, "==> process %d will purposefully crash\n", getpid());
-    fclose(processfd);
-  }
-  void (*funcptr)() = NULL;
-  funcptr(); // Crash calling null function pointer
+  Crash();
+  VOID_TO_NPVARIANT(*result);
+  return true;
+}
+
+static bool
+crashOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+  NPP npp = static_cast<TestNPObject*>(npobj)->npp;
+  InstanceData* id = static_cast<InstanceData*>(npp->pdata);
+
+  id->crashOnDestroy = true;
+  VOID_TO_NPVARIANT(*result);
   return true;
 }
 
 static bool
 setColor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
 {
   if (argCount != 1)
     return false;
--- a/modules/plugin/test/testplugin/nptest.h
+++ b/modules/plugin/test/testplugin/nptest.h
@@ -108,11 +108,12 @@ typedef struct InstanceData {
   std::ostringstream err;
   uint16_t streamMode;
   int32_t streamChunkSize;
   int32_t streamBufSize;
   int32_t fileBufSize;
   TestRange* testrange;
   void* streamBuf;
   void* fileBuf;
+  bool crashOnDestroy;
 } InstanceData;
 
 #endif // nptest_h_