Backed out changeset 8e2ff18bc67e
authorJosh Aas <joshmoz@gmail.com>
Wed, 09 Jun 2010 01:25:11 -0400
changeset 43373 9c15f02468dc9a99486ddc5ee1a377e973951038
parent 43361 8e2ff18bc67e3a14decbad48b3f5f9f057919ea0
child 43374 6d425b6517d6eaac6deda295f02a8541c443bb82
push idunknown
push userunknown
push dateunknown
milestone1.9.3a5pre
backs out8e2ff18bc67e3a14decbad48b3f5f9f057919ea0
Backed out changeset 8e2ff18bc67e
modules/plugin/base/src/nsNPAPIPluginInstance.cpp
modules/plugin/base/src/nsNPAPIPluginInstance.h
modules/plugin/base/src/nsNPAPIPluginStreamListener.h
--- 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;