aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler/qqmljsoptimizations.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2025-08-07 16:42:22 +0200
committerUlf Hermann <ulf.hermann@qt.io>2025-09-02 09:15:10 +0200
commitb1c48db754c7019e0472d0baf6d71d2bd93a205b (patch)
tree59d174c30931ab8a95bc513d840553e182cc4f07 /src/qmlcompiler/qqmljsoptimizations.cpp
parent2d016a2653c59f10a57dc1903b817f71d16d0622 (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.cpp20
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);