From b7a7351767bc58bc7e8719972e309a1e9f23967c Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 16 Oct 2023 17:21:08 +0200 Subject: [PATCH] JNI: treat equivalent C++ types as the same JNI types as well Our signature mapping treats both e.g. bool and jboolean as "Z", and it is allowed to pass a bool variable as an argument to a function expecting a jboolean. Except for fields and callMethod return values, where we only allowed the JNI primitive types. Fix this by comparing the signatures and size of the type we have with the JNI types that there are explicit functions for. Cast from and to the JNI type in both directions to address narrowing (e.g. jboolean is an unsigned char and converting to bool would be narrowing, even though both are 8bit types). This way we can get boolean fields using getField, and int fields using getField etc. Change-Id: I2f1ba855ee01423e79ba999dfb9d86f4b98b1402 Reviewed-by: Qt CI Bot Reviewed-by: Assam Boudjelthia --- src/corelib/kernel/qjniobject.h | 190 +++++++++--------- .../kernel/qjniobject/tst_qjniobject.cpp | 10 + 2 files changed, 100 insertions(+), 100 deletions(-) diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index 05db6f4414..88214a9311 100644 --- a/src/corelib/kernel/qjniobject.h +++ b/src/corelib/kernel/qjniobject.h @@ -561,20 +561,10 @@ private: friend bool operator==(const QJniObject &, const QJniObject &); friend bool operator!=(const QJniObject&, const QJniObject&); - template - struct IntegerTypeDetail - { - using type = T; - }; - template - struct IntegerTypeDetail>> - { - using type = std::underlying_type_t; - }; - - template - static constexpr bool likeIntegerType = std::is_same_v - || std::is_same_v::type, Want>; + template + static constexpr bool sameTypeForJni = (QtJniTypes::Traits::signature() + == QtJniTypes::Traits::signature()) + && (sizeof(Have) == sizeof(Want)); template static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, @@ -583,22 +573,22 @@ private: va_list args = {}; va_start(args, id); - if constexpr (std::is_same_v) - res = env->CallBooleanMethodV(obj, id, args); - else if constexpr (likeIntegerType) - res = T{env->CallByteMethodV(obj, id, args)}; - else if constexpr (likeIntegerType) - res = T{env->CallCharMethodV(obj, id, args)}; - else if constexpr (likeIntegerType) - res = T{env->CallShortMethodV(obj, id, args)}; - else if constexpr (likeIntegerType) - res = T{env->CallIntMethodV(obj, id, args)}; - else if constexpr (likeIntegerType) - res = T{env->CallLongMethodV(obj, id, args)}; - else if constexpr (std::is_same_v) - res = env->CallFloatMethodV(obj, id, args); - else if constexpr (std::is_same_v) - res = env->CallDoubleMethodV(obj, id, args); + if constexpr (sameTypeForJni) + res = T(env->CallBooleanMethodV(obj, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallByteMethodV(obj, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallCharMethodV(obj, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallShortMethodV(obj, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallIntMethodV(obj, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallLongMethodV(obj, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallFloatMethodV(obj, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallDoubleMethodV(obj, id, args)); else QtJniTypes::staticAssertTypeMismatch(); va_end(args); @@ -612,22 +602,22 @@ private: return; va_list args = {}; va_start(args, id); - if constexpr (std::is_same_v) - res = env->CallStaticBooleanMethodV(clazz, id, args); - else if constexpr (likeIntegerType) - res = T{env->CallStaticByteMethodV(clazz, id, args)}; - else if constexpr (likeIntegerType) - res = T{env->CallStaticCharMethodV(clazz, id, args)}; - else if constexpr (likeIntegerType) - res = T{env->CallStaticShortMethodV(clazz, id, args)}; - else if constexpr (likeIntegerType) - res = T{env->CallStaticIntMethodV(clazz, id, args)}; - else if constexpr (likeIntegerType) - res = T{env->CallStaticLongMethodV(clazz, id, args)}; - else if constexpr (std::is_same_v) - res = env->CallStaticFloatMethodV(clazz, id, args); - else if constexpr (std::is_same_v) - res = env->CallStaticDoubleMethodV(clazz, id, args); + if constexpr (sameTypeForJni) + res = T(env->CallStaticBooleanMethodV(clazz, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallStaticByteMethodV(clazz, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallStaticCharMethodV(clazz, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallStaticShortMethodV(clazz, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallStaticIntMethodV(clazz, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallStaticLongMethodV(clazz, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallStaticFloatMethodV(clazz, id, args)); + else if constexpr (sameTypeForJni) + res = T(env->CallStaticDoubleMethodV(clazz, id, args)); else QtJniTypes::staticAssertTypeMismatch(); va_end(args); @@ -648,22 +638,22 @@ private: static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id) { - if constexpr (std::is_same_v) - res = env->GetBooleanField(obj, id); - else if constexpr (likeIntegerType) - res = T{env->GetByteField(obj, id)}; - else if constexpr (likeIntegerType) - res = T{env->GetCharField(obj, id)}; - else if constexpr (likeIntegerType) - res = T{env->GetShortField(obj, id)}; - else if constexpr (likeIntegerType) - res = T{env->GetIntField(obj, id)}; - else if constexpr (likeIntegerType) - res = T{env->GetLongField(obj, id)}; - else if constexpr (std::is_same_v) - res = env->GetFloatField(obj, id); - else if constexpr (std::is_same_v) - res = env->GetDoubleField(obj, id); + if constexpr (sameTypeForJni) + res = T(env->GetBooleanField(obj, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetByteField(obj, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetCharField(obj, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetShortField(obj, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetIntField(obj, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetLongField(obj, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetFloatField(obj, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetDoubleField(obj, id)); else QtJniTypes::staticAssertTypeMismatch(); } @@ -672,22 +662,22 @@ private: static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id) { - if constexpr (std::is_same_v) - res = env->GetStaticBooleanField(clazz, id); - else if constexpr (likeIntegerType) - res = T{env->GetStaticByteField(clazz, id)}; - else if constexpr (likeIntegerType) - res = T{env->GetStaticCharField(clazz, id)}; - else if constexpr (likeIntegerType) - res = T{env->GetStaticShortField(clazz, id)}; - else if constexpr (likeIntegerType) - res = T{env->GetStaticIntField(clazz, id)}; - else if constexpr (likeIntegerType) - res = T{env->GetStaticLongField(clazz, id)}; - else if constexpr (std::is_same_v) - res = env->GetStaticFloatField(clazz, id); - else if constexpr (std::is_same_v) - res = env->GetStaticDoubleField(clazz, id); + if constexpr (sameTypeForJni) + res = T(env->GetStaticBooleanField(clazz, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetStaticByteField(clazz, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetStaticCharField(clazz, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetStaticShortField(clazz, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetStaticIntField(clazz, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetStaticLongField(clazz, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetStaticFloatField(clazz, id)); + else if constexpr (sameTypeForJni) + res = T(env->GetStaticDoubleField(clazz, id)); else QtJniTypes::staticAssertTypeMismatch(); } @@ -697,22 +687,22 @@ private: jfieldID id, T value) { LocalFrame frame; - if constexpr (std::is_same_v) - env->SetBooleanField(obj, id, value); - else if constexpr (likeIntegerType) + if constexpr (sameTypeForJni) + env->SetBooleanField(obj, id, static_cast(value)); + else if constexpr (sameTypeForJni) env->SetByteField(obj, id, static_cast(value)); - else if constexpr (likeIntegerType) + else if constexpr (sameTypeForJni) env->SetCharField(obj, id, static_cast(value)); - else if constexpr (likeIntegerType) + else if constexpr (sameTypeForJni) env->SetShortField(obj, id, static_cast(value)); - else if constexpr (likeIntegerType) + else if constexpr (sameTypeForJni) env->SetIntField(obj, id, static_cast(value)); - else if constexpr (likeIntegerType) + else if constexpr (sameTypeForJni) env->SetLongField(obj, id, static_cast(value)); - else if constexpr (std::is_same_v) - env->SetFloatField(obj, id, value); - else if constexpr (std::is_same_v) - env->SetDoubleField(obj, id, value); + else if constexpr (sameTypeForJni) + env->SetFloatField(obj, id, static_cast(value)); + else if constexpr (sameTypeForJni) + env->SetDoubleField(obj, id, static_cast(value)); else if constexpr (QtJniTypes::isObjectType()) env->SetObjectField(obj, id, static_cast(frame.convertToJni(value))); else @@ -724,22 +714,22 @@ private: jfieldID id, T value) { LocalFrame frame; - if constexpr (std::is_same_v) - env->SetStaticBooleanField(clazz, id, value); - else if constexpr (likeIntegerType) + if constexpr (sameTypeForJni) + env->SetStaticBooleanField(clazz, id, static_cast(value)); + else if constexpr (sameTypeForJni) env->SetStaticByteField(clazz, id, static_cast(value)); - else if constexpr (likeIntegerType) + else if constexpr (sameTypeForJni) env->SetStaticCharField(clazz, id, static_cast(value)); - else if constexpr (likeIntegerType) + else if constexpr (sameTypeForJni) env->SetStaticShortField(clazz, id, static_cast(value)); - else if constexpr (likeIntegerType) + else if constexpr (sameTypeForJni) env->SetStaticIntField(clazz, id, static_cast(value)); - else if constexpr (likeIntegerType) + else if constexpr (sameTypeForJni) env->SetStaticLongField(clazz, id, static_cast(value)); - else if constexpr (std::is_same_v) - env->SetStaticFloatField(clazz, id, value); - else if constexpr (std::is_same_v) - env->SetStaticDoubleField(clazz, id, value); + else if constexpr (sameTypeForJni) + env->SetStaticFloatField(clazz, id, static_cast(value)); + else if constexpr (sameTypeForJni) + env->SetStaticDoubleField(clazz, id, static_cast(value)); else if constexpr (QtJniTypes::isObjectType()) env->SetStaticObjectField(clazz, id, static_cast(frame.convertToJni(value))); else diff --git a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp index 751e5a84d8..364b0c5d62 100644 --- a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp +++ b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp @@ -77,6 +77,7 @@ private slots: void getStaticIntField(); void getStaticByteFieldClassName(); void getStaticByteField(); + void getStaticBooleanField(); void getStaticLongFieldClassName(); void getStaticLongField(); void getStaticDoubleFieldClassName(); @@ -936,6 +937,12 @@ void tst_QJniObject::getStaticByteField() QCOMPARE(e, Enum::MAX_VALUE); } +void tst_QJniObject::getStaticBooleanField() +{ + QCOMPARE(TestClass::getStaticField("S_BOOLEAN_VAR"), + TestClass::getStaticField("S_BOOLEAN_VAR")); +} + void tst_QJniObject::getStaticLongFieldClassName() { jlong i = QJniObject::getStaticField("java/lang/Long", "MAX_VALUE"); @@ -1038,6 +1045,7 @@ void tst_QJniObject::getBooleanField() QVERIFY(obj.isValid()); QVERIFY(obj.getField("BOOL_FIELD")); + QVERIFY(obj.getField("BOOL_FIELD")); } void tst_QJniObject::getIntField() @@ -1109,6 +1117,7 @@ void tst_QJniObject::setCharField() void tst_QJniObject::setBooleanField() { setField("BOOLEAN_VAR", jboolean(true)); + setField("BOOLEAN_VAR", true); } void tst_QJniObject::setObjectField() @@ -1191,6 +1200,7 @@ void tst_QJniObject::setStaticCharField() void tst_QJniObject::setStaticBooleanField() { setStaticField("S_BOOLEAN_VAR", jboolean(true)); + setStaticField("S_BOOLEAN_VAR", true); } void tst_QJniObject::setStaticObjectField()