Skip to content

Commit 20eadd7

Browse files
committed
[Java.Interop] Improve finalization support.
Finalizers may be run in any order, and if the process is being torn down and/or the JavaVM/JniEnvironment has been disposed, then it's not really valid to try to use anything that depends on them. Unfortunately, many of the SafeHandle types DO depend on them, via handle tracking; see commit d0b8f1d. This can result in an exception during process teardown: Unhandled Exception: System.ObjectDisposedException: The object was used after being disposed. at System.Threading.ThreadLocal`1[Java.Interop.JniEnvironment].get_Value () [0x00000] in <filename unknown>:0 at Java.Interop.JniEnvironment.get_RootEnvironment () [0x00006] in /Users/jon/Dropbox/Developer/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.cs:133 at Java.Interop.JniEnvironment.get_Current () [0x0000d] in /Users/jon/Dropbox/Developer/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.cs:123 at Java.Interop.JniMethodID.ReleaseHandle () [0x00001] in /Users/jon/Dropbox/Developer/Java.Interop/src/Java.Interop/Java.Interop/JniMethodID.cs:16 at System.Runtime.InteropServices.SafeHandle.Finalize () [0x00016] in /private/tmp/source-mono-mac-3.12.0-branch-32/bockbuild-mono-3.12.0-branch/profiles/mono-mac-xamarin/build-r JniEnvironment.Current is no more, the JavaVM was Dispose()d, and JniEnvironment.RootEnvironments was Dispose()d. To avoid this, add a JniEnvironment.HasCurrent property, which checks to see if JniEnvironment.Current would be valid (-ish; it just checks JniEnvironment.current, not JniEnvironment.RootEnvironments), and modify the *SafeHandle.ReleaseHandle() methods to only call JavaVM.UnTrack() if JniEnvironment.HasCurrent is true. Possible bug/something to ponder: should JavaVM actually dispose of JniEnvironment.RootEnvironments? 99.9999% of the time, that's the right thing to do, but if/when there's ever a JVM which allows having more than one JavaVM within the process, ever, then this could be problematic...
1 parent 6d66d5d commit 20eadd7

File tree

5 files changed

+12
-4
lines changed

5 files changed

+12
-4
lines changed

src/Java.Interop/Java.Interop/JniEnvironment.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ internal List<JniLocalReference> LocalReferences {
118118
get {return lrefs ?? (lrefs = new List<JniLocalReference> ());}
119119
}
120120

121+
internal static bool HasCurrent {
122+
get {return current != null;}
123+
}
124+
121125
public static JniEnvironment Current {
122126
get {
123127
return current ?? RootEnvironment;

src/Java.Interop/Java.Interop/JniFieldID.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ internal JniFieldID ()
1313

1414
protected override bool ReleaseHandle ()
1515
{
16-
JniEnvironment.Current.JavaVM.UnTrack (this);
16+
if (JniEnvironment.HasCurrent)
17+
JniEnvironment.Current.JavaVM.UnTrack (this);
1718
return true;
1819
}
1920

src/Java.Interop/Java.Interop/JniGlobalReference.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ namespace Java.Interop
88
public class JniGlobalReference : JniReferenceSafeHandle {
99
protected override bool ReleaseHandle ()
1010
{
11-
JniEnvironment.Current.JavaVM.JniHandleManager.DeleteGlobalReference (handle);
11+
if (JniEnvironment.HasCurrent)
12+
JniEnvironment.Current.JavaVM.JniHandleManager.DeleteGlobalReference (handle);
1213
return true;
1314
}
1415
}

src/Java.Interop/Java.Interop/JniMethodID.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ internal JniMethodID ()
1313

1414
protected override bool ReleaseHandle ()
1515
{
16-
JniEnvironment.Current.JavaVM.UnTrack (this);
16+
if (JniEnvironment.HasCurrent)
17+
JniEnvironment.Current.JavaVM.UnTrack (this);
1718
return true;
1819
}
1920

src/Java.Interop/Java.Interop/JniWeakGlobalReference.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ namespace Java.Interop
88
public class JniWeakGlobalReference : JniReferenceSafeHandle {
99
protected override bool ReleaseHandle ()
1010
{
11-
JniEnvironment.Current.JavaVM.JniHandleManager.DeleteWeakGlobalReference (handle);
11+
if (JniEnvironment.HasCurrent)
12+
JniEnvironment.Current.JavaVM.JniHandleManager.DeleteWeakGlobalReference (handle);
1213
return true;
1314
}
1415
}

0 commit comments

Comments
 (0)