diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index 260e523cf..ba1627856 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -111,6 +111,44 @@ namespace { bool finishInitializing(); }; + // + // RAII construct for calling AttachCurrentThread and DetachCurrent automatically + // + struct ScopedJNIThreadAttacher { + + JavaVM *jvm; + JNIEnv **env_p; + jint getEnvRet; + + ScopedJNIThreadAttacher(JavaVM *jvmIn, JNIEnv **env_pIn, jint getEnvRetIn) : + jvm(jvmIn), + env_p(env_pIn), + getEnvRet(getEnvRetIn) { + + if (getEnvRet != JNI_EDETACHED) { + return; + } + + jint attachCurrentThreadRet; + if ((attachCurrentThreadRet = jvm->AttachCurrentThread(env_p, NULL)) != JNI_OK) { + LOGE("Error calling AttachCurrentThread: %d", attachCurrentThreadRet); + assert(false && "Error calling AttachCurrentThread"); + } + } + + ~ScopedJNIThreadAttacher() { + + if (getEnvRet != JNI_EDETACHED) { + return; + } + + jint detachCurrentThreadRet; + if ((detachCurrentThreadRet = jvm->DetachCurrentThread()) != JNI_OK) { + LOGE("Error calling DetachCurrentThread: %d", detachCurrentThreadRet); + assert(false && "Error calling DetachCurrentThread"); + } + } + }; /* * This must return 0 on success. It can return any OS-dependent error code @@ -197,11 +235,23 @@ namespace { jint getEnvRet; assert(ref->jvm); - if ((getEnvRet = ref->jvm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6)) != JNI_OK) { + getEnvRet = ref->jvm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + + if (!(getEnvRet == JNI_OK || getEnvRet == JNI_EDETACHED)) { LOGE("Error calling GetEnv: %d", getEnvRet); assert(false && "Error calling GetEnv"); } + // + // Thread might actually be detached. + // + // e.g: + // https://github.com/zerotier/ZeroTierOne/blob/91e7ce87f09ac1cfdeaf6ff22c3cedcd93574c86/node/Switch.cpp#L519 + // + // Make sure to attach if needed + // + ScopedJNIThreadAttacher attacher{ref->jvm, &env, getEnvRet}; + if (env->ExceptionCheck()) { LOGE("Unhandled pending exception"); return;