diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-10-19 15:18:48 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-10-23 15:10:28 +0200 |
commit | 72ad4191161a078a8c5828aa52ffe232e86117a8 (patch) | |
tree | 8db9c15a76735a87c8fa99c651c636f06ce8fb0c /tests/auto/corelib/kernel | |
parent | fd48ce0b73c74dafd5db27bc1f2752ef665df7ef (diff) |
JNI: Fix reference leak in QJniArray
When the array type is QJniObject or a subclass, then we need to
explicitly release the local reference returned by GetObjectArrayElement
in the QJniArray::at implementation. Do this by constructing the
QJniObject via fromLocalRef, which does exactly that.
Amends 80d4d55e250af1d643805bde3821987112cf09c1.
Add a test case that stresses the local reference pool, and fix the old
test case (which operates on a QJniArray<jobject>) to also release the
local references.
Change-Id: Ie293b1db9f1b6825376bbf12338b22dfc3f8c6e9
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Diffstat (limited to 'tests/auto/corelib/kernel')
-rw-r--r-- | tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp index c39a6d0343..c658c35bb0 100644 --- a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp +++ b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp @@ -113,6 +113,7 @@ private slots: void templateApiCheck(); void isClassAvailable(); void fromLocalRef(); + void largeObjectArray(); void callback_data(); void callback(); @@ -1534,9 +1535,10 @@ void tst_QJniObject::templateApiCheck() const auto reverse = testClass.callMethod<jobject[]>("reverseObjectArray", newArray); QVERIFY(reverse.isValid()); QCOMPARE(reverse.size(), 3); - QCOMPARE(QJniObject(reverse.at(0)).toString(), u"three"_s); - QCOMPARE(QJniObject(reverse.at(1)).toString(), u"two"_s); - QCOMPARE(QJniObject(reverse.at(2)).toString(), u"one"_s); + // QJniArray::at returns a jobject that's a local reference; make sure we don't free it twice + QCOMPARE(QJniObject::fromLocalRef(reverse.at(0)).toString(), u"three"_s); + QCOMPARE(QJniObject::fromLocalRef(reverse.at(1)).toString(), u"two"_s); + QCOMPARE(QJniObject::fromLocalRef(reverse.at(2)).toString(), u"one"_s); } // jbooleanArray ------------------------------------------------------------------------------ @@ -1842,6 +1844,25 @@ void tst_QJniObject::fromLocalRef() QJniObject o = QJniObject::fromLocalRef(env->FindClass("java/lang/String")); } +void tst_QJniObject::largeObjectArray() +{ + QJniArray<jobject> newArray(QList<QJniObject>{QJniObject::fromString(u"one"_s), + QJniObject::fromString(u"two"_s), + QJniObject::fromString(u"three"_s)}); + QVERIFY(newArray.isValid()); + const QJniArray<QJniObject> reverse = TestClass::callStaticMethod<jobject[]>( + "staticReverseObjectArray", newArray); + QVERIFY(reverse.isValid()); + QCOMPARE(reverse.size(), 3); + + // make sure we don't leak local references + for (int i = 0; i < 10000; ++i) { + QVERIFY(reverse.at(0).isValid()); + QVERIFY(reverse.at(1).isValid()); + QVERIFY(reverse.at(2).isValid()); + } +} + static std::optional<TestClass> calledWithObject; static int callbackWithObject(JNIEnv *, jobject, TestClass that) |