diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index 6aaa65f9a6b..3175517a356 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -1296,7 +1296,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;
@@ -1304,7 +1306,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':
@@ -1338,18 +1341,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:
@@ -1363,7 +1366,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 };
@@ -1841,6 +1844,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 f3152bff378..fc122e66811 100644
--- a/src/corelib/serialization/qxmlstream.g
+++ b/src/corelib/serialization/qxmlstream.g
@@ -1420,7 +1420,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;
@@ -1431,7 +1435,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 1baa75c5fa4..417778090b0 100644
--- a/src/corelib/serialization/qxmlstream_p.h
+++ b/src/corelib/serialization/qxmlstream_p.h
@@ -38,7 +38,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)
@@ -498,7 +498,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();
 
 
@@ -507,6 +516,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 c12815c893c..ae3ebe7a8e1 100644
--- a/src/corelib/serialization/qxmlstreamparser_p.h
+++ b/src/corelib/serialization/qxmlstreamparser_p.h
@@ -948,7 +948,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;
@@ -956,7 +960,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;