From: Marcus Comstedt Date: Sun, 1 Nov 2015 22:27:41 +0000 (+0100) Subject: Java: Don't use JNIEnv* captured by lambdas, it may be invalid for the context X-Git-Tag: libsigrok-0.4.0~129 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=c470ae86dade608f747340f6f0699d657d33fd21;p=libsigrok.git Java: Don't use JNIEnv* captured by lambdas, it may be invalid for the context --- diff --git a/bindings/java/org/sigrok/core/classes/classes.i b/bindings/java/org/sigrok/core/classes/classes.i index 894c72f7..681515c4 100644 --- a/bindings/java/org/sigrok/core/classes/classes.i +++ b/bindings/java/org/sigrok/core/classes/classes.i @@ -237,6 +237,40 @@ MAP_COMMON(const sigrok::ConfigKey *, std::set, $1 = jenv; %} +/* Thread safe JNIEnv handling */ + +%inline { +namespace { + class ScopedEnv { + public: + ScopedEnv(JavaVM *jvm); + ScopedEnv(const ScopedEnv &ref) = delete; + ~ScopedEnv(); + JNIEnv* operator-> () { return env; } + operator bool () const { return (bool)env; } + private: + JavaVM *jvm; + JNIEnv *env; + int env_status; + }; + ScopedEnv::ScopedEnv(JavaVM *jvm) : jvm(jvm), env(NULL) { + env_status = jvm->GetEnv((void **)&env, JNI_VERSION_1_2); + if (env_status == JNI_EDETACHED) { +%#if defined(__ANDROID__) + jvm->AttachCurrentThread(&env, NULL); +%#else + jvm->AttachCurrentThread((void **)&env, NULL); +%#endif + } + } + ScopedEnv::~ScopedEnv() { + if (env_status == JNI_EDETACHED) { + jvm->DetachCurrentThread(); + } + } +} +} + /* Support Java log callbacks. */ %typemap(javaimports) sigrok::Context @@ -255,6 +289,8 @@ typedef jobject jlogcallback; { void add_log_callback(JNIEnv *env, jlogcallback obj) { + JavaVM *jvm = NULL; + env->GetJavaVM(&jvm); jclass obj_class = env->GetObjectClass(obj); jmethodID method = env->GetMethodID(obj_class, "run", "(Lorg/sigrok/core/classes/LogLevel;Ljava/lang/String;)V"); @@ -267,6 +303,9 @@ typedef jobject jlogcallback; const sigrok::LogLevel *loglevel, std::string message) { + ScopedEnv env(jvm); + if (!env) + throw sigrok::Error(SR_ERR); jlong loglevel_addr = 0; *(const sigrok::LogLevel **) &loglevel_addr = loglevel; jobject loglevel_obj = env->NewObject( @@ -297,6 +336,8 @@ typedef jobject jdatafeedcallback; { void add_datafeed_callback(JNIEnv *env, jdatafeedcallback obj) { + JavaVM *jvm = NULL; + env->GetJavaVM(&jvm); jclass obj_class = env->GetObjectClass(obj); jmethodID method = env->GetMethodID(obj_class, "run", "(Lorg/sigrok/core/classes/Device;Lorg/sigrok/core/classes/Packet;)V"); @@ -312,6 +353,9 @@ typedef jobject jdatafeedcallback; std::shared_ptr device, std::shared_ptr packet) { + ScopedEnv env(jvm); + if (!env) + throw sigrok::Error(SR_ERR); jlong device_addr = 0; jlong packet_addr = 0; *(std::shared_ptr **) &device_addr =