diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2025-08-07 16:42:22 +0200 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2025-09-02 09:15:10 +0200 |
| commit | b1c48db754c7019e0472d0baf6d71d2bd93a205b (patch) | |
| tree | 59d174c30931ab8a95bc513d840553e182cc4f07 /src/qmlcompiler/qqmljsoptimizations.cpp | |
| parent | 2d016a2653c59f10a57dc1903b817f71d16d0622 (diff) | |
QmlCompiler: Ensure QObjects returned to AOT-compiled code are wrapped
If a QObject is returned from a method call, the QML engine takes
ownership of it and it needs to be deleted by the garbage collector. Our
generated C++ code so far did not actually take ownership of the object
and thereby caused it to leak.
Pick-to: 6.10 6.9 6.8
Fixes: QTBUG-138919
Change-Id: I7bd57b3612bf4b98937756e8a7a7c03aff1c9b32
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Diffstat (limited to 'src/qmlcompiler/qqmljsoptimizations.cpp')
| -rw-r--r-- | src/qmlcompiler/qqmljsoptimizations.cpp | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/src/qmlcompiler/qqmljsoptimizations.cpp b/src/qmlcompiler/qqmljsoptimizations.cpp index d003aa1974..b862500994 100644 --- a/src/qmlcompiler/qqmljsoptimizations.cpp +++ b/src/qmlcompiler/qqmljsoptimizations.cpp @@ -195,10 +195,22 @@ bool QQmlJSOptimizations::eraseDeadStore(const InstructionAnnotations::iterator it->second.changedRegisterIndex = InvalidRegister; it->second.changedRegister = QQmlJSRegisterContent(); } else { - // void the output, rather than deleting it. We still need its variant. - const bool adjusted = m_typeResolver->adjustTrackedType( - it->second.changedRegister, m_typeResolver->voidType()); - Q_ASSERT(adjusted); // Can always convert to void + // We can't do this with certain QObjects because they still need tracking as + // implicitly destructible by the garbage collector. We may be calling a factory + // function and then forgetting the object after all. + // + // However, objects we need to track that way can only be produced through external + // side effects (i.e. function calls). + + const QQmlJSScope::ConstPtr contained = it->second.changedRegister.containedType(); + if (!it->second.hasExternalSideEffects + || (!contained->isReferenceType() + && !m_typeResolver->canHold(contained, m_typeResolver->qObjectType()))) { + // void the output, rather than deleting it. We still need its variant. + const bool adjusted = m_typeResolver->adjustTrackedType( + it->second.changedRegister, m_typeResolver->voidType()); + Q_ASSERT(adjusted); // Can always convert to void + } } m_readerLocations.erase(reader); |
