Dear Xalan developers,

I believe there is a bug in the NamedNodeMapAttributeList constructor: an
assertion fails if the attribute map is empty.

The assertion prevents me from serializing this to XML:
<page>
  <paragraph>
  </paragraph>
</page>

Please find below excerpts from the relevant source code, a stack trace, a
patch, example code that triggers the assertion.

(Studying Xalan's SVN history, it seems the bug was introduced in late June,
2008. Also, as far as I've seen, there must be two nested tags with no
attributes for the bug to appear. --- Perhaps that's why this has not been
fixed before.)

Regards,
Magnus


--------------------------------------------
Excerpt from relevant source code
--------------------------------------------

http://svn.apache.org/repos/asf/xalan/c/trunk/src/xalanc/PlatformSupport/NamedNodeMapAttributeList.cpp

NamedNodeMapAttributeList::NamedNodeMapAttributeList(
            const XalanNamedNodeMap&    theMap,
            MemoryManagerType&          theManager) :
    ParentType(),
    m_nodeMap(theMap),
    m_lastIndex(theMap.getLength() - 1),
    m_memoryManager(theManager)
{
    assert(theMap.getLength() != 0);  <-- fails
}


trunk\xml-xalan\c\src\xalanc\xmlsupport\formattertreewalker.cpp:

FormatterTreeWalker::startNode(const XalanNode*        node)
    :
    :
    case XalanNode::ELEMENT_NODE:
        {
            const XalanElement*    theElementNode =
#if defined(XALAN_OLD_STYLE_CASTS)
                (const XalanElement*)node;
#else
                static_cast<const XalanElement*>(node);
#endif

            const XalanNamedNodeMap*    atts =
theElementNode->getAttributes();
            assert(atts != 0);

            NamedNodeMapAttributeList    theAttributeList(*atts,
m_memoryManager);  <--- above assertion means that there *must* be an
attribute?


m_formatterListener.startElement(c_wstr(theElementNode->getNodeName()),
                                             theAttributeList);
        }
        break;
    :
    :

--------------------------------------------
Stack trace
--------------------------------------------

msvcr80d.dll!_wassert(const wchar_t * expr=0x095aa254, const wchar_t *
filename=0x095aa290, unsigned int lineno=56)  Line 384    C
Xalan-C_1_10D.dll!xalanc_1_10::NamedNodeMapAttributeList::NamedNodeMapAttributeList(const
xalanc_1_10::XalanNamedNodeMap & theMap={...}, xercesc_3_0::MemoryManager &
theManager={...})  Line 56 + 0x2e bytes    C++
Xalan-C_1_10D.dll!xalanc_1_10::FormatterTreeWalker::startNode(const
xalanc_1_10::XalanNode * node=0x09ff07e8)  Line 89 + 0x13 bytes    C++
Xalan-C_1_10D.dll!xalanc_1_10::TreeWalker::traverse(const
xalanc_1_10::XalanNode * pos=0x09ff07e8, const xalanc_1_10::XalanNode *
parent=0x09fee6c0)  Line 159 + 0x13 bytes    C++
Xalan-C_1_10D.dll!xalanc_1_10::TreeWalker::traverseSubtree(const
xalanc_1_10::XalanNode * pos=0x09fee6c0)  Line 265    C++
my-test-program.exe!XmlPageBuilder_tests::Xalan_assertion::test_method()
Line 39 + 0x15 bytes    C++

--------------------------------------------
Patch? (Removing assertion, setting index to 0)
--------------------------------------------
Index: NamedNodeMapAttributeList.cpp
===================================================================
--- NamedNodeMapAttributeList.cpp    (revision 679080)
+++ NamedNodeMapAttributeList.cpp    (working copy)
@@ -50,10 +50,10 @@
             MemoryManagerType&          theManager) :
     ParentType(),
     m_nodeMap(theMap),
-    m_lastIndex(theMap.getLength() - 1),
+    m_lastIndex(theMap.getLength() > 0 ? theMap.getLength() - 1 : 0),
     m_memoryManager(theManager)
 {
-    assert(theMap.getLength() != 0);
+    //assert(theMap.getLength() != 0); -- no, allow 0
 }


--------------------------------------------
Example code that reproduces the crash
--------------------------------------------

XalanTransformer oXalanTransformer;
XalanDocumentBuilder* pBuilder = oXalanTransformer.createDocumentBuilder();
ContentHandler* pContentHandler = pBuilder->getContentHandler();

AttributesImpl xAttributes;
const XalanDOMChar xNullChar = 0;

pContentHandler->startDocument();
pContentHandler->startElement( & xNullChar, & xNullChar, L"page",
xAttributes );
pContentHandler->startElement( & xNullChar, & xNullChar, L"paragraph",
xAttributes ); // nested tag required for assertion to fail
pContentHandler->endElement( & xNullChar, & xNullChar, L"paragraph" );
pContentHandler->endElement( & xNullChar, & xNullChar, L"page" );
pContentHandler->endDocument();

_STL::stringstream sstream;
XalanStdOutputStream xStream( sstream );
XalanOutputStreamPrintWriter xPrintWriter( xStream );
FormatterToXML xFormatter( xPrintWriter );
FormatterTreeWalker oTreeWalker( xFormatter );

const XalanNode* const    pFunctionNode =
pBuilder->getDocument()->getFirstChild();

xFormatter.setShouldWriteXMLHeader(false);
xFormatter.startDocument(); // (required)
oTreeWalker.traverseSubtree( pFunctionNode );
xFormatter.endDocument();

Reply via email to