c++recursiontreetinyxml

Segmentation Fault when using TinyXML recursively to generate General Tree?


I'm trying to parse an XML file using TinyXML in order to build a General Tree. I'm attempting to do this recursively. The problem is, I'm getting a segmentation fault whenever I do it.

Here is the snippet:

void buildTree() {
        // Loading XML file and getting rootNode
        string filename = "generalTree.xml";
        TiXmlDocument doc(filename);
        bool loadOkay = doc.LoadFile();
        if (!loadOkay) {
            cout << "Could not load file " << filename << endl;
            cout << "Error='" << doc.ErrorDesc() <<"'. Exiting.\n";
        }
        TiXmlNode* generalTreeNode = doc.FirstChild("GeneralTree");
        TiXmlNode* rootNode = generalTreeNode->FirstChild();
        int key = stoi(rootNode->ToElement()->Attribute("key"));
        Type data = rootNode->ToElement()->GetText();
        root = new TreeNode<Type>("General", key, data);
        // Populating the rest of the tree via recursive function
        recFunction(rootNode);
    }

Here is recFunction:

  void recFunction(TiXmlNode *node) {
        if(node->FirstChildElement() == NULL) {
            cout << "First child element is null" << endl;
        } else {
            int key = stoi(node->ToElement()->Attribute("key"));
            Type data = node->ToElement()->GetText();
            TreeNode<Type> *treeNode = new TreeNode<Type>("General", key, data);
            cout << "Right BEFORE recursive activates" << endl;
            return recFunction(node->FirstChild());
        }
        cout << "After recursiveness done" << endl;
        // After recursiveness is finished
        while(node->NextSibling() != NULL) {
            if(!node) {
                cout << "Node is null, breaking" << endl;
                break;
            }
            // Converting XML node to TreeNode
            cout << "DOING NODE TO ELEMENT" << endl;
            cout << node->ToText()->Value() << endl;
            cout << "Node is of type: " << typeid(node).name() << endl;
            cout << node->ToElement()->Attribute("key") << endl;
            cout << "DONE WITH NODE TO ELEMENT" << endl;
            int key = stoi(node->ToElement()->Attribute("key"));
            cout << "Key 1 is: " << key << endl;
            Type data = node->ToElement()->GetText();
            cout << "Data 1 is: " << data << endl;
            TreeNode<Type> *prev = new TreeNode<Type>("General", key, data);
            int key2 = stoi(node->NextSibling()->ToElement()->Attribute("key"));
            Type data2 = node->ToElement()->GetText();
            TreeNode<Type> *cur = new TreeNode<Type>("General", key2, data2);
            // Create linked list of siblings
            prev->setSibling(cur);
            node = node->NextSibling();
        }
        cout << "End of while loop reached" << endl;
    }

And here is the XML file:

<?xml version="1.0"?>
<GeneralTree>
    <Node key="1"> Genres
        <Node key="2">Thriller</Node>
        <Node key="3">Action</Node>
        <Node key="4">Romance
            <Node key="7">A Walk To Remember</Node>
            <Node key="8">The Notebook</Node>
            <Node key="9">Safe Haven</Node>
        </Node>
        <Node key="5">Anime
            <Node key="9">Full Metal Alchemist</Node>
            <Node key="10">Pokemon 2000: The Movie</Node>
        </Node>
    </Node>
    <Node key="12">Genre Sister</Node>
</GeneralTree>

Now, I have isolated the problem to the following lines in recFunction:

    cout << "DOING NODE TO ELEMENT" << endl;
    cout << node->ToText()->Value() << endl;
    cout << "Node is of type: " << typeid(node).name() << endl;
    cout << node->ToElement()->Attribute("key") << endl;
    cout << "DONE WITH NODE TO ELEMENT" << endl;

So I'm assuming node turns null at some point in the recursive function. The problem is I have looked over this again and again and I can't seem to figure out why. The checks in place should prevent node from becoming null.

Here is the output I receive (including the print statements so you can see where it's happening).

Right BEFORE recursive activates
First child element is null
After recursiveness done
DOING NODE TO ELEMENT
Genres
Node is of type: P9TiXmlNode

Thanks in advance!

EDIT: here is what happens when I run gdb and use a breakpoint at

    cout << node->ToText()->Value() << endl;

and cout << node->ToElement()->Attribute("key") << endl;

Right BEFORE recursive activates
First child element is null
After recursiveness done
DOING NODE TO ELEMENT

Breakpoint 1, GeneralTree<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::recFunction (this=0x100300040, node=0x1003005c0)
    at ./GeneralTree.h:70
70              cout << node->ToText()->Value() << endl;
(gdb) c
Continuing.
Genres
Node is of type: P9TiXmlNode

Breakpoint 2, GeneralTree<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::recFunction (this=0x100300040, node=0x1003005c0)
    at ./GeneralTree.h:72
72              cout << node->ToElement()->Attribute("key") << endl;
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
TiXmlAttributeSet::Find (this=0x60, name=0x100018ede "key") at tinyxml.cpp:1527
1527        for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )

Solution

  • There are a number of things, but they all come down to the same conceptual error.

    XML nodes include text, whitespace, and attributes, not just elements.

    So if you intend to recurse over all elements, this is wrong:

     return recFunction(node->FirstChild());
    

    Instead it should be this:

     return recFunction(node->FirstChildElement());
    

    Likewise where you ask for NextSibling you probably want NextSiblingElement.

    For example:

    int key2 = stoi(node->NextSibling()->ToElement()->Attribute("key"));
    

    If NextSibling returns a text node, then ToElement will return null.

    Looking at the SEGV information:

    TiXmlAttributeSet::Find (this=0x60, name=0x100018ede "key") at tinyxml.cpp:1527
    

    This shows the this pointer value of 0x60, which is unlikely to be valid. The most likely way to get such a pointer is by an unchecked pointer adjustment in a type cast of a null pointer. I.e. you have at some point used a null pointer, and either your code or library code has cast it to a related type.

    In this case since node->ToText() succeeded, then node->ToElement() is bound to return null since a node is either a text node or an element node. Therefore the return value of ToElement is null, and calling Attribute on it is an error.