JNI: don't access null jobject
When Java calls a native function that expects a QString with a null String object, then we get a nullptr jstring. We must not try to convert that to a QString. Add the necessary checks at the call-site of the toQString helper, and an assert to the helper itself. Add test case. Pick-to: 6.9 Change-Id: If5c55c702bdb3f89ac45fdf3912af2ac295f5e5c Reviewed-by: Volker Krause <vkrause@kde.org>
This commit is contained in:
parent
0e2656f937
commit
db6a9834d2
@ -819,13 +819,15 @@ public:
|
|||||||
container.reserve(sz);
|
container.reserve(sz);
|
||||||
if constexpr (std::is_same_v<typename ContainerType::value_type, QString>) {
|
if constexpr (std::is_same_v<typename ContainerType::value_type, QString>) {
|
||||||
for (auto element : *this) {
|
for (auto element : *this) {
|
||||||
if constexpr (std::is_same_v<decltype(element), QString>)
|
if constexpr (std::is_same_v<decltype(element), QString>) {
|
||||||
container.emplace_back(element);
|
container.emplace_back(element);
|
||||||
else if constexpr (std::is_same_v<decltype(element), jstring>)
|
} else if constexpr (std::is_same_v<decltype(element), jstring>) {
|
||||||
container.emplace_back(QtJniTypes::Detail::toQString(element, env));
|
container.emplace_back(element ? QtJniTypes::Detail::toQString(element, env)
|
||||||
else
|
: QString{});
|
||||||
|
} else {
|
||||||
container.emplace_back(QJniObject(element).toString());
|
container.emplace_back(QJniObject(element).toString());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>) {
|
} else if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>) {
|
||||||
for (auto element : *this)
|
for (auto element : *this)
|
||||||
container.emplace_back(element);
|
container.emplace_back(element);
|
||||||
|
@ -163,7 +163,7 @@ struct JNITypeForArgImpl<QString>
|
|||||||
|
|
||||||
static QString fromVarArg(Type t)
|
static QString fromVarArg(Type t)
|
||||||
{
|
{
|
||||||
return QtJniTypes::Detail::toQString(t, QJniEnvironment::getJniEnv());
|
return t ? QtJniTypes::Detail::toQString(t, QJniEnvironment::getJniEnv()) : QString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ public:
|
|||||||
|
|
||||||
static QList<T> fromVarArg(Type t)
|
static QList<T> fromVarArg(Type t)
|
||||||
{
|
{
|
||||||
return QJniArray<ElementType>(t).toContainer();
|
return t ? QJniArray<ElementType>(t).toContainer() : QList<T>{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ static inline jstring fromQString(const QString &string, JNIEnv *env)
|
|||||||
|
|
||||||
static inline QString toQString(jstring string, JNIEnv *env)
|
static inline QString toQString(jstring string, JNIEnv *env)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(string);
|
||||||
const jsize length = env->GetStringLength(string);
|
const jsize length = env->GetStringLength(string);
|
||||||
QString res(length, Qt::Uninitialized);
|
QString res(length, Qt::Uninitialized);
|
||||||
env->GetStringRegion(string, 0, length, reinterpret_cast<jchar *>(res.data()));
|
env->GetStringRegion(string, 0, length, reinterpret_cast<jchar *>(res.data()));
|
||||||
|
@ -307,6 +307,7 @@ public class QtJniObjectTestClass
|
|||||||
native public int callbackWithRawArray(Object[] value);
|
native public int callbackWithRawArray(Object[] value);
|
||||||
native public int callbackWithQList(double[] value);
|
native public int callbackWithQList(double[] value);
|
||||||
native public int callbackWithStringList(String[] value);
|
native public int callbackWithStringList(String[] value);
|
||||||
|
native public int callbackWithNull(String str);
|
||||||
|
|
||||||
public int callMeBackWithObject(QtJniObjectTestClass that)
|
public int callMeBackWithObject(QtJniObjectTestClass that)
|
||||||
{
|
{
|
||||||
@ -358,6 +359,10 @@ public class QtJniObjectTestClass
|
|||||||
{
|
{
|
||||||
return callbackWithStringList(value);
|
return callbackWithStringList(value);
|
||||||
}
|
}
|
||||||
|
public int callMeBackWithNull()
|
||||||
|
{
|
||||||
|
return callbackWithNull(null);
|
||||||
|
}
|
||||||
|
|
||||||
public Object callMethodThrowsException() throws Exception {
|
public Object callMethodThrowsException() throws Exception {
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
|
@ -1959,6 +1959,7 @@ enum class CallbackParameterType
|
|||||||
RawArray,
|
RawArray,
|
||||||
QList,
|
QList,
|
||||||
QStringList,
|
QStringList,
|
||||||
|
Null,
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::optional<TestClass> calledWithObject;
|
static std::optional<TestClass> calledWithObject;
|
||||||
@ -2047,6 +2048,14 @@ static int callbackWithStringList(JNIEnv *, jobject, const QStringList &value)
|
|||||||
}
|
}
|
||||||
Q_DECLARE_JNI_NATIVE_METHOD(callbackWithStringList)
|
Q_DECLARE_JNI_NATIVE_METHOD(callbackWithStringList)
|
||||||
|
|
||||||
|
static std::optional<QString> calledWithNull;
|
||||||
|
static int callbackWithNull(JNIEnv *, jobject, const QString &str)
|
||||||
|
{
|
||||||
|
calledWithNull.emplace(str);
|
||||||
|
return int(CallbackParameterType::Null);
|
||||||
|
}
|
||||||
|
Q_DECLARE_JNI_NATIVE_METHOD(callbackWithNull)
|
||||||
|
|
||||||
void tst_QJniObject::callback_data()
|
void tst_QJniObject::callback_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<CallbackParameterType>("parameterType");
|
QTest::addColumn<CallbackParameterType>("parameterType");
|
||||||
@ -2062,6 +2071,7 @@ void tst_QJniObject::callback_data()
|
|||||||
QTest::addRow("RawArray") << CallbackParameterType::RawArray;
|
QTest::addRow("RawArray") << CallbackParameterType::RawArray;
|
||||||
QTest::addRow("QList") << CallbackParameterType::QList;
|
QTest::addRow("QList") << CallbackParameterType::QList;
|
||||||
QTest::addRow("QStringList") << CallbackParameterType::QStringList;
|
QTest::addRow("QStringList") << CallbackParameterType::QStringList;
|
||||||
|
QTest::addRow("Null") << CallbackParameterType::Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QJniObject::callback()
|
void tst_QJniObject::callback()
|
||||||
@ -2171,6 +2181,15 @@ void tst_QJniObject::callback()
|
|||||||
QCOMPARE(calledWithStringList.value(), strings);
|
QCOMPARE(calledWithStringList.value(), strings);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CallbackParameterType::Null: {
|
||||||
|
QVERIFY(TestClass::registerNativeMethods({
|
||||||
|
Q_JNI_NATIVE_METHOD(callbackWithNull)
|
||||||
|
}));
|
||||||
|
result = testObject.callMethod<int>("callMeBackWithNull");
|
||||||
|
QVERIFY(calledWithNull);
|
||||||
|
QCOMPARE(calledWithNull.value(), QString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QCOMPARE(result, int(parameterType));
|
QCOMPARE(result, int(parameterType));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user