Bug 397804. pages loading feeds as content can trigger a leak. r=jst, sr=sicking, a=sicking
authorsayrer@gmail.com
Thu, 27 Sep 2007 20:00:35 -0700
changeset 6389 145ad92b817656500404589193b40840b13c193b
parent 6388 8952cbb842073e439e6bda02912d1b41165a239b
child 6390 e5182a66c316a85350072b6746695239cdf29e53
push idunknown
push userunknown
push dateunknown
reviewersjst, sicking, sicking
bugs397804
milestone1.9a9pre
Bug 397804. pages loading feeds as content can trigger a leak. r=jst, sr=sicking, a=sicking
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
parser/xml/src/nsSAXXMLReader.cpp
parser/xml/src/nsSAXXMLReader.h
toolkit/components/feeds/src/FeedProcessor.js
--- a/parser/htmlparser/src/nsParser.cpp
+++ b/parser/htmlparser/src/nsParser.cpp
@@ -284,20 +284,36 @@ nsParser::~nsParser()
   }
 
   // It should not be possible for this flag to be set when we are getting
   // destroyed since this flag implies a pending nsParserContinueEvent, which
   // has an owning reference to |this|.
   NS_ASSERTION(!(mFlags & NS_PARSER_FLAG_PENDING_CONTINUE_EVENT), "bad");
 }
 
-NS_IMPL_ISUPPORTS3(nsParser,
-                   nsIRequestObserver,
-                   nsIParser,
-                   nsIStreamListener)
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsParser)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsParser)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSink)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mObserver)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsParser)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSink)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObserver)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsParser, nsIParser)
+NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsParser, nsIParser)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsParser)
+ NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
+ NS_INTERFACE_MAP_ENTRY(nsIParser)
+ NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParser)
+NS_INTERFACE_MAP_END
 
 // The parser continue event is posted only if
 // all of the data to parse has been passed to ::OnDataAvailable
 // and the parser has been interrupted by the content sink
 // because the processing of tokens took too long.
 
 nsresult
 nsParser::PostContinueEvent()
--- a/parser/htmlparser/src/nsParser.h
+++ b/parser/htmlparser/src/nsParser.h
@@ -83,16 +83,17 @@
 #include "nsHTMLTags.h"
 #include "nsDTDUtils.h"
 #include "nsTimer.h"
 #include "nsThreadUtils.h"
 #include "nsIContentSink.h"
 #include "nsIParserFilter.h"
 #include "nsCOMArray.h"
 #include "nsIUnicharStreamListener.h"
+#include "nsCycleCollectionParticipant.h"
 
 class nsIDTD;
 class nsScanner;
 class nsIProgressEventSink;
 
 #ifdef _MSC_VER
 #pragma warning( disable : 4275 )
 #endif
@@ -109,18 +110,18 @@ class nsParser : public nsIParser,
      */
     static nsresult Init();
 
     /**
      * Called on module shutdown
      */
     static void Shutdown();
 
-    NS_DECL_ISUPPORTS
-
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsParser, nsIParser)
 
     /**
      * default constructor
      * @update	gess5/11/98
      */
     nsParser();
 
 
--- a/parser/xml/src/nsSAXXMLReader.cpp
+++ b/parser/xml/src/nsSAXXMLReader.cpp
@@ -47,20 +47,46 @@
 #include "nsSAXAttributes.h"
 #include "nsSAXLocator.h"
 #include "nsSAXXMLReader.h"
 
 #define XMLNS_URI "http://www.w3.org/2000/xmlns/"
 
 static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
 
-NS_IMPL_ISUPPORTS6(nsSAXXMLReader, nsISAXXMLReader,
-                   nsIExpatSink, nsIExtendedExpatSink,
-                   nsIContentSink,  nsIRequestObserver,
-                   nsIStreamListener)
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsSAXXMLReader)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsSAXXMLReader)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContentHandler)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDTDHandler)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mErrorHandler)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLexicalHandler)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBaseURI)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListener)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParserObserver)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsSAXXMLReader)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContentHandler)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDTDHandler)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mErrorHandler)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLexicalHandler)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBaseURI)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListener)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParserObserver)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsSAXXMLReader, nsISAXXMLReader)
+NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsSAXXMLReader, nsISAXXMLReader)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSAXXMLReader)
+  NS_INTERFACE_MAP_ENTRY(nsISAXXMLReader)
+  NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
+  NS_INTERFACE_MAP_ENTRY(nsIExtendedExpatSink)
+  NS_INTERFACE_MAP_ENTRY(nsIContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISAXXMLReader)
+NS_INTERFACE_MAP_END
 
 nsSAXXMLReader::nsSAXXMLReader() : mIsAsyncParse(PR_FALSE)
 {
 }
 
 // nsIContentSink
 NS_IMETHODIMP
 nsSAXXMLReader::WillBuildModel()
--- a/parser/xml/src/nsSAXXMLReader.h
+++ b/parser/xml/src/nsSAXXMLReader.h
@@ -43,29 +43,31 @@
 #include "nsIExtendedExpatSink.h"
 #include "nsIParser.h"
 #include "nsIURI.h"
 #include "nsISAXXMLReader.h"
 #include "nsISAXContentHandler.h"
 #include "nsISAXDTDHandler.h"
 #include "nsISAXErrorHandler.h"
 #include "nsISAXLexicalHandler.h"
+#include "nsCycleCollectionParticipant.h"
 
 #define NS_SAXXMLREADER_CONTRACTID "@mozilla.org/saxparser/xmlreader;1"
 #define NS_SAXXMLREADER_CLASSNAME "SAX XML Reader"
 #define NS_SAXXMLREADER_CID  \
 { 0xab1da296, 0x6125, 0x40ba, \
 { 0x96, 0xd0, 0x47, 0xa8, 0x28, 0x2a, 0xe3, 0xdb} }
 
 class nsSAXXMLReader : public nsISAXXMLReader,
                        public nsIExtendedExpatSink,
                        public nsIContentSink
 {
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsSAXXMLReader, nsISAXXMLReader)
   NS_DECL_NSIEXPATSINK
   NS_DECL_NSIEXTENDEDEXPATSINK
   NS_DECL_NSISAXXMLREADER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
 
   nsSAXXMLReader();
 
--- a/toolkit/components/feeds/src/FeedProcessor.js
+++ b/toolkit/components/feeds/src/FeedProcessor.js
@@ -1069,16 +1069,17 @@ function FeedProcessor() {
   this._feed = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2);
   this._handlerStack = [];
   this._xmlBaseStack = []; // sparse array keyed to nesting depth
   this._depth = 0;
   this._state = "START";
   this._result = null;
   this._extensionHandler = null;
   this._xhtmlHandler = null;
+  this._haveSentResult = false;
   
   // http://www.w3.org/WAI/PF/GUI/ uses QNames in content :(
   this._waiPrefixes = {};
 
   // The nsIFeedResultListener waiting for the parse results
   this.listener = null;
 
   // These elements can contain (X)HTML or plain text.
@@ -1257,16 +1258,17 @@ FeedProcessor.prototype = {
       this._xmlBaseStack[this._xmlBaseStack.length - 1];
     this._result.doc.fields = this._feed;
     this._result.version = version;
   },
 
   // When we're done with the feed, let the listener know what
   // happened.
   _sendResult: function FP_sendResult() {
+    this._haveSentResult = true;
     try {
       // Can be null when a non-feed is fed to us
       if (this._result.doc)
         this._result.doc.normalize();
     }
     catch (e) {
       LOG("FIXME: " + e);
     }
@@ -1326,27 +1328,29 @@ FeedProcessor.prototype = {
   // We only care about fatal errors. When this happens, we may have
   // parsed through the feed metadata and some number of entries. The
   // listener can still show some of that data if it wants, and we'll
   // set the bozo bit to indicate we were unable to parse all the way
   // through.
   fatalError: function FP_reportError() {
     this._result.bozo = true;
     //XXX need to QI to FeedProgressListener
-    this._sendResult();
+    if (!this._haveSentResult)
+      this._sendResult();
   },
 
   // nsISAXContentHandler
 
   startDocument: function FP_startDocument() {
     //LOG("----------");
   },
 
   endDocument: function FP_endDocument() {
-    this._sendResult();
+    if (!this._haveSentResult)
+      this._sendResult();
   },
 
   // The transitions defined above identify elements that contain more
   // than just text. For example RSS items contain many fields, and so
   // do Atom authors. The only commonly used elements that contain
   // mixed content are Atom Text Constructs of type="xhtml", which we
   // delegate to another handler for cleaning. That leaves a couple
   // different types of elements to deal with: those that should occur