Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

Commit 20edccb

Browse files
committed
[Java.Interop] Prevent premature collection w/ JniInstance* (#768)
Context: dotnet/android@e88cfbc While writing the commit message for xamarin/xamarin-android/@e88cfbcf, it occurred to me that the same fundamental scenario of: CallIntoJava (new JavaLangObjectSubclass ().Handle); // GC collects instance after `.Handle`, before `CallIntoJava()` could apply to `JniPeerMembers.JniInstanceMethods.Invoke*()` invocations: JniArgumentValue* __args = …; _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); // What prevents `this` from being collected "too soon"? Address this: update `JniPeerMembers.JniInstanceMethods.Invoke*()` so that there is a `GC.KeepAlive(self)` after accessing `self.PeerReference`. This will ensure that `self` isn't collected "during" `JniEnvironment.InstanceMethods.Call*Method()` invocations. Likewise update `JniPeerMembers.JniInstanceFields.Get*Value()` and `JniPeerMembers.JniInstanceFields.Set*Value()` so that there is a `GC.KeepAlive(self)` after the `JniEnvironment.InstanceFields.*` invocation.
1 parent 1d382be commit 20edccb

4 files changed

Lines changed: 168 additions & 90 deletions

File tree

‎src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs‎

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#nullable enable
22

3+
usingSystem;
4+
35
namespaceJava.Interop{
46

57
partialclassJniPeerMembers{
@@ -12,7 +14,9 @@ public bool GetBooleanValue (
1214
JniPeerMembers.AssertSelf(self);
1315

1416
varf=GetFieldInfo(encodedMember);
15-
returnJniEnvironment.InstanceFields.GetBooleanField(self.PeerReference,f);
17+
varr=JniEnvironment.InstanceFields.GetBooleanField(self.PeerReference,f);
18+
GC.KeepAlive(self);
19+
returnr;
1620
}
1721

1822
publicvoidSetValue(stringencodedMember,IJavaPeerableself,boolvalue)
@@ -21,6 +25,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, bool value)
2125

2226
varf=GetFieldInfo(encodedMember);
2327
JniEnvironment.InstanceFields.SetBooleanField(self.PeerReference,f,value);
28+
GC.KeepAlive(self);
2429
}
2530

2631
publicsbyteGetSByteValue(
@@ -30,7 +35,9 @@ public sbyte GetSByteValue (
3035
JniPeerMembers.AssertSelf(self);
3136

3237
varf=GetFieldInfo(encodedMember);
33-
returnJniEnvironment.InstanceFields.GetByteField(self.PeerReference,f);
38+
varr=JniEnvironment.InstanceFields.GetByteField(self.PeerReference,f);
39+
GC.KeepAlive(self);
40+
returnr;
3441
}
3542

3643
publicvoidSetValue(stringencodedMember,IJavaPeerableself,sbytevalue)
@@ -39,6 +46,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, sbyte value)
3946

4047
varf=GetFieldInfo(encodedMember);
4148
JniEnvironment.InstanceFields.SetByteField(self.PeerReference,f,value);
49+
GC.KeepAlive(self);
4250
}
4351

4452
publiccharGetCharValue(
@@ -48,7 +56,9 @@ public char GetCharValue (
4856
JniPeerMembers.AssertSelf(self);
4957

5058
varf=GetFieldInfo(encodedMember);
51-
returnJniEnvironment.InstanceFields.GetCharField(self.PeerReference,f);
59+
varr=JniEnvironment.InstanceFields.GetCharField(self.PeerReference,f);
60+
GC.KeepAlive(self);
61+
returnr;
5262
}
5363

5464
publicvoidSetValue(stringencodedMember,IJavaPeerableself,charvalue)
@@ -57,6 +67,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, char value)
5767

5868
varf=GetFieldInfo(encodedMember);
5969
JniEnvironment.InstanceFields.SetCharField(self.PeerReference,f,value);
70+
GC.KeepAlive(self);
6071
}
6172

6273
publicshortGetInt16Value(
@@ -66,7 +77,9 @@ public short GetInt16Value (
6677
JniPeerMembers.AssertSelf(self);
6778

6879
varf=GetFieldInfo(encodedMember);
69-
returnJniEnvironment.InstanceFields.GetShortField(self.PeerReference,f);
80+
varr=JniEnvironment.InstanceFields.GetShortField(self.PeerReference,f);
81+
GC.KeepAlive(self);
82+
returnr;
7083
}
7184

7285
publicvoidSetValue(stringencodedMember,IJavaPeerableself,shortvalue)
@@ -75,6 +88,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, short value)
7588

7689
varf=GetFieldInfo(encodedMember);
7790
JniEnvironment.InstanceFields.SetShortField(self.PeerReference,f,value);
91+
GC.KeepAlive(self);
7892
}
7993

8094
publicintGetInt32Value(
@@ -84,7 +98,9 @@ public int GetInt32Value (
8498
JniPeerMembers.AssertSelf(self);
8599

86100
varf=GetFieldInfo(encodedMember);
87-
returnJniEnvironment.InstanceFields.GetIntField(self.PeerReference,f);
101+
varr=JniEnvironment.InstanceFields.GetIntField(self.PeerReference,f);
102+
GC.KeepAlive(self);
103+
returnr;
88104
}
89105

90106
publicvoidSetValue(stringencodedMember,IJavaPeerableself,intvalue)
@@ -93,6 +109,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, int value)
93109

94110
varf=GetFieldInfo(encodedMember);
95111
JniEnvironment.InstanceFields.SetIntField(self.PeerReference,f,value);
112+
GC.KeepAlive(self);
96113
}
97114

98115
publiclongGetInt64Value(
@@ -102,7 +119,9 @@ public long GetInt64Value (
102119
JniPeerMembers.AssertSelf(self);
103120

104121
varf=GetFieldInfo(encodedMember);
105-
returnJniEnvironment.InstanceFields.GetLongField(self.PeerReference,f);
122+
varr=JniEnvironment.InstanceFields.GetLongField(self.PeerReference,f);
123+
GC.KeepAlive(self);
124+
returnr;
106125
}
107126

108127
publicvoidSetValue(stringencodedMember,IJavaPeerableself,longvalue)
@@ -111,6 +130,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, long value)
111130

112131
varf=GetFieldInfo(encodedMember);
113132
JniEnvironment.InstanceFields.SetLongField(self.PeerReference,f,value);
133+
GC.KeepAlive(self);
114134
}
115135

116136
publicfloatGetSingleValue(
@@ -120,7 +140,9 @@ public float GetSingleValue (
120140
JniPeerMembers.AssertSelf(self);
121141

122142
varf=GetFieldInfo(encodedMember);
123-
returnJniEnvironment.InstanceFields.GetFloatField(self.PeerReference,f);
143+
varr=JniEnvironment.InstanceFields.GetFloatField(self.PeerReference,f);
144+
GC.KeepAlive(self);
145+
returnr;
124146
}
125147

126148
publicvoidSetValue(stringencodedMember,IJavaPeerableself,floatvalue)
@@ -129,6 +151,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, float value)
129151

130152
varf=GetFieldInfo(encodedMember);
131153
JniEnvironment.InstanceFields.SetFloatField(self.PeerReference,f,value);
154+
GC.KeepAlive(self);
132155
}
133156

134157
publicdoubleGetDoubleValue(
@@ -138,7 +161,9 @@ public double GetDoubleValue (
138161
JniPeerMembers.AssertSelf(self);
139162

140163
varf=GetFieldInfo(encodedMember);
141-
returnJniEnvironment.InstanceFields.GetDoubleField(self.PeerReference,f);
164+
varr=JniEnvironment.InstanceFields.GetDoubleField(self.PeerReference,f);
165+
GC.KeepAlive(self);
166+
returnr;
142167
}
143168

144169
publicvoidSetValue(stringencodedMember,IJavaPeerableself,doublevalue)
@@ -147,6 +172,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, double value)
147172

148173
varf=GetFieldInfo(encodedMember);
149174
JniEnvironment.InstanceFields.SetDoubleField(self.PeerReference,f,value);
175+
GC.KeepAlive(self);
150176
}
151177

152178
publicJniObjectReferenceGetObjectValue(
@@ -156,7 +182,9 @@ public JniObjectReference GetObjectValue (
156182
JniPeerMembers.AssertSelf(self);
157183

158184
varf=GetFieldInfo(encodedMember);
159-
returnJniEnvironment.InstanceFields.GetObjectField(self.PeerReference,f);
185+
varr=JniEnvironment.InstanceFields.GetObjectField(self.PeerReference,f);
186+
GC.KeepAlive(self);
187+
returnr;
160188
}
161189

162190
publicvoidSetValue(stringencodedMember,IJavaPeerableself,JniObjectReferencevalue)
@@ -165,6 +193,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, JniObjectReferen
165193

166194
varf=GetFieldInfo(encodedMember);
167195
JniEnvironment.InstanceFields.SetObjectField(self.PeerReference,f,value);
196+
GC.KeepAlive(self);
168197
}
169198
}
170199

‎src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#>
2020
#nullable enable
2121

22+
using System;
23+
2224
namespace Java.Interop {
2325

2426
partial class JniPeerMembers {
@@ -34,7 +36,9 @@ namespace Java.Interop {
3436
JniPeerMembers.AssertSelf (self);
3537

3638
var f = GetFieldInfo (encodedMember);
37-
return JniEnvironment.InstanceFields.Get<#= info.JniCallType #>Field (self.PeerReference, f);
39+
var r = JniEnvironment.InstanceFields.Get<#= info.JniCallType #>Field (self.PeerReference, f);
40+
GC.KeepAlive (self);
41+
return r;
3842
}
3943

4044
public void SetValue (string encodedMember, IJavaPeerable self, <#= info.ParameterType #> value)
@@ -43,6 +47,7 @@ namespace Java.Interop {
4347

4448
var f = GetFieldInfo (encodedMember);
4549
JniEnvironment.InstanceFields.Set<#= info.JniCallType #>Field (self.PeerReference, f, value);
50+
GC.KeepAlive (self);
4651
}
4752
<#
4853
}

0 commit comments

Comments
 (0)