fix crash in mime draft due to un-refcounted nsIChannel, r=protz, bug 692735
authorDavid Bienvenu <bienvenu@nventure.com>
Mon, 17 Oct 2011 06:28:46 -0700
changeset 9503 142afe5421fb2477360880486ac9a73bd31ec034
parent 9502 6feb8945d4e0ad984508b851c96d363e4737daa9
child 9504 fd03acbff68a203b4f1358ae861c3e60b1d6f3e8
push idunknown
push userunknown
push dateunknown
reviewersprotz, bug
bugs692735
fix crash in mime draft due to un-refcounted nsIChannel, r=protz, bug 692735
mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp
mailnews/mime/emitters/src/nsMimeBaseEmitter.h
mailnews/mime/src/mimei.cpp
mailnews/mime/src/mimemoz2.cpp
mailnews/mime/src/mimemoz2.h
mailnews/mime/src/mimemult.cpp
mailnews/mime/src/nsStreamConverter.cpp
--- a/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp
+++ b/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp
@@ -87,17 +87,16 @@ nsMimeBaseEmitter::nsMimeBaseEmitter()
   mFirstHeaders = PR_TRUE;
 
   mBufferMgr = nsnull;
   mTotalWritten = 0;
   mTotalRead = 0;
   mInputStream = nsnull;
   mOutStream = nsnull;
   mOutListener = nsnull;
-  mChannel = nsnull;
 
   // Display output control vars...
   mDocHeader = PR_FALSE;
   m_stringBundle = nsnull;
   mURL = nsnull;
   mHeaderDisplayType = nsMimeHeaderDisplayTypes::NormalHeaders;
 
   // Setup array for attachments
@@ -352,20 +351,17 @@ nsMimeBaseEmitter::SetPipe(nsIInputStrea
 NS_IMETHODIMP
 nsMimeBaseEmitter::Initialize(nsIURI *url, nsIChannel * aChannel, PRInt32 aFormat)
 {
   // set the url
   mURL = url;
   mChannel = aChannel;
 
   // Create rebuffering object
-  if (mBufferMgr)
-  {
-    delete mBufferMgr;
-  }
+  delete mBufferMgr;
   mBufferMgr = new MimeRebuffer();
 
   // Counters for output stream
   mTotalWritten = 0;
   mTotalRead = 0;
   mFormat = aFormat;
 
   return NS_OK;
--- a/mailnews/mime/emitters/src/nsMimeBaseEmitter.h
+++ b/mailnews/mime/emitters/src/nsMimeBaseEmitter.h
@@ -134,17 +134,17 @@ protected:
 
   // mscott
   // don't ref count the streams....the emitter is owned by the converter
   // which owns these streams...
   //
   nsIOutputStream     *mOutStream;
   nsIInputStream      *mInputStream;
   nsIStreamListener   *mOutListener;
-  nsIChannel          *mChannel;
+  nsCOMPtr<nsIChannel> mChannel;
 
   // For gathering statistics on processing...
   PRUint32            mTotalWritten;
   PRUint32            mTotalRead;
 
   // Output control and info...
   bool                mDocHeader;         // For header determination...
   nsIURI              *mURL;              // the url for the data being processed...
--- a/mailnews/mime/src/mimei.cpp
+++ b/mailnews/mime/src/mimei.cpp
@@ -403,17 +403,17 @@ void getMsgHdrForCurrentURL(MimeDisplayO
 
   if (!opts)
     return;
 
   mime_stream_data *msd = (mime_stream_data *) (opts->stream_closure);
   if (!msd)
     return;
 
-  nsIChannel *channel = msd->channel;  // note the lack of ref counting...
+  nsCOMPtr<nsIChannel> channel = msd->channel;  // note the lack of ref counting...
   if (channel)
   {
     nsCOMPtr<nsIURI> uri;
     nsCOMPtr<nsIMsgMessageUrl> msgURI;
     channel->GetURI(getter_AddRefs(uri));
     if (uri)
     {
       msgURI = do_QueryInterface(uri);
--- a/mailnews/mime/src/mimemoz2.cpp
+++ b/mailnews/mime/src/mimemoz2.cpp
@@ -105,16 +105,22 @@ static NS_DEFINE_CID(kParserCID, NS_PARS
 #endif
 
 void                 ValidateRealName(nsMsgAttachmentData *aAttach, MimeHeaders *aHdrs);
 
 static MimeHeadersState MIME_HeaderType;
 static bool MIME_WrapLongLines;
 static bool MIME_VariableWidthPlaintext;
 
+mime_stream_data::mime_stream_data() : url_name(nsnull), orig_url_name(nsnull),
+  pluginObj2(nsnull), istream(nsnull), obj(nsnull), options(nsnull),
+  headers(nsnull), output_emitter(nsnull), firstCheck(false)
+{
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Attachment handling routines
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //
 MimeObject    *mime_get_main_object(MimeObject* obj);
 
 nsresult
 ProcessBodyAsAttachment(MimeObject *obj, nsMsgAttachmentData **data)
@@ -917,17 +923,17 @@ mime_convert_charset (const char *input_
 
   return 0;
 }
 
 static int
 mime_output_fn(const char *buf, PRInt32 size, void *stream_closure)
 {
   PRUint32  written = 0;
-  struct mime_stream_data *msd = (struct mime_stream_data *) stream_closure;
+  mime_stream_data *msd = (mime_stream_data *) stream_closure;
   if ( (!msd->pluginObj2) && (!msd->output_emitter) )
     return -1;
 
   // Fire pending start request
   ((nsStreamConverter*)msd->pluginObj2)->FirePendingStartRequest();
 
 
   // Now, write to the WriteBody method if this is a message body and not
@@ -950,17 +956,17 @@ mime_output_fn(const char *buf, PRInt32 
   return written;
 }
 
 extern "C" int
 mime_display_stream_write (nsMIMESession *stream,
                            const char* buf,
                            PRInt32 size)
 {
-  struct mime_stream_data *msd = (struct mime_stream_data *) ((nsMIMESession *)stream)->data_object;
+  mime_stream_data *msd = (mime_stream_data *) ((nsMIMESession *)stream)->data_object;
 
   MimeObject *obj = (msd ? msd->obj : 0);
   if (!obj) return -1;
 
   //
   // Ok, now check to see if this is a display operation for a MIME Parts on Demand
   // enabled call.
   //
@@ -988,17 +994,17 @@ mime_display_stream_write (nsMIMESession
   }
 
   return obj->clazz->parse_buffer((char *) buf, size, obj);
 }
 
 extern "C" void
 mime_display_stream_complete (nsMIMESession *stream)
 {
-  struct mime_stream_data *msd = (struct mime_stream_data *) ((nsMIMESession *)stream)->data_object;
+  mime_stream_data *msd = (mime_stream_data *) ((nsMIMESession *)stream)->data_object;
   MimeObject *obj = (msd ? msd->obj : 0);
   if (obj)
   {
     int       status;
     bool      abortNow = false;
 
     if ((obj->options) && (obj->options->headers == MimeHeadersOnly))
       abortNow = PR_TRUE;
@@ -1043,23 +1049,23 @@ mime_display_stream_complete (nsMIMESess
     MimeHeaders_free (msd->headers);
 
   if (msd->url_name)
     NS_Free(msd->url_name);
 
   if (msd->orig_url_name)
       NS_Free(msd->orig_url_name);
 
-  PR_FREEIF(msd);
+  delete msd;
 }
 
 extern "C" void
 mime_display_stream_abort (nsMIMESession *stream, int status)
 {
-  struct mime_stream_data *msd = (struct mime_stream_data *) ((nsMIMESession *)stream)->data_object;
+  mime_stream_data *msd = (mime_stream_data *) ((nsMIMESession *)stream)->data_object;
 
   MimeObject *obj = (msd ? msd->obj : 0);
   if (obj)
   {
     if (!obj->closed_p)
       obj->clazz->parse_eof(obj, PR_TRUE);
     if (!obj->parsed_p)
       obj->clazz->parse_end(obj, PR_TRUE);
@@ -1078,28 +1084,28 @@ mime_display_stream_abort (nsMIMESession
     MimeHeaders_free (msd->headers);
 
   if (msd->url_name)
     NS_Free(msd->url_name);
 
   if (msd->orig_url_name)
       NS_Free(msd->orig_url_name);
 
-  PR_FREEIF(msd);
+  delete msd;
 }
 
 static int
 mime_output_init_fn (const char *type,
                      const char *charset,
                      const char *name,
                      const char *x_mac_type,
                      const char *x_mac_creator,
                      void *stream_closure)
 {
-  struct mime_stream_data *msd = (struct mime_stream_data *) stream_closure;
+  mime_stream_data *msd = (mime_stream_data *) stream_closure;
 
   // Now, all of this stream creation is done outside of libmime, so this
   // is just a check of the pluginObj member and returning accordingly.
   if (!msd->pluginObj2)
     return -1;
   else
     return 0;
 }
@@ -1112,17 +1118,17 @@ static int    mime_image_write_buffer(co
 
 /* Interface between libmime and inline display of images: the abomination
    that is known as "internal-external-reconnect".
  */
 class mime_image_stream_data {
 public:
   mime_image_stream_data();
 
-  struct mime_stream_data *msd;
+  mime_stream_data *msd;
   char                    *url;
   nsMIMESession           *istream;
   nsCOMPtr<nsIOutputStream> memCacheOutputStream;
   bool m_shouldCacheImage;
 };
 
 mime_image_stream_data::mime_image_stream_data()
 {
@@ -1131,17 +1137,17 @@ mime_image_stream_data::mime_image_strea
   msd = nsnull;
   m_shouldCacheImage = PR_FALSE;
 }
 
 static void *
 mime_image_begin(const char *image_url, const char *content_type,
                  void *stream_closure)
 {
-  struct mime_stream_data *msd = (struct mime_stream_data *) stream_closure;
+  mime_stream_data *msd = (mime_stream_data *) stream_closure;
   class mime_image_stream_data *mid;
 
   mid = new mime_image_stream_data;
   if (!mid) return nsnull;
 
 
   mid->msd = msd;
 
@@ -1265,17 +1271,17 @@ mime_image_make_image_html(void *image_c
   return buf;
 }
 
 static int
 mime_image_write_buffer(const char *buf, PRInt32 size, void *image_closure)
 {
   mime_image_stream_data *mid =
                 (mime_image_stream_data *) image_closure;
-  struct mime_stream_data *msd = mid->msd;
+  mime_stream_data *msd = mid->msd;
 
   if ( ( (!msd->output_emitter) ) &&
        ( (!msd->pluginObj2)     ) )
     return -1;
 
   //
   // If we get here, we are just eating the data this time around
   // and the returned URL will deal with writing the data to the viewer.
@@ -1506,23 +1512,23 @@ mime_bridge_create_display_stream(
                           nsStreamConverter   *newPluginObj2,
                           nsIURI              *uri,
                           nsMimeOutputType    format_out,
                           PRUint32            whattodo,
                           nsIChannel          *aChannel)
 {
   int                       status = 0;
   MimeObject                *obj;
-  struct mime_stream_data   *msd;
+  mime_stream_data   *msd;
   nsMIMESession             *stream = 0;
 
   if (!uri)
     return nsnull;
 
-  msd = PR_NEWZAP(struct mime_stream_data);
+  msd = new mime_stream_data;
   if (!msd)
     return NULL;
 
   // Assign the new mime emitter - will handle output operations
   msd->output_emitter = newEmitter;
   msd->firstCheck = PR_TRUE;
 
   // Store the URL string for this decode operation
@@ -1534,50 +1540,50 @@ mime_bridge_create_display_stream(
   rv = uri->GetSpec(urlString);
   if (NS_SUCCEEDED(rv))
   {
     if (!urlString.IsEmpty())
     {
       msd->url_name = ToNewCString(urlString);
       if (!(msd->url_name))
       {
-        PR_FREEIF(msd);
+        delete msd;
         return NULL;
       }
       nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(uri);
       if (msgUrl)
           msgUrl->GetOriginalSpec(&msd->orig_url_name);
     }
   }
 
   msd->format_out = format_out;       // output format
   msd->pluginObj2 = newPluginObj2;    // the plugin object pointer
 
   msd->options = new MimeDisplayOptions;
   if (!msd->options)
   {
-    PR_Free(msd);
+    delete msd;
     return 0;
   }
 //  memset(msd->options, 0, sizeof(*msd->options));
   msd->options->format_out = format_out;     // output format
 
   msd->options->m_prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv))
   {
-    PR_FREEIF(msd);
+    delete msd;
     return nsnull;
   }
 
   // Need the text converter...
   rv = CallCreateInstance(MOZ_TXTTOHTMLCONV_CONTRACTID, &(msd->options->conv));
   if (NS_FAILED(rv))
   {
     msd->options->m_prefBranch = 0;
-    PR_FREEIF(msd);
+    delete msd;
     return nsnull;
   }
 
   //
   // Set the defaults, based on the context, and the output-type.
   //
   MIME_HeaderType = MimeHeadersAll;
   msd->options->write_html_p = PR_TRUE;
@@ -1649,17 +1655,17 @@ mime_bridge_create_display_stream(
 
   // We need to have the URL to be able to support the various
   // arguments
   status = mime_parse_url_options(msd->url_name, msd->options);
   if (status < 0)
   {
     PR_FREEIF(msd->options->part_to_load);
     PR_Free(msd->options);
-    PR_Free(msd);
+    delete msd;
     return 0;
   }
 
   if (msd->options->headers == MimeHeadersMicro &&
      (msd->url_name == NULL || (strncmp(msd->url_name, "news:", 5) != 0 &&
               strncmp(msd->url_name, "snews:", 6) != 0)) )
     msd->options->headers = MimeHeadersMicroPlus;
 
@@ -1686,31 +1692,31 @@ mime_bridge_create_display_stream(
   // (i.e. embedded images)
   if (msd->options->part_to_load && msd->options->format_out != nsMimeOutput::nsMimeMessageBodyDisplay)
     msd->options->write_html_p = PR_FALSE;
 
   obj = mime_new ((MimeObjectClass *)&mimeMessageClass, (MimeHeaders *) NULL, MESSAGE_RFC822);
   if (!obj)
   {
     delete msd->options;
-    PR_Free(msd);
+    delete msd;
     return 0;
   }
 
   obj->options = msd->options;
   msd->obj = obj;
 
   /* Both of these better not be true at the same time. */
   PR_ASSERT(! (obj->options->decrypt_p && obj->options->write_html_p));
 
   stream = PR_NEW(nsMIMESession);
   if (!stream)
   {
     delete msd->options;
-    PR_Free(msd);
+    delete msd;
     PR_Free(obj);
     return 0;
   }
 
   ResetMsgHeaderSinkProps(uri);
 
   memset (stream, 0, sizeof (*stream));
   stream->name           = "MIME Conversion Stream";
@@ -1721,17 +1727,17 @@ mime_bridge_create_display_stream(
 
   status = obj->clazz->initialize(obj);
   if (status >= 0)
     status = obj->clazz->parse_begin(obj);
   if (status < 0)
   {
     PR_Free(stream);
     delete msd->options;
-    PR_Free(msd);
+    delete msd;
     PR_Free(obj);
     return 0;
   }
 
   return stream;
 }
 
 //
--- a/mailnews/mime/src/mimemoz2.h
+++ b/mailnews/mime/src/mimemoz2.h
@@ -107,22 +107,25 @@ struct _nsMIMESession {
     MKSessionAbortFunc       abort;            /* abnormal end */
 
     bool                    is_multipart;    /* is the stream part of a multipart sequence */
 };
 
 /*
  * This is for the reworked mime parser.
  */
-struct mime_stream_data {           /* This struct is the state we pass around
+class mime_stream_data {           /* This object is the state we pass around
                                        amongst the various stream functions
                                        used by MIME_MessageConverter(). */
+public:
+  mime_stream_data();
+
   char                *url_name;
   char                *orig_url_name; /* original url name */
-  nsIChannel          *channel;
+  nsCOMPtr<nsIChannel> channel;
   nsMimeOutputType    format_out;
   void                *pluginObj2;  /* The new XP-COM stream converter object */
   nsMIMESession       *istream;     /* Holdover - new stream we're writing out image data-if any. */
   MimeObject          *obj;         /* The root parser object */
   MimeDisplayOptions  *options;     /* Data for communicating with libmime.a */
   MimeHeaders         *headers;     /* Copy of outer most mime header */
 
   nsIMimeEmitter      *output_emitter;  /* Output emitter engine for libmime */
--- a/mailnews/mime/src/mimemult.cpp
+++ b/mailnews/mime/src/mimemult.cpp
@@ -518,17 +518,17 @@ MimeMultipart_create_child(MimeObject *o
   if (body->output_p)
   {  
     status = body->clazz->parse_begin(body);
 
 #ifdef XP_MACOSX
     /* if we are saving an apple double attachment, we need to set correctly the conten type of the channel */
     if (mime_typep(obj, (MimeObjectClass *) &mimeMultipartAppleDoubleClass))
     {
-      struct mime_stream_data *msd = (struct mime_stream_data *)body->options->stream_closure;
+      mime_stream_data *msd = (smime_stream_data *)body->options->stream_closure;
       if (!body->options->write_html_p && body->content_type && !PL_strcasecmp(body->content_type, APPLICATION_APPLEFILE))
       {
         if (msd && msd->channel)
           msd->channel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_APPLEFILE));
       }
     }
 #endif
 
--- a/mailnews/mime/src/nsStreamConverter.cpp
+++ b/mailnews/mime/src/nsStreamConverter.cpp
@@ -115,17 +115,17 @@ bridge_destroy_stream(void *newStream)
 void
 bridge_set_output_type(void *bridgeStream, nsMimeOutputType aType)
 {
   nsMIMESession *session = (nsMIMESession *)bridgeStream;
 
   if (session)
   {
     // BAD ASSUMPTION!!!! NEED TO CHECK aType
-    struct mime_stream_data *msd = (struct mime_stream_data *)session->data_object;
+    mime_stream_data *msd = (mime_stream_data *)session->data_object;
     if (msd)
       msd->format_out = aType;     // output format type
   }
 }
 
 nsresult
 bridge_new_new_uri(void *bridgeStream, nsIURI *aURI, PRInt32 aOutputType)
 {
@@ -148,17 +148,17 @@ bridge_new_new_uri(void *bridgeStream, n
         {
           default_charset = &(mdd->options->default_charset);
           override_charset = &(mdd->options->override_charset);
           url_name = &(mdd->url_name);
         }
       }
       else
       {
-        struct mime_stream_data *msd = (struct mime_stream_data *)session->data_object;
+        mime_stream_data *msd = (mime_stream_data *)session->data_object;
 
         if (msd->options)
         {
           default_charset = &(msd->options->default_charset);
           override_charset = &(msd->options->override_charset);
           url_name = &(msd->url_name);
           fixup_pointer = &(msd->options->url);
         }
@@ -253,17 +253,17 @@ bridge_new_new_uri(void *bridgeStream, n
 
   return NS_OK;
 }
 
 static int
 mime_headers_callback ( void *closure, MimeHeaders *headers )
 {
   // We get away with this because this doesn't get called on draft operations.
-  struct mime_stream_data *msd = (struct mime_stream_data *)closure;
+  mime_stream_data *msd = (mime_stream_data *)closure;
 
   NS_ASSERTION(msd && headers, "null mime stream data or headers");
   if ( !msd || ! headers )
     return 0;
 
   NS_ASSERTION(!msd->headers, "non-null mime stream data headers");
   msd->headers = MimeHeaders_copy ( headers );
   return 0;
@@ -292,17 +292,17 @@ bridge_set_mime_stream_converter_listene
         {
           mdd->options->caller_need_root_headers = PR_FALSE;
           mdd->options->decompose_headers_info_fn = nsnull;
         }
       }
     }
     else
     {
-      struct mime_stream_data *msd = (struct mime_stream_data *)session->data_object;
+      mime_stream_data *msd = (mime_stream_data *)session->data_object;
 
       if (msd->options)
       {
         if (listener)
         {
           msd->options->caller_need_root_headers = PR_TRUE;
           msd->options->decompose_headers_info_fn = mime_headers_callback;
         }
@@ -1059,17 +1059,17 @@ nsStreamConverter::OnStopRequest(nsIRequ
             (mOutputType == nsMimeOutput::nsMimeMessageEditorTemplate) )
       {
         mime_draft_data *mdd = (mime_draft_data *)tSession->data_object;
         if (mdd)
           workHeaders = &(mdd->headers);
       }
       else
       {
-        struct mime_stream_data *msd = (struct mime_stream_data *)tSession->data_object;
+        mime_stream_data *msd = (mime_stream_data *)tSession->data_object;
         if (msd)
           workHeaders = &(msd->headers);
       }
 
       if (workHeaders)
       {
         nsresult rv;
         nsCOMPtr<nsIMimeHeaders> mimeHeaders = do_CreateInstance(NS_IMIMEHEADERS_CONTRACTID, &rv);