Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Bug 1250: fix for missing FieldInfo
This fixes the error in bug #1250 by separately serializing the FieldInfo.

Probably this can be optimized a bunch. I haven't verified the performance
implications at all.
  • Loading branch information
benoithudson authored and BadSingleton committed Oct 20, 2020
commit 7d6e6e9c48fad1264e3f231b63d58448276f232c
131 changes: 122 additions & 9 deletions src/runtime/fieldobject.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace Python.Runtime
{
Expand All @@ -9,11 +12,97 @@ namespace Python.Runtime
[Serializable]
internal class FieldObject : ExtensionType
{
private FieldInfo info;
[Serializable]
private struct SerializedFieldInfo : ISerializable
{
// The field if we can find it. Otherwise null.
private FieldInfo m_info;

// The name of the field if the field is missing. Otherwise null.
private string m_name;

public SerializedFieldInfo(FieldInfo info)
{
if (info == null)
{
throw new System.ArgumentNullException("null FieldInfo");
}
m_info = info;
m_name = null;
}

public FieldInfo Value
{
get
{
if (m_info == null)
{
throw new SerializationException($".NET field {m_name} was renamed or removed during domain reload");
}
return m_info;
}
}

public string Name
{
get
{
if (m_info == null)
{
return $"(missing {m_name})";
}
else
{
return m_info.Name;
}
}
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (m_info == null)
{
info.AddValue("n", m_name);
}
else
{
// Serialize in a silly way. TODO optimize.
var formatter = new BinaryFormatter();
using (var ms = new MemoryStream())
{
formatter.Serialize(ms, m_info);
info.AddValue("i", ms.ToArray());
}

// Also save the name in case the info doesn't deserialize
info.AddValue("n", m_info.ToString());
}
}

private SerializedFieldInfo(SerializationInfo info, StreamingContext context)
{
try
{
var serialized = (byte[])info.GetValue("i", typeof(byte[]));
var formatter = new BinaryFormatter();
using (var ms = new MemoryStream(serialized))
{
m_info = (FieldInfo)formatter.Deserialize(ms);
}
}
catch (SerializationException _)
{
m_info = null;
}
m_name = (m_info != null) ? null : info.GetString("n");
}
}

private SerializedFieldInfo m_info;

public FieldObject(FieldInfo info)
{
this.info = info;
m_info = new SerializedFieldInfo(info);
}

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

if (self == null)
{
return IntPtr.Zero;
}
try
{
return self.tp_descr_get(ob, tp);
}
catch (Exception e)
{
Exceptions.SetError(Exceptions.TypeError, e.Message);
return IntPtr.Zero;
}
}

FieldInfo info = self.info;
IntPtr tp_descr_get(IntPtr ob, IntPtr tp)
{
FieldInfo info = m_info.Value;

if (ob == IntPtr.Zero || ob == Runtime.PyNone)
{
Expand All @@ -43,7 +143,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
}
try
{
result = info.GetValue(null);
var result = info.GetValue(null);
return Converter.ToPython(result, info.FieldType);
}
catch (Exception e)
Expand All @@ -61,7 +161,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
Exceptions.SetError(Exceptions.TypeError, "instance is not a clr object");
return IntPtr.Zero;
}
result = info.GetValue(co.inst);
var result = info.GetValue(co.inst);
return Converter.ToPython(result, info.FieldType);
}
catch (Exception e)
Expand All @@ -79,7 +179,6 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val)
{
var self = (FieldObject)GetManagedObject(ds);
object newval;

if (self == null)
{
Expand All @@ -91,8 +190,21 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
Exceptions.SetError(Exceptions.TypeError, "cannot delete field");
return -1;
}
try
{
return self.tp_descr_set(ob, val);
}
catch (Exception e)
{
Exceptions.SetError(Exceptions.TypeError, e.Message);
return -1;
}
}


FieldInfo info = self.info;
int tp_descr_set(IntPtr ob, IntPtr val)
{
FieldInfo info = m_info.Value;

if (info.IsLiteral || info.IsInitOnly)
{
Expand All @@ -111,6 +223,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
}
}

object newval;
if (!Converter.ToManaged(val, info.FieldType, out newval, true))
{
return -1;
Expand Down Expand Up @@ -147,7 +260,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
public static IntPtr tp_repr(IntPtr ob)
{
var self = (FieldObject)GetManagedObject(ob);
return Runtime.PyString_FromString($"<field '{self.info.Name}'>");
return Runtime.PyString_FromString($"<field '{self.m_info.Name}'>");
}
}
}