Skip to content

Commit c955319

Browse files
Magdalenoojaheikk
authored andcommitted
QDom: Guard against null nodes returned by factory functions
Since the default InvalidDataPolicy changed to ReturnNullNode, the QDomDocumentPrivate factory functions return nullptr when the input contains data that is invalid per XML 1.0. QDomBuilder::characters(), QDomBuilder::skippedEntity() and QDomBuilder::comment() used the returned node without checking, causing a crash. Check for nullptr and return false, as startElement() and processingInstruction() already do. Fixes: QTBUG-148791 Change-Id: Id46c8438e648008d7edad50ae411d682ec5152f6 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit 8b56704) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit ec02738) (cherry picked from commit ca6d005) Reviewed-by: Magdalena Stojek <magdalena.stojek@qt.io>
1 parent 6cfd75f commit c955319

2 files changed

Lines changed: 62 additions & 0 deletions

File tree

src/xml/dom/qdomhelpers.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ bool QDomBuilder::characters(const QString &characters, bool cdata)
139139
} else {
140140
n.reset(doc->createTextNode(characters));
141141
}
142+
if (!n)
143+
return false;
142144
n->setLocation(int(reader->lineNumber()), int(reader->columnNumber()));
143145
node->appendChild(n.get());
144146
Q_UNUSED(n.release());
@@ -161,6 +163,8 @@ bool QDomBuilder::processingInstruction(const QString &target, const QString &da
161163
bool QDomBuilder::skippedEntity(const QString &name)
162164
{
163165
QDomNodePrivate *n = doc->createEntityReference(name);
166+
if (!n)
167+
return false;
164168
n->setLocation(int(reader->lineNumber()), int(reader->columnNumber()));
165169
node->appendChild(n);
166170
return true;
@@ -189,6 +193,8 @@ bool QDomBuilder::comment(const QString &characters)
189193
{
190194
QDomNodePrivate *n;
191195
n = doc->createComment(characters);
196+
if (!n)
197+
return false;
192198
n->setLocation(int(reader->lineNumber()), int(reader->columnNumber()));
193199
node->appendChild(n);
194200
return true;

tests/auto/xml/dom/qdom/tst_qdom.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ private slots:
105105
void germanUmlautToFile() const;
106106
void setInvalidDataPolicy() const;
107107
void crashInSetContent() const;
108+
void invalidCharDataInSetContent() const;
109+
void invalidCharDataInSetContent_data() const;
108110
void doubleNamespaceDeclarations() const;
109111
void setContentQXmlReaderOverload() const;
110112
void toStringWithoutNewlines() const;
@@ -2336,6 +2338,60 @@ void tst_QDom::crashInSetContent() const
23362338
QVERIFY(docImport.setContent(QLatin1String("<?xml version=\"1.0\"?><e/>")));
23372339
}
23382340

2341+
void tst_QDom::invalidCharDataInSetContent_data() const
2342+
{
2343+
QTest::addColumn<QByteArray>("input");
2344+
QTest::addColumn<bool>("parsed");
2345+
QTest::addColumn<QString>("document");
2346+
2347+
QTest::newRow("control")
2348+
<< "<r><before/><a>TextNode</a><after/></r>"_ba << true
2349+
<< u"<r><before/><a>TextNode</a><after/></r>"_s;
2350+
QTest::newRow("text-with-nul")
2351+
<< "<r><before/><a>te\0xt</a><after/></r>"_ba << false
2352+
<< u"<r><before/><a>te</a></r>"_s;
2353+
QTest::newRow("cdata")
2354+
<< "<r><before/><![CDATA[da\0ta]]><after/></r>"_ba << false
2355+
<< u"<r><before/></r>"_s;
2356+
QTest::newRow("comment")
2357+
<< "<r><before/><!-- co\0m --><after/></r>"_ba << false
2358+
<< u"<r><before/></r>"_s;
2359+
QTest::newRow("pi-data")
2360+
<< "<r><before/><?pi da\0ta?><after/></r>"_ba << false
2361+
<< u"<r><before/></r>"_s;
2362+
QTest::newRow("start-element")
2363+
<< "<r><before/><a\0b/><after/></r>"_ba << false
2364+
<< u"<r><before/></r>"_s;
2365+
QTest::newRow("nul-at-end")
2366+
<< "<r><before/><before2/></r>\0"_ba << false
2367+
<< u"<r><before/><before2/></r>"_s;
2368+
}
2369+
2370+
void tst_QDom::invalidCharDataInSetContent() const
2371+
{
2372+
QFETCH(const QByteArray, input);
2373+
QFETCH(const bool, parsed);
2374+
QFETCH(const QString, document);
2375+
2376+
const auto policy = QDomImplementation::invalidDataPolicy();
2377+
const auto restoreInvalidDataPolicy = qScopeGuard([policy] {
2378+
QDomImplementation::setInvalidDataPolicy(policy);
2379+
});
2380+
QDomImplementation::setInvalidDataPolicy(QDomImplementation::ReturnNullNode);
2381+
2382+
QDomDocument doc;
2383+
const QDomDocument::ParseResult result =
2384+
doc.setContent(input, QDomDocument::ParseOption::UseNamespaceProcessing);
2385+
2386+
QCOMPARE(bool(result), parsed);
2387+
if (!parsed) {
2388+
QVERIFY(!result.errorMessage.isEmpty());
2389+
QCOMPARE(result.errorLine, qsizetype(1));
2390+
QVERIFY(result.errorColumn > 0);
2391+
}
2392+
QCOMPARE(doc.toString(-1), document);
2393+
}
2394+
23392395
void tst_QDom::doubleNamespaceDeclarations() const
23402396
{
23412397
QDomDocument doc;

0 commit comments

Comments
 (0)