Author: amiloslavskiy Date: Thu Oct 15 10:15:47 2020 New Revision: 1882522 URL: http://svn.apache.org/viewvc?rev=1882522&view=rev Log: JavaHL: Fix crash in TunnelAgent.CloseTunnelCallback after GC
When jobject reference is kept across different JNI calls, a new global reference must be requested with NewGlobalRef(). Otherwise, GC is free to remove the object. Even if Java code keeps a reference to the object, GC can still move the object around, invalidating the kept jobject, which results in a native crash when trying to access it. This crash is demonstrated by the following JavaHL test: 'testCrash_RemoteSession_nativeDispose' [in subversion/bindings/javahl] * native/OperationContext.cpp (callCloseTunnelCallback): Extract function to facilitate changes in further commits. (openTunnel): Add NewGlobalRef() for kept jobject. (callCloseTunnelCallback): Add a matching DeleteGlobalRef(). Modified: subversion/branches/javahl-1.14-fixes/subversion/bindings/javahl/native/OperationContext.cpp Modified: subversion/branches/javahl-1.14-fixes/subversion/bindings/javahl/native/OperationContext.cpp URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.14-fixes/subversion/bindings/javahl/native/OperationContext.cpp?rev=1882522&r1=1882521&r2=1882522&view=diff ============================================================================== --- subversion/branches/javahl-1.14-fixes/subversion/bindings/javahl/native/OperationContext.cpp (original) +++ subversion/branches/javahl-1.14-fixes/subversion/bindings/javahl/native/OperationContext.cpp Thu Oct 15 10:15:47 2020 @@ -629,23 +629,17 @@ OperationContext::openTunnel(svn_stream_ jtunnel_name, juser, jhostname, jint(port)), SVN_ERR_BASE); + if (tc->jclosecb) + { + tc->jclosecb = env->NewGlobalRef(tc->jclosecb); + SVN_JNI_CATCH(, SVN_ERR_BASE); + } + return SVN_NO_ERROR; } -void -OperationContext::closeTunnel(void *tunnel_context, void *) +void callCloseTunnelCallback(JNIEnv* env, jobject jclosecb) { - TunnelContext* tc = static_cast<TunnelContext*>(tunnel_context); - jobject jclosecb = tc->jclosecb; - delete tc; - - if (!jclosecb) - return; - - JNIEnv *env = JNIUtil::getEnv(); - if (JNIUtil::isJavaExceptionThrown()) - return; - static jmethodID mid = 0; if (0 == mid) { @@ -656,4 +650,20 @@ OperationContext::closeTunnel(void *tunn SVN_JNI_CATCH_VOID(mid = env->GetMethodID(cls, "closeTunnel", "()V")); } SVN_JNI_CATCH_VOID(env->CallVoidMethod(jclosecb, mid)); + env->DeleteGlobalRef(jclosecb); +} + +void +OperationContext::closeTunnel(void *tunnel_context, void *) +{ + TunnelContext* tc = static_cast<TunnelContext*>(tunnel_context); + jobject jclosecb = tc->jclosecb; + delete tc; + + JNIEnv *env = JNIUtil::getEnv(); + if (JNIUtil::isJavaExceptionThrown()) + return; + + if (jclosecb) + callCloseTunnelCallback(env, jclosecb); }