Merge of backout for 8e2ff18bc67e, bug 554524
authorJosh Aas <joshmoz@gmail.com>
Wed, 09 Jun 2010 01:26:01 -0400
changeset 43374 6d425b6517d6eaac6deda295f02a8541c443bb82
parent 43372 86cdcd6616de9dd4ea522a52b7bcb418bbc4803e (current diff)
parent 43373 9c15f02468dc9a99486ddc5ee1a377e973951038 (diff)
child 43375 bef54ce2c671490a17c8dbaca2194a6380df9039
push idunknown
push userunknown
push dateunknown
bugs554524
milestone1.9.3a5pre
Merge of backout for 8e2ff18bc67e, bug 554524
--- a/modules/plugin/base/src/nsNPAPIPluginInstance.cpp
+++ b/modules/plugin/base/src/nsNPAPIPluginInstance.cpp
@@ -199,76 +199,92 @@ nsNPAPIPluginStreamListener::nsNPAPIPlug
     mCallNotify(PR_FALSE),
     mIsSuspended(PR_FALSE),
     mIsPluginInitJSStream(mInst->mInPluginInitCall &&
                           aURL && strncmp(aURL, "javascript:",
                                           sizeof("javascript:") - 1) == 0),
     mResponseHeaderBuf(nsnull)
 {
   memset(&mNPStream, 0, sizeof(mNPStream));
+
+  NS_IF_ADDREF(mInst);
 }
 
-nsNPAPIPluginStreamListener::~nsNPAPIPluginStreamListener()
+nsNPAPIPluginStreamListener::~nsNPAPIPluginStreamListener(void)
 {
+  // remove itself from the instance stream list
+  nsNPAPIPluginInstance *inst = mInst;
+  if (inst) {
+    nsInstanceStream * prev = nsnull;
+    for (nsInstanceStream *is = inst->mStreams; is != nsnull; is = is->mNext) {
+      if (is->mPluginStreamListener == this) {
+        if (!prev)
+          inst->mStreams = is->mNext;
+        else
+          prev->mNext = is->mNext;
+
+        delete is;
+        break;
+      }
+      prev = is;
+    }
+  }
+
   // For those cases when NewStream is never called, we still may need
   // to fire a notification callback. Return network error as fallback
   // reason because for other cases, notify should have already been
   // called for other reasons elsewhere.
   CallURLNotify(NPRES_NETWORK_ERR);
 
   // lets get rid of the buffer
   if (mStreamBuffer) {
     PR_Free(mStreamBuffer);
     mStreamBuffer=nsnull;
   }
 
+  NS_IF_RELEASE(inst);
+
   if (mNotifyURL)
     PL_strfree(mNotifyURL);
 
   if (mResponseHeaderBuf)
     PL_strfree(mResponseHeaderBuf);
 }
 
 nsresult nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
 {
-  // We must null out the instance (mInst) before this method completes but
-  // after all of its code has run.
-
   nsresult rv = NS_ERROR_FAILURE;
 
-  if (mStreamCleanedUp || !mInst)
+  if (mStreamCleanedUp)
     return NS_OK;
 
   mStreamCleanedUp = PR_TRUE;
 
   StopDataPump();
 
   // Seekable streams have an extra addref when they are created which must
   // be matched here.
   if (NP_SEEK == mStreamType)
     NS_RELEASE_THIS();
 
-  if (!mInst->CanFireNotifications()) {
-    mInst = nsnull;
+  if (!mInst || !mInst->CanFireNotifications())
     return rv;
-  }
 
   mStreamInfo = NULL;
 
   PluginDestructionGuard guard(mInst);
 
   const NPPluginFuncs *callbacks = nsnull;
   mInst->GetCallbacks(&callbacks);
-  if (!callbacks) {
-    mInst = nsnull;
+  if (!callbacks)
     return rv;
-  }
 
   NPP npp;
   mInst->GetNPP(&npp);
+
   if (mStreamStarted && callbacks->destroystream) {
     NPPAutoPusher nppPusher(npp);
 
     PluginLibrary* lib = nsnull;
     lib = mInst->mLibrary;
     NPError error;
     NS_TRY_SAFE_CALL_RETURN(error, (*callbacks->destroystream)(npp, &mNPStream, reason), lib, mInst);
 
@@ -280,18 +296,16 @@ nsresult nsNPAPIPluginStreamListener::Cl
       rv = NS_OK;
   }
 
   mStreamStarted = PR_FALSE;
 
   // fire notification back to plugin, just like before
   CallURLNotify(reason);
 
-  mInst = nsnull;
-
   return rv;
 }
 
 void nsNPAPIPluginStreamListener::CallURLNotify(NPReason reason)
 {
   if (!mCallNotify || !mInst || !mInst->CanFireNotifications())
     return;
 
@@ -300,16 +314,17 @@ void nsNPAPIPluginStreamListener::CallUR
   mCallNotify = PR_FALSE; // only do this ONCE and prevent recursion
 
   const NPPluginFuncs *callbacks = nsnull;
   mInst->GetCallbacks(&callbacks);
   if (!callbacks)
     return;
   
   if (callbacks->urlnotify) {
+
     NPP npp;
     mInst->GetNPP(&npp);
 
     NS_TRY_SAFE_CALL_VOID((*callbacks->urlnotify)(npp, mNotifyURL, reason, mNotifyData), mInst->mLibrary, mInst);
 
     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     ("NPP URLNotify called: this=%p, npp=%p, notify=%p, reason=%d, url=%s\n",
     this, npp, mNotifyData, reason, mNotifyURL));
@@ -453,21 +468,18 @@ nsNPAPIPluginStreamListener::StopDataPum
   }
 }
 
 // Return true if a javascript: load that was started while the plugin
 // was being initialized is still in progress.
 PRBool
 nsNPAPIPluginStreamListener::PluginInitJSLoadInProgress()
 {
-  if (!mInst)
-    return PR_FALSE;
-
-  for (unsigned int i = 0; i < mInst->mStreams.Length(); i++) {
-    if (mInst->mStreams[i]->mIsPluginInitJSStream) {
+  for (nsInstanceStream *is = mInst->mStreams; is; is = is->mNext) {
+    if (is->mPluginStreamListener->mIsPluginInitJSStream) {
       return PR_TRUE;
     }
   }
 
   return PR_FALSE;
 }
 
 // This method is called when there's more data available off the
@@ -856,16 +868,26 @@ nsNPAPIPluginStreamListener::NewResponse
 {
   mResponseHeaders.Append(headerName);
   mResponseHeaders.Append(": ");
   mResponseHeaders.Append(headerValue);
   mResponseHeaders.Append('\n');
   return NS_OK;
 }
 
+nsInstanceStream::nsInstanceStream()
+{
+  mNext = nsnull;
+  mPluginStreamListener = nsnull;
+}
+
+nsInstanceStream::~nsInstanceStream()
+{
+}
+
 NS_IMPL_ISUPPORTS1(nsNPAPIPluginInstance, nsIPluginInstance)
 
 nsNPAPIPluginInstance::nsNPAPIPluginInstance(NPPluginFuncs* callbacks,
                                              PluginLibrary* aLibrary)
   : mCallbacks(callbacks),
 #ifdef XP_MACOSX
 #ifdef NP_NO_QUICKDRAW
     mDrawingModel(NPDrawingModelCoreGraphics),
@@ -891,20 +913,27 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
   // Initialize the NPP structure.
 
   mNPP.pdata = NULL;
   mNPP.ndata = this;
 
   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
 }
 
-nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
+nsNPAPIPluginInstance::~nsNPAPIPluginInstance(void)
 {
   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
 
+  // clean the stream list if any
+  for (nsInstanceStream *is = mStreams; is != nsnull;) {
+    nsInstanceStream * next = is->mNext;
+    delete is;
+    is = next;
+  }
+
   if (mMIMEType) {
     PR_Free((void *)mMIMEType);
     mMIMEType = nsnull;
   }
 }
 
 TimeStamp
 nsNPAPIPluginInstance::LastStopTime()
@@ -970,20 +999,29 @@ NS_IMETHODIMP nsNPAPIPluginInstance::Sto
   EnterAsyncPluginThreadCallLock();
   mRunning = DESTROYING;
   mStopTime = TimeStamp::Now();
   ExitAsyncPluginThreadCallLock();
 
   OnPluginDestroy(&mNPP);
 
   // clean up open streams
-  for (unsigned int i = 0; i < mStreams.Length(); i++) {
-    mStreams[i]->CleanUpStream(NPRES_USER_BREAK);
+  for (nsInstanceStream *is = mStreams; is != nsnull;) {
+    nsRefPtr<nsNPAPIPluginStreamListener> listener = is->mPluginStreamListener;
+
+    nsInstanceStream *next = is->mNext;
+    delete is;
+    is = next;
+    mStreams = is;
+
+    // Clean up our stream after removing it from the list because 
+    // it may be released and destroyed at this point.
+    if (listener)
+      listener->CleanUpStream(NPRES_USER_BREAK);
   }
-  mStreams.Clear();
 
   NPError error = NPERR_GENERIC_ERROR;
   if (mCallbacks->destroy) {
     NPSavedData *sdata = 0;
 
     NS_TRY_SAFE_CALL_RETURN(error, (*mCallbacks->destroy)(&mNPP, &sdata), mLibrary, this);
 
     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
@@ -1253,20 +1291,33 @@ nsNPAPIPluginInstance::NewStreamFromPlug
 nsresult nsNPAPIPluginInstance::NewNotifyStream(nsIPluginStreamListener** listener, 
                                                 void* notifyData,
                                                 PRBool aCallNotify,
                                                 const char* aURL)
 {
   nsNPAPIPluginStreamListener* stream = new nsNPAPIPluginStreamListener(this, notifyData, aURL);
   NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY);
 
-  mStreams.AppendElement(stream);
+  // add it to the list
+  nsInstanceStream * is = new nsInstanceStream();
+  NS_ENSURE_TRUE(is, NS_ERROR_OUT_OF_MEMORY);
+
+  is->mNext = mStreams;
+  is->mPluginStreamListener = stream;
+  mStreams = is;
   stream->SetCallNotify(aCallNotify); // set flag in stream to call URLNotify
 
-  return stream->QueryInterface(kIPluginStreamListenerIID, (void**)listener);
+  NS_ADDREF(stream); // Stabilize
+    
+  nsresult res = stream->QueryInterface(kIPluginStreamListenerIID, (void**)listener);
+
+  // Destabilize and avoid leaks. Avoid calling delete <interface pointer>
+  NS_RELEASE(stream);
+
+  return res;
 }
 
 NS_IMETHODIMP nsNPAPIPluginInstance::Print(NPPrint* platformPrint)
 {
   NS_ENSURE_TRUE(platformPrint, NS_ERROR_NULL_POINTER);
 
   PluginDestructionGuard guard(this);
 
--- a/modules/plugin/base/src/nsNPAPIPluginInstance.h
+++ b/modules/plugin/base/src/nsNPAPIPluginInstance.h
@@ -36,32 +36,40 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsNPAPIPluginInstance_h_
 #define nsNPAPIPluginInstance_h_
 
 #include "nsCOMPtr.h"
-#include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "nsIPlugin.h"
 #include "nsIPluginInstance.h"
 #include "nsIPluginTagInfo.h"
 #include "nsPIDOMWindow.h"
 #include "nsIPluginInstanceOwner.h"
 #include "nsITimer.h"
 #include "mozilla/TimeStamp.h"
 
 #include "npfunctions.h"
 #include "mozilla/PluginLibrary.h"
 
 class nsNPAPIPluginStreamListener;
 class nsPIDOMWindow;
 
+struct nsInstanceStream
+{
+  nsInstanceStream *mNext;
+  nsNPAPIPluginStreamListener *mPluginStreamListener;
+
+  nsInstanceStream();
+  ~nsInstanceStream();
+};
+
 class nsNPAPITimer
 {
 public:
   NPP npp;
   uint32_t id;
   nsCOMPtr<nsITimer> timer;
   void (*callback)(NPP npp, uint32_t timerID);
 };
@@ -167,17 +175,17 @@ protected:
   PRPackedBool mTransparent;
   PRPackedBool mCached;
   PRPackedBool mWantsAllNetworkStreams;
 
 public:
   // True while creating the plugin, or calling NPP_SetWindow() on it.
   PRPackedBool mInPluginInitCall;
   PluginLibrary* mLibrary;
-  nsTArray< nsRefPtr<nsNPAPIPluginStreamListener> > mStreams;
+  nsInstanceStream *mStreams;
 
 private:
   nsTArray<PopupControlState> mPopupStates;
 
   char* mMIMEType;
 
   // Weak pointer to the owner. The owner nulls this out (by calling
   // InvalidateOwner()) when it's no longer our owner.
--- a/modules/plugin/base/src/nsNPAPIPluginStreamListener.h
+++ b/modules/plugin/base/src/nsNPAPIPluginStreamListener.h
@@ -80,17 +80,17 @@ public:
   void StopDataPump();
 
   PRBool PluginInitJSLoadInProgress();
 
 protected:
   void* mNotifyData;
   char* mStreamBuffer;
   char* mNotifyURL;
-  nsNPAPIPluginInstance* mInst; // weak, can be NULL
+  nsNPAPIPluginInstance* mInst;
   NPStream mNPStream;
   PRUint32 mStreamBufferSize;
   PRInt32 mStreamBufferByteCount;
   PRInt32 mStreamType;
   PRPackedBool mStreamStarted;
   PRPackedBool mStreamCleanedUp;
   PRPackedBool mCallNotify;
   PRPackedBool mIsSuspended;