From 9a8178ca3b79143dbd784fc35139d84cd403680f Mon Sep 17 00:00:00 2001 From: Michael Andres Date: Mon, 20 Mar 2006 21:28:35 +0000 Subject: [PATCH] - fixed memory leak in XMLNodeIterator (#157474) - disabled storing filelist (YUMFileListParser) and changelog (YUMOtherParser) --- zypp/base/Debug.h | 117 ++++++++++++----------------- zypp/base/ReferenceCounted.h | 15 +++- zypp/parser/XMLNodeIterator.h | 140 +++++++++++++++++------------------ zypp/parser/yum/YUMFileListParser.cc | 32 ++++---- zypp/parser/yum/YUMOtherParser.cc | 32 ++++---- 5 files changed, 163 insertions(+), 173 deletions(-) diff --git a/zypp/base/Debug.h b/zypp/base/Debug.h index cca201e..fb29f21 100644 --- a/zypp/base/Debug.h +++ b/zypp/base/Debug.h @@ -16,9 +16,11 @@ #include #include +#include #include "zypp/base/Logger.h" -//#include "zypp/base/PtrTypes.h" -//#include "zypp/ResObject.h" +#include "zypp/base/String.h" +#include "zypp/ExternalProgram.h" +#include "zypp/base/ProvideNumericId.h" /////////////////////////////////////////////////////////////////// namespace zypp @@ -32,6 +34,27 @@ namespace zypp #define TAG INT << __PRETTY_FUNCTION__ << std::endl + /** 'ps v' */ + inline std::ostream & dumpMemOn( std::ostream & str, const std::string & msg = std::string() ) + { + static std::string mypid( str::numstring( getpid() ) ); + const char* argv[] = + { + "ps", + "v", + mypid.c_str(), + NULL + }; + ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); + + str << "MEMUSAGE " << msg << std::endl; + for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() ) + str << line; + + prog.close(); + return str; + } + /////////////////////////////////////////////////////////////////// /** \defgroup DBG_TRACER Tracer * \ingroup DEBUG @@ -46,10 +69,6 @@ namespace zypp std::string _ident; }; - /** \relates TraceCADBase Stream output. */ - inline std::ostream & operator<<( std::ostream & str, const TraceCADBase & obj ) - { return str << obj._ident << "[" << &obj << "] "; } - /** \relates TraceCADBase Stream output of TraceCADBase::What. */ inline std::ostream & operator<<( std::ostream & str, TraceCADBase::What obj ) { @@ -85,25 +104,39 @@ namespace zypp * \see \c Example.COW_debug.cc. */ template - struct TraceCAD : public TraceCADBase + struct TraceCAD : public base::ProvideNumericId, unsigned long> + , public TraceCADBase { + static unsigned long & _totalTraceCAD() + { static unsigned long _val = 0; + return _val; } + TraceCAD() { _ident = __PRETTY_FUNCTION__; + ++_totalTraceCAD(); traceCAD( CTOR, *this, *this ); } TraceCAD( const TraceCAD & rhs ) - { traceCAD( COPYCTOR, *this, rhs ); } + { ++_totalTraceCAD(); + traceCAD( COPYCTOR, *this, rhs ); } TraceCAD & operator=( const TraceCAD & rhs ) { traceCAD( ASSIGN, *this, rhs ); return *this; } virtual ~TraceCAD() - { traceCAD( DTOR, *this, *this ); } + { --_totalTraceCAD(); + traceCAD( DTOR, *this, *this ); } void _PING() const { traceCAD( PING, *this, *this ); } }; + /** \relates TraceCAD Stream output. */ + template + inline std::ostream & operator<<( std::ostream & str, const TraceCAD<_Tp> & obj ) + { return str << "(ID " << obj.numericId() << ", TOTAL " << obj._totalTraceCAD() + << ") [" << &obj << "] "; } + /** Drop a log line about the traced method. Overload to * fit your needs. */ @@ -115,78 +148,20 @@ namespace zypp switch( what_r ) { case TraceCADBase::CTOR: - case TraceCADBase::DTOR: case TraceCADBase::PING: - std::cerr << self_r << what_r << std::endl; + case TraceCADBase::DTOR: + std::cerr << what_r << self_r << " (" << self_r._ident << ")" << std::endl; break; + case TraceCADBase::COPYCTOR: case TraceCADBase::ASSIGN: - std::cerr << self_r << what_r << "( " << rhs_r << ")" << std::endl; + std::cerr << what_r << self_r << "( " << rhs_r << ")" << " (" << self_r._ident << ")" << std::endl; break; } } //@} /////////////////////////////////////////////////////////////////// -#if 0 - /////////////////////////////////////////////////////////////////// - /** \defgroup DBG_FAKED_RESOLVABLES Faked Resolvables - * \ingroup DEBUG - * \code - * // parse or fill in the values: - * std::string _name; - * Edition _edition; - * Arch _arch; - * Dependencies _deps; - * // Create a faked ResObject claiming to be a Package: - * ResObject::Ptr ptr( debug::fakeResObject( _name, _edition, _arch, Dependencies() ) ); - * \endcode - */ - //@{ - /** Implementation of faked Resolvable. */ - class ResObjectFakeImpl : public detail::ResObjectImplIf - { - virtual Label summary() const - { - std::ostringstream str; - str << "FAKED " << *self(); - return str.str(); - } - }; - - /** Faked Resolvable. - * Template argument defines the kind of Resolvable. - */ - template - class ResObjectFake : public ResObject - { - public: - ResObjectFake( const std::string & name_r, - const Edition & edition_r, - const Arch & arch_r ) - : ResObject( ResTraits<_Res>::kind, name_r, edition_r, arch_r ) - {} - }; - - /** Faked Resolvable factory function. - * Provide ready to use NVRA and Dependencies. - */ - template - ResObject::Ptr fakeResObject( const std::string & name_r, - const Edition & edition_r, - const Arch & arch_r, - const Dependencies & deps_r ) - { - using detail::_resobjectfactory_detail::ResImplConnect; - shared_ptr impl( new ResObjectFakeImpl ); - ResObject::Ptr ret( new ResImplConnect > - ( name_r, edition_r, arch_r, impl ) ); - ret->setDeps( deps_r ); - return ret; - } - //@} - /////////////////////////////////////////////////////////////////// -#endif ///////////////////////////////////////////////////////////////// } // namespace debug /////////////////////////////////////////////////////////////////// diff --git a/zypp/base/ReferenceCounted.h b/zypp/base/ReferenceCounted.h index f0972eb..9ec2b02 100644 --- a/zypp/base/ReferenceCounted.h +++ b/zypp/base/ReferenceCounted.h @@ -64,7 +64,7 @@ namespace zypp /** Add a reference. */ void ref() const - { ++_counter; } + { ref_to( ++_counter ); } /** Release a reference. * Deletes the object if reference count gets zero. @@ -74,7 +74,9 @@ namespace zypp { if ( !_counter ) unrefException(); // will throw! - if ( --_counter == 0 ) + if ( --_counter ) + unref_to( _counter ); + else delete this; } @@ -94,6 +96,15 @@ namespace zypp /** Overload to realize std::ostream & operator\<\<. */ virtual std::ostream & dumpOn( std::ostream & str ) const; + /** Trigger derived classes after refCount was increased. */ + virtual void ref_to( unsigned /* rep_cnt_r */ ) const {} + + /** Trigger derived classes after refCount was decreased. + * No trigger is sent, if refCount got zero (i.e. the + * object is deleted). + **/ + virtual void unref_to( unsigned /* rep_cnt_r */ ) const {} + private: /** The reference counter. */ mutable unsigned _counter; diff --git a/zypp/parser/XMLNodeIterator.h b/zypp/parser/XMLNodeIterator.h index c87da51..07422bc 100644 --- a/zypp/parser/XMLNodeIterator.h +++ b/zypp/parser/XMLNodeIterator.h @@ -38,8 +38,8 @@ extern "C" { namespace zypp { namespace parser { - - + + /** * @short class for reporting syntax errors in XMLNodeIterator. */ @@ -53,54 +53,54 @@ namespace zypp { xmlTextReaderLocatorPtr locator, int docLine, int docColumn) throw(); - + ~XMLParserError() throw(); - + /** * The message of the errors */ std::string msg() const throw(); - + /** * The severity of this error */ int severity() const throw(); - + /** * See libxml2 documentation */ xmlTextReaderLocatorPtr locator() const throw(); - + /** * The line number in the xml document where the error occurred. */ int docLine() const throw(); - + /** * The column number in the xml document where the error occurred. */ int docColumn() const throw(); - + /** * Gives a string describing the position in the xml document. * (either empty, or "at line ..., column ...") **/ std::string position() const throw(); - + private: - + std::string _msg; int _severity; xmlTextReaderLocatorPtr _locator; int _docLine; int _docColumn; }; - - + + std::ostream& operator<<(std::ostream &out, const XMLParserError& error); - - - + + + /** * * @short Abstract class to iterate over an xml stream @@ -128,8 +128,8 @@ namespace zypp { * continue parsing, XMLNodeIterator will log it and consider the input as finished. * You can query the exit status with errorStatus(). */ - - + + class XMLNodeIteratorBase { public: /** @@ -138,29 +138,29 @@ namespace zypp { * @param baseUrl is the base URL of the xml document * FIXME: use XMLParserError::operator<< instead of doing it on my own. */ - XMLNodeIteratorBase(std::istream &input, + XMLNodeIteratorBase(std::istream &input, const std::string &baseUrl, const char *validationPath = 0); - + /** * Constructor for an empty iterator. * An empty iterator is already at its end. * This is what end() returns ... */ XMLNodeIteratorBase(); - + /** * Destructor */ virtual ~XMLNodeIteratorBase(); - + /** * Have we reached the end? * A parser error also means "end reached" * @return whether the end has been reached. */ bool atEnd() const; - + /** * Two iterators are equal if both are at the end * or if they are identical. @@ -169,20 +169,20 @@ namespace zypp { * @param other the other iterator * @return true if equal */ - bool + bool operator==(const XMLNodeIteratorBase &other) const; - + /** * Opposit of operator== * @param other the other iterator * @return true if not equal */ - bool + bool operator!=(const XMLNodeIteratorBase &otherNode) const { return ! operator==(otherNode); } - + /** * returns the error status or 0 if no error * the returned pointer is not-owning, @@ -191,9 +191,9 @@ namespace zypp { */ const XMLParserError * errorStatus() const; - + protected: - + /** * filter for the xml nodes * The derived class decides which xml nodes it is actually interested in. @@ -207,14 +207,14 @@ namespace zypp { */ virtual bool isInterested(const xmlNodePtr nodePtr) = 0; - + /** * process an xml node and set it as next element * The derived class has to produce the ENTRYTYPE object here. * Details about the xml reader is in the libxml2 documentation. * You'll most probably want to use xmlTextReaderExpand(reader) to - * request the full subtree, and then use the links in the resulting - * node structure to traverse, and class LibXMLHelper to access the + * request the full subtree, and then use the links in the resulting + * node structure to traverse, and class LibXMLHelper to access the * attributes and element contents. * fetchNext() cannot throw an error since it will be called in the constructor. * Instead, in case of a fundamental syntax error the error is saved @@ -223,12 +223,12 @@ namespace zypp { */ virtual void _process(const xmlTextReaderPtr readerPtr) = 0; - + /** * Fetch the next element and save it as next element */ void fetchNext(); - + /** * Internal function to set the _error variable * in case of a parser error. It logs the message @@ -244,55 +244,55 @@ namespace zypp { const char * msg, int severity, xmlTextReaderLocatorPtr locator); - - + + virtual void setCurrent(const void *data) = 0; virtual void* getCurrent() const = 0; - + private: - + /** * assignment is forbidden. * Reason: We can't copy an xmlTextReader */ XMLNodeIteratorBase & operator=(const XMLNodeIteratorBase& otherNode); - + /** * copy constructor is forbidden. * Reason: We can't copy an xmlTextReader * FIXME: This prevents implementing the end() method for derived classes. - * - * @param otherNode - * @return + * + * @param otherNode + * @return */ XMLNodeIteratorBase(const XMLNodeIteratorBase& otherNode); - + /** * if an error occured, this contains the error. */ std::auto_ptr _error; - + /** * contains the istream to read the xml file from. * Can be 0 if at end or if the current element is the only element left. **/ std::istream* _input; - + /** * contains the xmlTextReader used to parse the xml file. **/ xmlTextReaderPtr _reader; - + /** * contains the base URL of the xml documentation */ std::string _baseUrl; }; /* end class XMLNodeIteratorBase */ - - - + + + /* --------------------------------------------------------------------------- */ - + template class XMLNodeIterator : public XMLNodeIteratorBase, public std::iterator { @@ -312,8 +312,8 @@ namespace zypp { XMLNodeIterator has no access to their virtual functions during construction */ } - - + + /** * Constructor for a trivial iterator. * A trivial iterator contains only one element. @@ -323,10 +323,10 @@ namespace zypp { */ XMLNodeIterator(ENTRYTYPE &entry) : XMLNodeIteratorBase() - { + { setCurrent((void *)& entry); } - + /** * Constructor for an empty iterator. * An empty iterator is already at its end. @@ -335,13 +335,13 @@ namespace zypp { XMLNodeIterator() : XMLNodeIteratorBase(), _current(0) { } - + /** * Destructor */ virtual ~XMLNodeIterator() { } - + /** * Fetch a pointer to the current element * @return pointer to the current element. @@ -352,7 +352,7 @@ namespace zypp { assert (! atEnd()); return * (ENTRYTYPE *) getCurrent(); } - + /** * Fetch the current element * @return the current element @@ -365,7 +365,7 @@ namespace zypp { else return getCurrent(); } - + /** * Go to the next element and return it * @return the next element @@ -375,7 +375,7 @@ namespace zypp { fetchNext(); return *this; } - + /** * remember the current element, go to next and return remembered one. * avoid this, usually you need the preinc operator (++iter) @@ -390,7 +390,7 @@ namespace zypp { fetchNext(); return tmp; } - + /** * similar to operator*, allows direct member access * @return pointer to current element @@ -401,9 +401,9 @@ namespace zypp { xml_assert(! atEnd()); return getCurrent(); } - + protected: - + /** * filter for the xml nodes * The derived class decides which xml nodes it is actually interested in. @@ -417,7 +417,7 @@ namespace zypp { */ virtual bool isInterested(const xmlNodePtr nodePtr) = 0; - + /** * process an xml node * The derived class has to produce the ENTRYTYPE object here. @@ -434,15 +434,15 @@ namespace zypp { */ virtual ENTRYTYPE process(const xmlTextReaderPtr readerPtr) = 0; - + void _process(const xmlTextReaderPtr readerPtr) { - setCurrent(new ENTRYTYPE(process(readerPtr))); + _current.reset( new ENTRYTYPE(process(readerPtr))); } - + private: - + void setCurrent(const void *data) { if (data) @@ -450,12 +450,12 @@ namespace zypp { else _current.reset(0); } - + void *getCurrent() const { return _current.get(); } - + /** * contains the current element of the iterator. * a pointer is used to be able to handle non-assigneable ENTRYTYPEs. @@ -464,7 +464,7 @@ namespace zypp { **/ std::auto_ptr _current; }; /* end class XMLNodeIterator */ - + } } diff --git a/zypp/parser/yum/YUMFileListParser.cc b/zypp/parser/yum/YUMFileListParser.cc index d50b9d5..ef92d7f 100644 --- a/zypp/parser/yum/YUMFileListParser.cc +++ b/zypp/parser/yum/YUMFileListParser.cc @@ -37,33 +37,33 @@ namespace zypp { { fetchNext(); } - + YUMFileListParser::YUMFileListParser() { } - + YUMFileListParser::YUMFileListParser(YUMFileListData_Ptr& entry) : XMLNodeIterator(entry) { } - - - + + + YUMFileListParser::~YUMFileListParser() { } - - - - + + + + // select for which elements process() will be called - bool + bool YUMFileListParser::isInterested(const xmlNodePtr nodePtr) { bool result = (_helper.isElement(nodePtr) && _helper.name(nodePtr) == "package"); return result; } - - + + // do the actual processing YUMFileListData_Ptr YUMFileListParser::process(const xmlTextReaderPtr reader) @@ -72,11 +72,11 @@ namespace zypp { YUMFileListData_Ptr dataPtr = new YUMFileListData; xmlNodePtr dataNode = xmlTextReaderExpand(reader); xml_assert(dataNode); - + dataPtr->pkgId = _helper.attribute(dataNode,"pkgid"); dataPtr->name = _helper.attribute(dataNode,"name"); dataPtr->arch = _helper.attribute(dataNode,"arch"); - + for (xmlNodePtr child = dataNode->children; child != 0; child = child->next) { @@ -88,9 +88,11 @@ namespace zypp { dataPtr->rel = _helper.attribute(child,"rel"); } else if (name == "file") { +#if 0 dataPtr->files.push_back (FileData(_helper.content(child), _helper.attribute(child,"type"))); +#endif } else { WAR << "YUM contains the unknown element <" << name << "> " @@ -100,7 +102,7 @@ namespace zypp { } return dataPtr; } - + } // namespace yum } // namespace parser diff --git a/zypp/parser/yum/YUMOtherParser.cc b/zypp/parser/yum/YUMOtherParser.cc index c7a69c8..5f0b1a2 100644 --- a/zypp/parser/yum/YUMOtherParser.cc +++ b/zypp/parser/yum/YUMOtherParser.cc @@ -34,33 +34,33 @@ namespace zypp { { fetchNext(); } - + YUMOtherParser::YUMOtherParser() { } - + YUMOtherParser::YUMOtherParser(YUMOtherData_Ptr& entry) : XMLNodeIterator(entry) { } - - - + + + YUMOtherParser::~YUMOtherParser() { } - - - - + + + + // select for which elements process() will be called - bool + bool YUMOtherParser::isInterested(const xmlNodePtr nodePtr) { bool result = (_helper.isElement(nodePtr) && _helper.name(nodePtr) == "package"); return result; } - - + + // do the actual processing YUMOtherData_Ptr YUMOtherParser::process(const xmlTextReaderPtr reader) @@ -69,11 +69,11 @@ namespace zypp { YUMOtherData_Ptr dataPtr = new YUMOtherData; xmlNodePtr dataNode = xmlTextReaderExpand(reader); xml_assert(dataNode); - + dataPtr->pkgId = _helper.attribute(dataNode,"pkgid"); dataPtr->name = _helper.attribute(dataNode,"name"); dataPtr->arch = _helper.attribute(dataNode,"arch"); - + for (xmlNodePtr child = dataNode->children; child != 0; child = child->next) { @@ -85,10 +85,12 @@ namespace zypp { dataPtr->rel = _helper.attribute(child,"rel"); } else if (name == "changelog") { +#if 0 dataPtr->changelog.push_back (ChangelogEntry(_helper.attribute(child,"author"), _helper.attribute(child,"date"), _helper.content(child))); +#endif } else if (name == "license_to_confirm") { @@ -102,7 +104,7 @@ namespace zypp { } return dataPtr; } - + } // namespace yum } // namespace parser } // namespace zypp -- 2.7.4