Skip to content

Commit 581a19a

Browse files
author
benoithudson
committed
Bug 1250: fix for missing FieldInfo
This fixes the error in bug pythonnet#1250 by separately serializing the FieldInfo. Probably this can be optimized a bunch. I haven't verified the performance implications at all.
1 parent 18d3b13 commit 581a19a

File tree

1 file changed

+122
-9
lines changed

1 file changed

+122
-9
lines changed

src/runtime/fieldobject.cs

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using System;
22
using System.Reflection;
3+
using System.Runtime.Serialization;
4+
using System.Runtime.Serialization.Formatters.Binary;
5+
using System.IO;
36

47
namespace Python.Runtime
58
{
@@ -9,11 +12,97 @@ namespace Python.Runtime
912
[Serializable]
1013
internal class FieldObject : ExtensionType
1114
{
12-
private FieldInfo info;
15+
[Serializable]
16+
private struct SerializedFieldInfo : ISerializable
17+
{
18+
// The field if we can find it. Otherwise null.
19+
private FieldInfo m_info;
20+
21+
// The name of the field if the field is missing. Otherwise null.
22+
private string m_name;
23+
24+
public SerializedFieldInfo(FieldInfo info)
25+
{
26+
if (info == null)
27+
{
28+
throw new System.ArgumentNullException("null FieldInfo");
29+
}
30+
m_info = info;
31+
m_name = null;
32+
}
33+
34+
public FieldInfo Value
35+
{
36+
get
37+
{
38+
if (m_info == null)
39+
{
40+
throw new SerializationException($".NET field {m_name} was renamed or removed during domain reload");
41+
}
42+
return m_info;
43+
}
44+
}
45+
46+
public string Name
47+
{
48+
get
49+
{
50+
if (m_info == null)
51+
{
52+
return $"(missing {m_name})";
53+
}
54+
else
55+
{
56+
return m_info.Name;
57+
}
58+
}
59+
}
60+
61+
public void GetObjectData(SerializationInfo info, StreamingContext context)
62+
{
63+
if (m_info == null)
64+
{
65+
info.AddValue("n", m_name);
66+
}
67+
else
68+
{
69+
// Serialize in a silly way. TODO optimize.
70+
var formatter = new BinaryFormatter();
71+
using (var ms = new MemoryStream())
72+
{
73+
formatter.Serialize(ms, m_info);
74+
info.AddValue("i", ms.ToArray());
75+
}
76+
77+
// Also save the name in case the info doesn't deserialize
78+
info.AddValue("n", m_info.ToString());
79+
}
80+
}
81+
82+
private SerializedFieldInfo(SerializationInfo info, StreamingContext context)
83+
{
84+
try
85+
{
86+
var serialized = (byte[])info.GetValue("i", typeof(byte[]));
87+
var formatter = new BinaryFormatter();
88+
using (var ms = new MemoryStream(serialized))
89+
{
90+
m_info = (FieldInfo)formatter.Deserialize(ms);
91+
}
92+
}
93+
catch (SerializationException _)
94+
{
95+
m_info = null;
96+
}
97+
m_name = (m_info != null) ? null : info.GetString("n");
98+
}
99+
}
100+
101+
private SerializedFieldInfo m_info;
13102

14103
public FieldObject(FieldInfo info)
15104
{
16-
this.info = info;
105+
m_info = new SerializedFieldInfo(info);
17106
}
18107

19108
/// <summary>
@@ -24,14 +113,25 @@ public FieldObject(FieldInfo info)
24113
public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
25114
{
26115
var self = (FieldObject)GetManagedObject(ds);
27-
object result;
28116

29117
if (self == null)
30118
{
31119
return IntPtr.Zero;
32120
}
121+
try
122+
{
123+
return self.tp_descr_get(ob, tp);
124+
}
125+
catch (Exception e)
126+
{
127+
Exceptions.SetError(Exceptions.TypeError, e.Message);
128+
return IntPtr.Zero;
129+
}
130+
}
33131

34-
FieldInfo info = self.info;
132+
IntPtr tp_descr_get(IntPtr ob, IntPtr tp)
133+
{
134+
FieldInfo info = m_info.Value;
35135

36136
if (ob == IntPtr.Zero || ob == Runtime.PyNone)
37137
{
@@ -43,7 +143,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
43143
}
44144
try
45145
{
46-
result = info.GetValue(null);
146+
var result = info.GetValue(null);
47147
return Converter.ToPython(result, info.FieldType);
48148
}
49149
catch (Exception e)
@@ -61,7 +161,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
61161
Exceptions.SetError(Exceptions.TypeError, "instance is not a clr object");
62162
return IntPtr.Zero;
63163
}
64-
result = info.GetValue(co.inst);
164+
var result = info.GetValue(co.inst);
65165
return Converter.ToPython(result, info.FieldType);
66166
}
67167
catch (Exception e)
@@ -79,7 +179,6 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
79179
public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val)
80180
{
81181
var self = (FieldObject)GetManagedObject(ds);
82-
object newval;
83182

84183
if (self == null)
85184
{
@@ -91,8 +190,21 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
91190
Exceptions.SetError(Exceptions.TypeError, "cannot delete field");
92191
return -1;
93192
}
193+
try
194+
{
195+
return self.tp_descr_set(ob, val);
196+
}
197+
catch (Exception e)
198+
{
199+
Exceptions.SetError(Exceptions.TypeError, e.Message);
200+
return -1;
201+
}
202+
}
203+
94204

95-
FieldInfo info = self.info;
205+
int tp_descr_set(IntPtr ob, IntPtr val)
206+
{
207+
FieldInfo info = m_info.Value;
96208

97209
if (info.IsLiteral || info.IsInitOnly)
98210
{
@@ -111,6 +223,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
111223
}
112224
}
113225

226+
object newval;
114227
if (!Converter.ToManaged(val, info.FieldType, out newval, true))
115228
{
116229
return -1;
@@ -147,7 +260,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
147260
public static IntPtr tp_repr(IntPtr ob)
148261
{
149262
var self = (FieldObject)GetManagedObject(ob);
150-
return Runtime.PyString_FromString($"<field '{self.info.Name}'>");
263+
return Runtime.PyString_FromString($"<field '{self.m_info.Name}'>");
151264
}
152265
}
153266
}

0 commit comments

Comments
 (0)