From 4444167c169f2e6594cbb86a873442e551f789da Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Fri, 22 Mar 2024 01:21:09 +0200 Subject: [PATCH] JNI: check for pending exception first in getCleanJniObject() returning early if the object is null will not clear pending exceptions from the previous failed JNI call, and that will crash the app on the next jni call if an explicit exception clearing is not done, wish mostly the case. Checking and clearing for exceptions has to always be done under this call. Fixes: QTBUG-122135 Change-Id: I0d42d012a4d1305fa07147fd22860d7c005f9b83 Reviewed-by: Ville Voutilainen (cherry picked from commit 0a4599637657375517fcaf35177d8c7bac302556) --- src/corelib/kernel/qjniobject.cpp | 8 +++----- .../testdata/QtJniObjectTestClass.java | 8 ++++++++ .../kernel/qjniobject/tst_qjniobject.cpp | 20 +++++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp index f75b5bc9d25..a7497f96242 100644 --- a/src/corelib/kernel/qjniobject.cpp +++ b/src/corelib/kernel/qjniobject.cpp @@ -346,11 +346,9 @@ static jclass getCachedClass(const QByteArray &className) */ static QJniObject getCleanJniObject(jobject object, JNIEnv *env) { - if (!object) - return QJniObject(); - - if (QJniEnvironment::checkAndClearExceptions(env)) { - env->DeleteLocalRef(object); + if (QJniEnvironment::checkAndClearExceptions(env) || !object) { + if (object) + env->DeleteLocalRef(object); return QJniObject(); } diff --git a/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java b/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java index 5b983407a3c..36f47632692 100644 --- a/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java +++ b/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java @@ -319,4 +319,12 @@ public class QtJniObjectTestClass { return callbackWithDouble(value); } + + public Object callMethodThrowsException() throws Exception { + throw new Exception(); + } + + public static Object callStaticMethodThrowsException() throws Exception { + throw new Exception(); + } } diff --git a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp index 6af3c300141..16a27bcf01a 100644 --- a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp +++ b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp @@ -40,10 +40,12 @@ private slots: void ctor(); void callMethodTest(); + void callMethodThrowsException(); void callObjectMethodTest(); void stringConvertionTest(); void compareOperatorTests(); void className(); + void callStaticMethodThrowsException(); void callStaticObjectMethodClassName(); void callStaticObjectMethod(); void callStaticObjectMethodById(); @@ -262,6 +264,15 @@ void tst_QJniObject::callMethodTest() } } +void tst_QJniObject::callMethodThrowsException() +{ + QtJniTypes::QtJniObjectTestClass instance; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.Exception")); + auto res = instance.callMethod("callMethodThrowsException"); + QVERIFY(!res.isValid()); + QVERIFY(!QJniEnvironment().checkAndClearExceptions()); +} + void tst_QJniObject::callObjectMethodTest() { const QString qString = QLatin1String("Hello, Java"); @@ -339,6 +350,15 @@ void tst_QJniObject::className() } } +void tst_QJniObject::callStaticMethodThrowsException() +{ + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.Exception")); + auto res = QtJniTypes::QtJniObjectTestClass::callStaticMethod( + "callStaticMethodThrowsException"); + QVERIFY(!res.isValid()); + QVERIFY(!QJniEnvironment().checkAndClearExceptions()); +} + void tst_QJniObject::callStaticObjectMethodClassName() { QJniObject formatString = QJniObject::fromString(QLatin1String("test format"));