From 8dc7761e6d490877af18949c0177097e5c857424 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 20 May 2020 21:59:21 +0200 Subject: [PATCH] Fix QXmlStreamSimpleStack to work also with non POD data types The current code is already undefined behavior, as QStringRef is not POD. It happened to work, because the destructor is empty. Fix this and rather let the compiler determine whether it needs to call any constructors or destructors. Change-Id: Idc8710df539603b0ca401a9453f2501f01beaab4 Reviewed-by: Thiago Macieira --- src/corelib/serialization/qxmlstream.cpp | 6 ++-- src/corelib/serialization/qxmlstream_p.h | 28 +++++++++++++------ .../serialization/qxmlstreamparser_p.h | 4 +-- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index e242340f7b..176dbfe398 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -3037,7 +3037,7 @@ bool QXmlStreamWriterPrivate::finishStartElement(bool contents) if (inEmptyElement) { write("/>"); - QXmlStreamWriterPrivate::Tag &tag = tagStack_pop(); + QXmlStreamWriterPrivate::Tag tag = tagStack_pop(); lastNamespaceDeclaration = tag.namespaceDeclarationsSize; lastWasStartElement = false; } else { @@ -3496,7 +3496,7 @@ void QXmlStreamWriter::writeEndElement() if (d->inStartElement && !d->inEmptyElement) { d->write("/>"); d->lastWasStartElement = d->inStartElement = false; - QXmlStreamWriterPrivate::Tag &tag = d->tagStack_pop(); + QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop(); d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize; return; } @@ -3506,7 +3506,7 @@ void QXmlStreamWriter::writeEndElement() if (d->tagStack.isEmpty()) return; d->lastWasStartElement = false; - QXmlStreamWriterPrivate::Tag &tag = d->tagStack_pop(); + QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop(); d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize; d->write(" class QXmlStreamSimpleStack { +template class QXmlStreamSimpleStack +{ T *data; qsizetype tos, cap; public: - inline QXmlStreamSimpleStack():data(nullptr), tos(-1), cap(0){} - inline ~QXmlStreamSimpleStack(){ if (data) free(data); } + inline QXmlStreamSimpleStack() + : data(nullptr), tos(-1), cap(0) + {} + inline ~QXmlStreamSimpleStack() + { + if (data) { + std::destroy_n(data, size()); + free(data); + } + } - inline void reserve(qsizetype extraCapacity) { + inline void reserve(qsizetype extraCapacity) + { if (tos + extraCapacity + 1 > cap) { cap = qMax(tos + extraCapacity + 1, cap << 1 ); void *ptr = realloc(static_cast(data), cap * sizeof(T)); @@ -74,11 +84,11 @@ public: } } - inline T &push() { reserve(1); return data[++tos]; } - inline T &rawPush() { return data[++tos]; } + inline T &push() { reserve(1); return rawPush(); } + inline T &rawPush() { return *new (data + (++tos)) T; } inline const T &top() const { return data[tos]; } inline T &top() { return data[tos]; } - inline T &pop() { return data[tos--]; } + inline T pop() { T t = std::move(data[tos]); std::destroy_at(data + tos); --tos; return t; } inline T &operator[](qsizetype index) { return data[index]; } inline const T &at(qsizetype index) const { return data[index]; } inline qsizetype size() const { return tos + 1; } @@ -147,8 +157,8 @@ public: QXmlStreamSimpleStack tagStack; - inline Tag &tagStack_pop() { - Tag& tag = tagStack.pop(); + inline Tag tagStack_pop() { + Tag tag = tagStack.pop(); tagStackStringStorageSize = tag.tagStackStringStorageSize; namespaceDeclarations.resize(tag.namespaceDeclarationsSize); tagsDone = tagStack.isEmpty(); diff --git a/src/corelib/serialization/qxmlstreamparser_p.h b/src/corelib/serialization/qxmlstreamparser_p.h index 1d28923a11..2d2dc5811d 100644 --- a/src/corelib/serialization/qxmlstreamparser_p.h +++ b/src/corelib/serialization/qxmlstreamparser_p.h @@ -90,7 +90,7 @@ bool QXmlStreamReaderPrivate::parse() attributes.clear(); if (isEmptyElement) { setType(QXmlStreamReader::EndElement); - Tag &tag = tagStack_pop(); + Tag tag = tagStack_pop(); namespaceUri = tag.namespaceDeclaration.namespaceUri; name = tag.name; qualifiedName = tag.qualifiedName; @@ -837,7 +837,7 @@ bool QXmlStreamReaderPrivate::parse() case 238: { setType(QXmlStreamReader::EndElement); - Tag &tag = tagStack_pop(); + Tag tag = tagStack_pop(); namespaceUri = tag.namespaceDeclaration.namespaceUri; name = tag.name;