diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index 72c33584a98..598b9f0428f 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -1292,7 +1292,9 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList() return n; } -inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) +// Fast scan an XML attribute name (e.g. "xml:lang"). +inline QXmlStreamReaderPrivate::FastScanNameResult +QXmlStreamReaderPrivate::fastScanName(Value *val) { qsizetype n = 0; uint c; @@ -1300,7 +1302,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) if (n >= 4096) { // This is too long to be a sensible name, and // can exhaust memory, or the range of decltype(*prefix) - return 0; + raiseNamePrefixTooLongError(); + return {}; } switch (c) { case '\n': @@ -1334,18 +1337,18 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) putChar(':'); --n; } - return n; + return FastScanNameResult(n); case ':': if (val) { if (val->prefix == 0) { val->prefix = qint16(n + 2); } else { // only one colon allowed according to the namespace spec. putChar(c); - return n; + return FastScanNameResult(n); } } else { putChar(c); - return n; + return FastScanNameResult(n); } Q_FALLTHROUGH(); default: @@ -1359,7 +1362,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) qsizetype pos = textBuffer.size() - n; putString(textBuffer, pos); textBuffer.resize(pos); - return 0; + return FastScanNameResult(0); } enum NameChar { NameBeginning, NameNotBeginning, NotName }; @@ -1839,6 +1842,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message) raiseError(QXmlStreamReader::NotWellFormedError, message); } +void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError() +{ + // TODO: add a ImplementationLimitsExceededError and use it instead + raiseError(QXmlStreamReader::NotWellFormedError, + QXmlStream::tr("Length of XML attribute name exceeds implemnetation limits (4KiB " + "characters).")); +} + void QXmlStreamReaderPrivate::parseError() { diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g index 81ca36688cd..1b5a682b36a 100644 --- a/src/corelib/serialization/qxmlstream.g +++ b/src/corelib/serialization/qxmlstream.g @@ -1490,7 +1490,11 @@ qname ::= LETTER; /. case $rule_number: { Value &val = sym(1); - val.len += fastScanName(&val); + if (auto res = fastScanName(&val)) + val.len += *res; + else + return false; + if (atEnd) { resume($rule_number); return false; @@ -1501,7 +1505,11 @@ qname ::= LETTER; name ::= LETTER; /. case $rule_number: - sym(1).len += fastScanName(); + if (auto res = fastScanName()) + sym(1).len += *res; + else + return false; + if (atEnd) { resume($rule_number); return false; diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h index 8f64130d2f9..a277753f188 100644 --- a/src/corelib/serialization/qxmlstream_p.h +++ b/src/corelib/serialization/qxmlstream_p.h @@ -71,7 +71,7 @@ public: constexpr XmlStringRef() = default; constexpr inline XmlStringRef(const QString *string, qsizetype pos, qsizetype length) - : m_string(string), m_pos(pos), m_size(length) + : m_string(string), m_pos(pos), m_size((Q_ASSERT(length >= 0), length)) { } XmlStringRef(const QString *string) @@ -504,7 +504,16 @@ public: qsizetype fastScanLiteralContent(); qsizetype fastScanSpace(); qsizetype fastScanContentCharList(); - qsizetype fastScanName(Value *val = nullptr); + + struct FastScanNameResult { + FastScanNameResult() : ok(false) {} + explicit FastScanNameResult(qsizetype len) : addToLen(len), ok(true) { } + operator bool() { return ok; } + qsizetype operator*() { Q_ASSERT(ok); return addToLen; } + qsizetype addToLen; + bool ok; + }; + FastScanNameResult fastScanName(Value *val = nullptr); inline qsizetype fastScanNMTOKEN(); @@ -513,6 +522,7 @@ public: void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); void raiseWellFormedError(const QString &message); + void raiseNamePrefixTooLongError(); QXmlStreamEntityResolver *entityResolver; diff --git a/src/corelib/serialization/qxmlstreamparser_p.h b/src/corelib/serialization/qxmlstreamparser_p.h index 17558aae641..d67d71ca01d 100644 --- a/src/corelib/serialization/qxmlstreamparser_p.h +++ b/src/corelib/serialization/qxmlstreamparser_p.h @@ -982,7 +982,11 @@ bool QXmlStreamReaderPrivate::parse() case 262: { Value &val = sym(1); - val.len += fastScanName(&val); + if (auto res = fastScanName(&val)) + val.len += *res; + else + return false; + if (atEnd) { resume(262); return false; @@ -990,7 +994,11 @@ bool QXmlStreamReaderPrivate::parse() } break; case 263: - sym(1).len += fastScanName(); + if (auto res = fastScanName()) + sym(1).len += *res; + else + return false; + if (atEnd) { resume(263); return false;