Skip to content

Commit da73d6a

Browse files
authored
[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 7574f16 commit da73d6a

4 files changed

+168
-90
lines changed

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

+38-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#nullable enable
22

3+
using System;
4+
35
namespace Java.Interop {
46

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

1416
var f = GetFieldInfo (encodedMember);
15-
return JniEnvironment.InstanceFields.GetBooleanField (self.PeerReference, f);
17+
var r = JniEnvironment.InstanceFields.GetBooleanField (self.PeerReference, f);
18+
GC.KeepAlive (self);
19+
return r;
1620
}
1721

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

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

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

3237
var f = GetFieldInfo (encodedMember);
33-
return JniEnvironment.InstanceFields.GetByteField (self.PeerReference, f);
38+
var r = JniEnvironment.InstanceFields.GetByteField (self.PeerReference, f);
39+
GC.KeepAlive (self);
40+
return r;
3441
}
3542

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

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

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

5058
var f = GetFieldInfo (encodedMember);
51-
return JniEnvironment.InstanceFields.GetCharField (self.PeerReference, f);
59+
var r = JniEnvironment.InstanceFields.GetCharField (self.PeerReference, f);
60+
GC.KeepAlive (self);
61+
return r;
5262
}
5363

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

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

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

6879
var f = GetFieldInfo (encodedMember);
69-
return JniEnvironment.InstanceFields.GetShortField (self.PeerReference, f);
80+
var r = JniEnvironment.InstanceFields.GetShortField (self.PeerReference, f);
81+
GC.KeepAlive (self);
82+
return r;
7083
}
7184

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

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

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

86100
var f = GetFieldInfo (encodedMember);
87-
return JniEnvironment.InstanceFields.GetIntField (self.PeerReference, f);
101+
var r = JniEnvironment.InstanceFields.GetIntField (self.PeerReference, f);
102+
GC.KeepAlive (self);
103+
return r;
88104
}
89105

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

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

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

104121
var f = GetFieldInfo (encodedMember);
105-
return JniEnvironment.InstanceFields.GetLongField (self.PeerReference, f);
122+
var r = JniEnvironment.InstanceFields.GetLongField (self.PeerReference, f);
123+
GC.KeepAlive (self);
124+
return r;
106125
}
107126

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

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

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

122142
var f = GetFieldInfo (encodedMember);
123-
return JniEnvironment.InstanceFields.GetFloatField (self.PeerReference, f);
143+
var r = JniEnvironment.InstanceFields.GetFloatField (self.PeerReference, f);
144+
GC.KeepAlive (self);
145+
return r;
124146
}
125147

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

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

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

140163
var f = GetFieldInfo (encodedMember);
141-
return JniEnvironment.InstanceFields.GetDoubleField (self.PeerReference, f);
164+
var r = JniEnvironment.InstanceFields.GetDoubleField (self.PeerReference, f);
165+
GC.KeepAlive (self);
166+
return r;
142167
}
143168

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

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

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

158184
var f = GetFieldInfo (encodedMember);
159-
return JniEnvironment.InstanceFields.GetObjectField (self.PeerReference, f);
185+
var r = JniEnvironment.InstanceFields.GetObjectField (self.PeerReference, f);
186+
GC.KeepAlive (self);
187+
return r;
160188
}
161189

162190
public void SetValue (string encodedMember, IJavaPeerable self, JniObjectReference value)
@@ -165,6 +193,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, JniObjectReferen
165193

166194
var f = 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

+6-1
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)