c++xmlqtqxmlstreamreader

Qt QXmlStreamReader Access Violation


I am using Qt 5.11.1(MSVSC2015 32bit) and QtCreator 4.6.2. I am having trouble parsing XML with QXmlStreamReader. Code is written based on Qt's example. When my code is executed it produces access violation in QIODevice.cpp in checkWarnMessage function. This image shows call stack and exact line where access violation occurred.

The actual XML i more complex and has nested elements. Functions that parse XML are implemented same way as void XbelReader::readXBEL() function from Qt's example (based on element name appropriate function is called to parse that element). But with this simple example I have managed to reproduce problem I have in actual solution.

XML is:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <element1>1</element1>
    <element2>2</element2>
    <element3>3</element3>
    <element4>4</element4>
    <element5>5</element5>
    <element6>6</element6>
</root>

Code that parses this XML is:

#include <string>
#include <stdexcept>
#include <iostream>

#include <QCoreApplication>
#include <QXmlStreamReader>
#include <QFile>
#include <QString>

#define ASSERT_ELEMENT_NAME(NAME) Q_ASSERT(xmlReader.isStartElement() && xmlReader.name() == NAME);

using namespace std;

void OpenFile(const QString& fileName, QXmlStreamReader& xmlReader)
{
    QFile configFile(fileName);
    if (configFile.open(QFile::ReadOnly | QFile::Text) == false)
        throw runtime_error(string("Failed to open file: ") + configFile.errorString().toStdString());

    xmlReader.setDevice(&configFile);
    if (xmlReader.readNextStartElement() == false)
        throw runtime_error("File does not have root element");

    if (xmlReader.name() != "root")
        throw runtime_error("File has invalid root element");
}

void ParseElement1(QXmlStreamReader& xmlReader)
{
    ASSERT_ELEMENT_NAME("element1");

    auto text = xmlReader.readElementText().trimmed();
    auto isOk = false;
    auto value = text.toInt(&isOk);

    if (isOk == false)
        throw runtime_error(string("invalid value: ") + text.toStdString());
    else
        cout << "element1: " << value << endl;
}

void ParseElement2(QXmlStreamReader& xmlReader)
{
    ASSERT_ELEMENT_NAME("element2");

    auto text = xmlReader.readElementText().trimmed();
    auto isOk = false;
    auto value = text.toInt(&isOk);

    if (isOk == false)
        throw runtime_error(string("invalid value: ") + text.toStdString());
    else
        cout << "element2: " << value << endl;
}

int main()
{
    QXmlStreamReader xmlReader;

    OpenFile("config.xml", xmlReader);

    while(xmlReader.readNextStartElement())
    {
        if(xmlReader.name() == "element1")
            ParseElement1(xmlReader);
        if(xmlReader.name() == "element2")
            ParseElement2(xmlReader);
        else
            xmlReader.skipCurrentElement();
    }
}

If I comment two lines in main function:

        if(xmlReader.name() == "element2")
            ParseElement2(xmlReader);

access violation does not happen.

I really can't figure out what am I doing wrong. Or is there a bug in QXmlStreamReader? I think that even in case I did something wrong, access violation should not happen in Qt's library.

Entire project (XmlParser.pro, main.cpp and config.xml) can be downloaded from this link

EDIT

I have fixed my example as Manthan suggested and it worked as expected. I have added one more thing to the XML. I have added large multiline comment before element1. Comment itself has 8019 characters, including whitespace characters, whereas entire XML file has 8266 characters.

XML now looks like

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <!--
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, 
    comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment, comment,
    comment, comment, co
    -->
    <element1>1</element1>
    <element2>2</element2>
    <element3>3</element3>
    <element4>4</element4>
    <element5>5</element5>
    <element6>6</element6>
</root>

I have checked that XML is valid in Notepad++ with XML Tools plugin and also on xmlvalidation.xml. When I execute fixed example with new XML, again I have access violation on exact same place depicted on previously linked image.

Now, if I remove last "o" character from comment in XML(or any other character from comment, or e.g. "6" from text of element6, or as a matter of fact any character from XML while keeping XML valid), example is executed successfully. And this is my original problem. I have a lot of comments in my original XML file, resulting file to be larger that 8KB. For now, as a workaround, I remove comments to avoid access violation.

It is not clear to me how does comment (or file) length causes access violation.

Entire project can be downloaded from this link


Solution

  • Problem is within while loop. Update it as below.

    while(xmlReader.readNextStartElement())
    {
        if(xmlReader.name() == "element1")
            ParseElement1(xmlReader);
        else if(xmlReader.name() == "element2")
            ParseElement2(xmlReader);
        else
            xmlReader.skipCurrentElement();
    }
    

    In your code, first element is of type 'element1' then first it process (with first if) and they again it come to else where it try to skip it, which cause problem.