diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2023-02-28 15:59:48 -0800 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-03-01 23:06:03 +0000 |
commit | b8b828d5653636df36bdfb7313ec12f142fafd87 (patch) | |
tree | 41ad3fa39a9248e5a3430cdab9f50428a03fa846 | |
parent | f6d5dd093a33f8af71387129f5cd475825295c88 (diff) |
Work around GCC 13 bogus warning about use-after-free
By simply adding std::move() to the variables we've received by value
and aren't using again, thereby also improving performance slightly.
The message was:
In static member function ‘static void QSharedPointer<T>::deref(Data*) [with T = const QQmlJSScope]’,
inlined from ‘void QSharedPointer<T>::deref() [with T = const QQmlJSScope]’ at qsharedpointer_impl.h:440:12,
inlined from ‘QSharedPointer<T>::~QSharedPointer() [with T = const QQmlJSScope]’ at qsharedpointer_impl.h:280:30,
inlined from ‘QDeferredSharedPointer<const QQmlJSScope>::~QDeferredSharedPointer()’ at qdeferredpointer_p.h:45:7,
inlined from ‘QString QmltcCodeGenerator::generate_typeCount(Predicate, const InlineComponentOrDocumentRootName&) const
cc1plus: error: pointer may be used after ‘void operator delete(void*)’ [-Werror=use-after-free]
In static member function ‘static void QtSharedPointer::ExternalRefCountData::operator delete(void*)’,
inlined from ‘static void QSharedPointer<T>::deref(Data*) [with T = const QQmlJSScope]’ at qsharedpointer_impl.h:448:13,
inlined from ‘static void QSharedPointer<T>::deref(Data*) [with T = const QQmlJSScope]’ at qsharedpointer_impl.h:441:17,
inlined from ‘void QSharedPointer<T>::deref() [with T = const QQmlJSScope]’ at qsharedpointer_impl.h:440:12,
inlined from ‘QSharedPointer<T>::~QSharedPointer() [with T = const QQmlJSScope]’ at qsharedpointer_impl.h:280:30,
inlined from ‘QDeferredSharedPointer<T>::operator QDeferredSharedPointer<const T>() const [with T = QQmlJSScope]’ at qdeferredpointer_p.h:75:83,
inlined from ‘QString QmltcCodeGenerator::generate_typeCount(Predicate, const InlineComponentOrDocumentRootName&) const
qsharedpointer_impl.h:130:67: note: call to ‘void operator delete(void*)’ here
For reference:
static void deref(Data *dd) noexcept
{
if (!dd) return;
if (!dd->strongref.deref()) {
dd->destroy();
}
if (!dd->weakref.deref())
delete dd;
}
Note how there's one extra frame in the deletion sequence
(QDeferredSharedPointer<T>::operator QDeferredSharedPointer<const T>())
compared to the use. The common source is
if (t == visitor->result()) { // t is this document's root
The variable `t` is a QDeferredSharedPointer<const QQmlJSScope>, but the
right side is only QDeferredSharedPointer<QQmlJSScope>, which is why the
conversion operator was called.
operator QDeferredSharedPointer<const T>() const { return { m_data, m_factory }; }
The above is calling the constructor
QDeferredSharedPointer(QSharedPointer<T> data, QSharedPointer<Factory> factory)
for T = const QQmlJSScope, which means it's calling
template <class X, IfCompatible<X> = true>
QSharedPointer(const QSharedPointer<X> &other) noexcept : value(other.value), d(other.d)
to construct the const version from m_data. This temporary is then moved
into the QDeferredSharedPointer's argument because it's a prvalue by way
of QSharedPointer's move constructor
QSharedPointer(QSharedPointer &&other) noexcept
: value(other.value), d(other.d)
{
other.d = nullptr;
other.value = nullptr;
}
After the QDeferredSharedPointer's constructor returns, the temporary
QSharedPointer is destroyed, which is where the compiler saw the call to
operator delete.
Except that it can't happen. The move constructor will have set the
temporary's d pointer to null, so when deref() is called on that
temporary, the check will match:
if (!dd) return;
Change-Id: I7f354474adce419ca6c2fffd17482074d5cdc9d5
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit fa7c03f92ea922ac20617c9e8b6da83d8c6665b6)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/qmlcompiler/qdeferredpointer_p.h | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h index 481c0e27ae..f4d8696f69 100644 --- a/src/qmlcompiler/qdeferredpointer_p.h +++ b/src/qmlcompiler/qdeferredpointer_p.h @@ -50,15 +50,15 @@ public: QDeferredSharedPointer() = default; QDeferredSharedPointer(QSharedPointer<T> data) - : m_data(data) + : m_data(std::move(data)) {} QDeferredSharedPointer(QWeakPointer<T> data) - : m_data(data) + : m_data(std::move(data)) {} QDeferredSharedPointer(QSharedPointer<T> data, QSharedPointer<Factory> factory) - : m_data(data), m_factory(factory) + : m_data(std::move(data)), m_factory(std::move(factory)) { // You have to provide a valid pointer if you provide a factory. We cannot allocate the // pointer for you because then two copies of the same QDeferredSharedPointer will diverge |