diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-09-27 08:19:21 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-09-27 19:44:58 +0200 |
commit | 185c3b080c5d4875266833eda703fca57f8a30af (patch) | |
tree | 1b8ae6cf38753e386d31a63d9b02bd1c9e3bbe6f /tests/auto/corelib/kernel/qjnitypes | |
parent | 62cb5589b3723fe8162e190cd54d9c78929b98d2 (diff) |
JNI: Fix native functions that take a declared QtJniTypes class
Now that QtJniTypes::Objects are no longer primitive types that are the
same as a jobject, using those types in registered native functions
breaks. JNI will call those function with a jobject on the function
pointer, and lacking any type safety, the call to the registered
function will proceed with a wrong type of object on the stack.
To fix that, register the native function via a proxy that is a variadic
argument function, and unpack the variadic arguments into a list of
typed arguments, using the types we know the user-code function wants.
Then call the function with a tuple of those types using std::apply,
which gives us type safety and implicit conversion for free.
Add a test that exercises this.
Change-Id: I9f980e55d3d13f8fc16c410dc0d17dbdc200cb47
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
Diffstat (limited to 'tests/auto/corelib/kernel/qjnitypes')
-rw-r--r-- | tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp index 0ce2295092..a499b6f2d2 100644 --- a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp +++ b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp @@ -14,6 +14,9 @@ class tst_QJniTypes : public QObject public: tst_QJniTypes() = default; + static void nativeClassMethod(JNIEnv *, jclass, int); + Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(nativeClassMethod); + private slots: void initTestCase(); void nativeMethod(); @@ -154,12 +157,32 @@ Q_DECLARE_JNI_NATIVE_METHOD(nativeFunction) static_assert(QtJniTypes::nativeMethodSignature(nativeFunction) == "(ILjava/lang/String;J)Z"); +static int forwardDeclaredNativeFunction(JNIEnv *, jobject, bool); +Q_DECLARE_JNI_NATIVE_METHOD(forwardDeclaredNativeFunction) +static int forwardDeclaredNativeFunction(JNIEnv *, jobject, bool) { return 0; } +static_assert(QtJniTypes::nativeMethodSignature(forwardDeclaredNativeFunction) == "(Z)I"); + +static_assert(QtJniTypes::nativeMethodSignature(tst_QJniTypes::nativeClassMethod) == "(I)V"); +void tst_QJniTypes::nativeClassMethod(JNIEnv *, jclass, int) {} + void tst_QJniTypes::nativeMethod() { - const auto method = Q_JNI_NATIVE_METHOD(nativeFunction); - QVERIFY(method.fnPtr == nativeFunction); - QCOMPARE(method.name, "nativeFunction"); - QCOMPARE(method.signature, "(ILjava/lang/String;J)Z"); + { + const auto method = Q_JNI_NATIVE_METHOD(nativeFunction); + QVERIFY(method.fnPtr == QtJniMethods::va_nativeFunction); + QCOMPARE(method.name, "nativeFunction"); + QCOMPARE(method.signature, "(ILjava/lang/String;J)Z"); + } + + { + const auto method = Q_JNI_NATIVE_METHOD(forwardDeclaredNativeFunction); + QVERIFY(method.fnPtr == QtJniMethods::va_forwardDeclaredNativeFunction); + } + + { + const auto method = Q_JNI_NATIVE_SCOPED_METHOD(nativeClassMethod, tst_QJniTypes); + QVERIFY(method.fnPtr == va_nativeClassMethod); + } } void tst_QJniTypes::construct() |