views:

504

answers:

3

I've been playing around with the Xerces-C XML library.

I have this simple example I'm playing with.

I can't seem to get it to run without leaking memory and without segfaulting. It's one or the other.

The segfault always occurs when I delete the parser object under "Clean up".

I've tried using both the 2.8 & 2.7 versions of the library.

Note: I took all of the exception checking out of the code, I get the same results with it and without it. For readability and simplicity I removed it from the code below.

Any Xerces-savvy people out there care to make some suggestions?

I can't really tell much from the back trace, it's just jumping down into the superclass destructor and segfaulting there.

Backtrace:

(gdb) bt
#0  0x9618ae42 in __kill ()
#1  0x9618ae34 in kill$UNIX2003 ()
#2  0x961fd23a in raise ()
#3  0x96209679 in abort ()
#4  0x95c5c005 in __gnu_cxx::__verbose_terminate_handler ()
#5  0x95c5a10c in __gxx_personality_v0 ()
#6  0x95c5a14b in std::terminate ()
#7  0x95c5a6da in __cxa_pure_virtual ()
#8  0x003e923e in xercesc_2_8::AbstractDOMParser::cleanUp ()
#9  0x003ead2a in xercesc_2_8::AbstractDOMParser::~AbstractDOMParser ()
#10 0x0057022d in xercesc_2_8::XercesDOMParser::~XercesDOMParser ()
#11 0x000026c9 in main (argc=2, argv=0xbffff460) at test.C:77

The code:

#include <string>
#include <vector> 

#if defined(XERCES_NEW_IOSTREAMS)
#include <iostream>
#else
#include <iostream.h>
#endif

#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>

using namespace std;

XERCES_CPP_NAMESPACE_USE

int main(int argc, char const* argv[])
{

  string skXmlMetadata = "<?xml version=\"1.0\"?>\n <xmlMetadata>b</xmlMetadata>";

  XMLPlatformUtils::Initialize();
  XercesDOMParser* xmlParser = NULL;
  DOMWriter* xmlWriter = NULL; 
  ErrorHandler* errHandler = NULL;
  const XMLByte* xmlBuf =  NULL;
  MemBufInputSource* memBufIS = NULL;
  DOMNode* xmlDoc = NULL;

  xmlParser = new XercesDOMParser();
  xmlParser->setValidationScheme( XercesDOMParser::Val_Never );
  xmlParser->setDoNamespaces( false );
  xmlParser->setDoSchema( false );
  xmlParser->setLoadExternalDTD( false );

  errHandler = (ErrorHandler*) new HandlerBase();
  xmlParser->setErrorHandler( errHandler );

  // Create buffer for current xmlMetadata
  xmlBuf = (const XMLByte*) skXmlMetadata.c_str();
  const char* bufID = "XmlMetadata";
  memBufIS = new MemBufInputSource( xmlBuf, skXmlMetadata.length(), bufID, false );

  // Parse
  xmlParser->resetErrors();
  xmlParser->parse( *memBufIS );
  xmlDoc = xmlParser->getDocument();

  // Write created xml to input SkArray
  XMLCh* metadata = NULL;
  xmlWriter = DOMImplementation::getImplementation()->createDOMWriter();
  xmlWriter->setFeature( XMLUni::fgDOMWRTFormatPrettyPrint, true );
  metadata = xmlWriter->writeToString( *xmlDoc );
  xmlWriter->release();


  // Print out our parsed document
  char* xmlMetadata = XMLString::transcode( metadata );
  string c = xmlMetadata;
  cout << c << endl;

  // Clean up
  XMLString::release( &xmlMetadata );
  xmlDoc->release();
  delete xmlParser; // Dies here
  delete memBufIS;
  delete errHandler;
  XMLPlatformUtils::Terminate();

  return 0;
}
+1  A: 

Lets explore the evidence...

#6  0x95c5a14b in std::terminate ()

I can tell you this is called when a destructor throws an exception. Destructors throwing exceptions is a big no-no. Xerces may be doing something wonky.

Or it might be caused by this line

#7  0x95c5a6da in __cxa_pure_virtual ()

where something might be missing in a virtual function table. Perhaps one of the DOM object's members destructor? Perhaps this generates an exception?

This link offers a great explanation on what might cause the virtual table lookups to fail. In short, it can be caused by a dangling base-class pointer hanging around someone trying to make a polymorphic function call on that pointer.

Example given from the link above:

// From sample program 5:
AbstractShape* p1 = new Rectangle(width, height, valuePerSquareUnit);
std::cout << "value = " << p1->value() << std::endl;
AbstractShape* p2 = p1;  // Need another copy of the pointer.
delete p1;
std::cout << "now value = " << p2->value() << std::endl;

Speaking of dangling pointers, it looks like the XercesDomParser is holding objects you newed:

  errHandler = (ErrorHandler*) new HandlerBase();
  xmlParser->setErrorHandler( errHandler )

but later deleted/released

  // Clean up
  XMLString::release( &xmlMetadata );
  xmlDoc->release();
  delete xmlParser;
  delete memBufIS;
  delete errHandler;

Could the order you are destroying things be incorrect and cause some of the above problems? On the face of it, things look OK, but that's where I would experiment and double check the documentation on how things are supposed to be torn down.

Doug T.
Xerces parsers do not own their error handlers and will not delete them.
anon
I tried a try/catch block around the delete of xmlParser before I asked the question, as @Doug T mentioned no exceptions are thrown.
Brian Gianforcaro
A: 

I can't see anything obviously wrong with the code. You might like to try removing all the uses of new & delete in the code and create the Cerces objects you use as stack based objectys instead. For example, instead of:

xmlParser = new XercesDOMParser();

use:

XercesDOMParser xmlParser;

and so on.

anon
Tried that, still segfaults in the deconstructor of the stack based XercesDOMParser :(
Brian Gianforcaro
+1  A: 

" xmlDoc->release(); " is the culprit. You dont own that Node unless you say " xmlParser->adoptDocument() "

http://xerces.apache.org/xerces-c/apiDocs-2/classAbstractDOMParser.html#fe052561c37d70b62ac57ab6706d75aa

Thanks, Shiva

Shiva
Wow, awesome catch. That was totally the problem. Thanks!
Brian Gianforcaro