From a81f3bfade47c677dbc9af2622d4de77c724bdd0 Mon Sep 17 00:00:00 2001 From: "pedemont%us.ibm.com" Date: Tue, 6 Jun 2006 17:13:18 +0000 Subject: [PATCH] Bug 339947 - Java XPCOM proxies can get used (resurrected) after having been garbage collected causing VM crash. XULRunner only. patch by ttudor/jhpedemonte, r=jhpedemonte. git-svn-id: svn://10.0.0.236/trunk@199133 18797224-902f-48f8-a5cc-f745e15eee43 --- .../java/xpcom/nsJavaXPCOMBindingUtils.cpp | 45 +++++++++++++++---- .../java/xpcom/nsJavaXPCOMBindingUtils.h | 4 ++ .../extensions/java/xpcom/nsJavaXPTCStub.cpp | 22 ++++++--- .../extensions/java/xpcom/nsJavaXPTCStub.h | 2 +- .../java/xpcom/nsJavaXPTCStubWeakRef.cpp | 14 ++++-- .../java/xpcom/nsJavaXPTCStubWeakRef.h | 2 +- 6 files changed, 67 insertions(+), 22 deletions(-) diff --git a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp index d34f4b26c5e..2ba718b93ba 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp @@ -62,6 +62,7 @@ jclass stringClass = nsnull; jclass nsISupportsClass = nsnull; jclass xpcomExceptionClass = nsnull; jclass xpcomJavaProxyClass = nsnull; +jclass weakReferenceClass = nsnull; jmethodID hashCodeMID = nsnull; jmethodID booleanValueMID = nsnull; @@ -83,6 +84,9 @@ jmethodID doubleInitMID = nsnull; jmethodID createProxyMID = nsnull; jmethodID isXPCOMJavaProxyMID = nsnull; jmethodID getNativeXPCOMInstMID = nsnull; +jmethodID weakReferenceConstructorMID = nsnull; +jmethodID getReferentMID = nsnull; +jmethodID clearReferentMID = nsnull; #ifdef DEBUG_JAVAXPCOM jmethodID getNameMID = nsnull; @@ -255,6 +259,19 @@ InitializeJavaGlobals(JNIEnv *env) goto init_error; } + if (!(clazz = env->FindClass("java/lang/ref/WeakReference")) || + !(weakReferenceClass = (jclass) env->NewGlobalRef(clazz)) || + !(weakReferenceConstructorMID = env->GetMethodID(weakReferenceClass, + "","(Ljava/lang/Object;)V")) || + !(getReferentMID = env->GetMethodID(weakReferenceClass, + "get", "()Ljava/lang/Object;")) || + !(clearReferentMID = env->GetMethodID(weakReferenceClass, + "clear", "()V"))) + { + NS_WARNING("Problem creating java.lang.ref.WeakReference globals"); + goto init_error; + } + #ifdef DEBUG_JAVAXPCOM if (!(clazz = env->FindClass("java/lang/Class")) || !(getNameMID = env->GetMethodID(clazz, "getName","()Ljava/lang/String;"))) @@ -392,6 +409,10 @@ FreeJavaGlobals(JNIEnv* env) env->DeleteGlobalRef(xpcomJavaProxyClass); xpcomJavaProxyClass = nsnull; } + if (weakReferenceClass) { + env->DeleteGlobalRef(weakReferenceClass); + weakReferenceClass = nsnull; + } if (gJavaKeywords) { delete gJavaKeywords; @@ -449,7 +470,7 @@ DestroyJavaProxyMappingEnum(PLDHashTable* aTable, PLDHashEntryHdr* aHeader, NativeToJavaProxyMap::ProxyList* item = entry->list; while(item != nsnull) { void* xpcom_obj; - jobject javaObject = env->NewLocalRef(item->javaObject); + jobject javaObject = env->CallObjectMethod(item->javaObject, getReferentMID); rv = GetXPCOMInstFromProxy(env, javaObject, &xpcom_obj); NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get XPCOM instance from Java proxy"); @@ -466,6 +487,8 @@ DestroyJavaProxyMappingEnum(PLDHashTable* aTable, PLDHashEntryHdr* aHeader, } NativeToJavaProxyMap::ProxyList* next = item->next; + env->CallVoidMethod(item->javaObject, clearReferentMID); + env->DeleteGlobalRef(item->javaObject); delete item; item = next; } @@ -498,11 +521,15 @@ NativeToJavaProxyMap::Add(JNIEnv* env, nsISupports* aXPCOMObject, if (!e) return NS_ERROR_FAILURE; - jweak ref = env->NewWeakGlobalRef(aProxy); + jobject ref = nsnull; + jobject weakRefObj = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aProxy); + if (weakRefObj) + ref = env->NewGlobalRef(weakRefObj); if (!ref) return NS_ERROR_OUT_OF_MEMORY; - // Add Java proxy ref to start of list + // Add Java proxy weak reference ref to start of list ProxyList* item = new ProxyList(ref, aIID, e->list); e->key = aXPCOMObject; e->list = item; @@ -538,9 +565,10 @@ NativeToJavaProxyMap::Find(JNIEnv* env, nsISupports* aNativeObject, ProxyList* item = e->list; while (item != nsnull && *aResult == nsnull) { if (item->iid.Equals(aIID)) { - jobject javaObject = env->NewLocalRef(item->javaObject); - if (javaObject) { - *aResult = javaObject; + jobject referentObj = env->CallObjectMethod(item->javaObject, + getReferentMID); + if (!env->IsSameObject(referentObj, NULL)) { + *aResult = referentObj; #ifdef DEBUG_JAVAXPCOM char* iid_str = aIID.ToString(); LOG(("< NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", @@ -584,9 +612,8 @@ NativeToJavaProxyMap::Remove(JNIEnv* env, nsISupports* aNativeObject, PR_Free(iid_str); #endif - jweak weakref = NS_STATIC_CAST(jweak, - NS_CONST_CAST(jobject, item->javaObject)); - env->DeleteWeakGlobalRef(weakref); + env->CallVoidMethod(item->javaObject, clearReferentMID); + env->DeleteGlobalRef(item->javaObject); if (item == e->list) { e->list = item->next; if (e->list == nsnull) diff --git a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h index d9da29f69cc..1afb2594b90 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h +++ b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h @@ -74,6 +74,7 @@ extern jclass stringClass; extern jclass nsISupportsClass; extern jclass xpcomExceptionClass; extern jclass xpcomJavaProxyClass; +extern jclass weakReferenceClass; extern jmethodID hashCodeMID; extern jmethodID booleanValueMID; @@ -95,6 +96,9 @@ extern jmethodID doubleInitMID; extern jmethodID createProxyMID; extern jmethodID isXPCOMJavaProxyMID; extern jmethodID getNativeXPCOMInstMID; +extern jmethodID weakReferenceConstructorMID; +extern jmethodID getReferentMID; +extern jmethodID clearReferentMID; #ifdef DEBUG_JAVAXPCOM extern jmethodID getNameMID; diff --git a/mozilla/extensions/java/xpcom/nsJavaXPTCStub.cpp b/mozilla/extensions/java/xpcom/nsJavaXPTCStub.cpp index 805b9e00335..c9dcb7f7518 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPTCStub.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaXPTCStub.cpp @@ -53,7 +53,9 @@ nsJavaXPTCStub::nsJavaXPTCStub(jobject aJavaObject, nsIInterfaceInfo *aIInfo) , mWeakRefCnt(0) { JNIEnv* env = GetJNIEnv(); - mJavaWeakRef = env->NewWeakGlobalRef(aJavaObject); + jobject weakref = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aJavaObject); + mJavaWeakRef = env->NewGlobalRef(weakref); #ifdef DEBUG_JAVAXPCOM nsIID* iid; @@ -77,7 +79,11 @@ nsJavaXPTCStub::AddRefInternal() // If this is the first AddRef call, we create a strong global ref to the // Java object to keep it from being garbage collected. if (mRefCnt == 0) { - mJavaStrongRef = GetJNIEnv()->NewGlobalRef(mJavaWeakRef); + JNIEnv* env = GetJNIEnv(); + jobject referent = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + if (!env->IsSameObject(referent, NULL)) { + mJavaStrongRef = env->NewGlobalRef(referent); + } NS_ASSERTION(mJavaStrongRef != nsnull, "Failed to acquire strong ref"); } @@ -179,7 +185,8 @@ nsJavaXPTCStub::Destroy() } } - env->DeleteWeakGlobalRef(mJavaWeakRef); + env->CallVoidMethod(mJavaWeakRef, clearReferentMID); + env->DeleteGlobalRef(mJavaWeakRef); } void @@ -255,7 +262,7 @@ nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr) // Query Java object LOG(("\tCalling Java object queryInterface\n")); - jobject javaObject = env->NewLocalRef(mJavaWeakRef); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); jmethodID qiMID = 0; jclass clazz = env->GetObjectClass(javaObject); @@ -390,7 +397,7 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, nsresult rv = NS_OK; JNIEnv* env = GetJNIEnv(); - jobject javaObject = env->NewLocalRef(mJavaWeakRef); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); nsCAutoString methodSig("("); @@ -1682,7 +1689,8 @@ nsJavaXPTCStub::GetWeakReference(nsIWeakReference** aInstancePtr) if (!aInstancePtr) return NS_ERROR_NULL_POINTER; - jobject javaObject = GetJNIEnv()->NewLocalRef(mJavaWeakRef); + jobject javaObject = GetJNIEnv()->CallObjectMethod(mJavaWeakRef, + getReferentMID); nsJavaXPTCStubWeakRef* weakref; weakref = new nsJavaXPTCStubWeakRef(javaObject, this); if (!weakref) @@ -1699,7 +1707,7 @@ jobject nsJavaXPTCStub::GetJavaObject() { JNIEnv* env = GetJNIEnv(); - jobject javaObject = env->NewLocalRef(mJavaWeakRef); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); #ifdef DEBUG_JAVAXPCOM nsIID* iid; diff --git a/mozilla/extensions/java/xpcom/nsJavaXPTCStub.h b/mozilla/extensions/java/xpcom/nsJavaXPTCStub.h index 29b5bef1bd1..64a44769e4a 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPTCStub.h +++ b/mozilla/extensions/java/xpcom/nsJavaXPTCStub.h @@ -119,7 +119,7 @@ private: jvalue &aJValue); nsresult SetXPCOMRetval(); - jweak mJavaWeakRef; + jobject mJavaWeakRef; jobject mJavaStrongRef; nsCOMPtr mIInfo; diff --git a/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.cpp b/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.cpp index 7cdb4a98028..cb98fc9bd78 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.cpp @@ -60,12 +60,17 @@ nsJavaXPTCStubWeakRef::nsJavaXPTCStubWeakRef(jobject aJavaObject, nsJavaXPTCStub* aXPTCStub) : mXPTCStub(aXPTCStub) { - mWeakRef = GetJNIEnv()->NewWeakGlobalRef(aJavaObject); + JNIEnv* env = GetJNIEnv(); + jobject weakref = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aJavaObject); + mWeakRef = env->NewGlobalRef(weakref); } nsJavaXPTCStubWeakRef::~nsJavaXPTCStubWeakRef() { - GetJNIEnv()->DeleteWeakGlobalRef(mWeakRef); + JNIEnv* env = GetJNIEnv(); + env->CallVoidMethod(mWeakRef, clearReferentMID); + env->DeleteGlobalRef(mWeakRef); mXPTCStub->ReleaseWeakRef(); } @@ -82,8 +87,9 @@ nsJavaXPTCStubWeakRef::QueryReferent(const nsIID& aIID, void** aInstancePtr) // Is weak ref still valid? // We create a strong local ref to make sure Java object isn't garbage // collected during this call. - jobject javaObject = GetJNIEnv()->NewLocalRef(mWeakRef); - if (!javaObject) + JNIEnv* env = GetJNIEnv(); + jobject javaObject = env->CallObjectMethod(mWeakRef, getReferentMID); + if (env->IsSameObject(javaObject, NULL)) return NS_ERROR_NULL_POINTER; // Java object has not been garbage collected, so return QI from XPTCStub. diff --git a/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.h b/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.h index a53ffce7989..b538eecb4c2 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.h +++ b/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.h @@ -56,7 +56,7 @@ public: NS_DECL_NSIWEAKREFERENCE protected: - jweak mWeakRef; + jobject mWeakRef; nsJavaXPTCStub* mXPTCStub; };