From ed2fbed47913139c1187ef89b454b36f5f78ac83 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 11 Oct 2023 13:37:31 +0200 Subject: [PATCH] JNI: emit warning in debug mode in case of JNI environment conflicts If a QJniObject method that uses the stored JNIEnv pointer is called from a different thread than the one the object was created in, then a FATAL abort of the JNI runtime is likely, but hard to debug (the error messages from JNI are visible in the logcat log of adb). In debug mode, compare the stored JNIEnv pointer with the one provided for the current thread, and emit a critical runtime warning if they do not match, as this indicates a race condition to the underlying JAVA object. Change-Id: Ief578f445bcfab1939ddbe95c6ba796279be9115 Reviewed-by: Assam Boudjelthia --- src/corelib/kernel/qjniobject.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp index 5a5239fc63d..a6245aa79bc 100644 --- a/src/corelib/kernel/qjniobject.cpp +++ b/src/corelib/kernel/qjniobject.cpp @@ -736,9 +736,20 @@ QJniObject::~QJniObject() {} /*! \internal + + While we can synchronize concurrent access to a QJniObject on the C++ side, + we cannot synchronize access across C++ and Java, so any concurrent access to + a QJniObject, except the most basic ref-counting operations (destructor and + assignment) is wrong. All calls must happen from the thread that created the + QJniObject. */ JNIEnv *QJniObject::jniEnv() const noexcept { + Q_ASSERT_X([this]{ + QJniEnvironment currentThreadEnv; + return currentThreadEnv.jniEnv() == d->jniEnv(); + }(), __FUNCTION__, "QJniEnvironment mismatch, probably accessing this Java object" + " from the wrong thread!"); return d->jniEnv(); }