Skip to content

Commit

Permalink
Fix ExceptionFormatter not to use BinaryFormatter
Browse files Browse the repository at this point in the history
  • Loading branch information
sky1045 committed Jul 25, 2024
1 parent 3df0519 commit 36b69fb
Showing 1 changed file with 84 additions and 14 deletions.
98 changes: 84 additions & 14 deletions Lib9c.MessagePack/Formatters/ExceptionFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Buffers;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using MessagePack;
using MessagePack.Formatters;
Expand All @@ -19,14 +21,18 @@ public class ExceptionFormatter<T> : IMessagePackFormatter<T?> where T : Excepti
writer.WriteNil();
return;
}
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
var info = new SerializationInfo(typeof(T), new FormatterConverter());
value.GetObjectData(info, new StreamingContext(StreamingContextStates.All));

writer.WriteMapHeader(info.MemberCount + 1);
writer.Write("ExceptionType");
writer.Write(value.GetType().AssemblyQualifiedName);

foreach (SerializationEntry entry in info)
{
#pragma warning disable SYSLIB0011
formatter.Serialize(stream, value);
#pragma warning restore SYSLIB0011
var bytes = stream.ToArray();
writer.Write(bytes);
writer.Write(entry.Name);
writer.Write(entry.ObjectType.AssemblyQualifiedName);
MessagePackSerializer.Serialize(entry.ObjectType, ref writer, entry.Value, options);
}
}

Expand All @@ -39,15 +45,79 @@ public class ExceptionFormatter<T> : IMessagePackFormatter<T?> where T : Excepti
}

options.Security.DepthStep(ref reader);
var formatter = new BinaryFormatter();
byte[] bytes = reader.ReadBytes()?.ToArray()
?? throw new MessagePackSerializationException();
using (var stream = new MemoryStream(bytes))
var count = reader.ReadMapHeader();

var info = new SerializationInfo(typeof(T), new FormatterConverter());
string? typeName = null;

for (int i = 0; i < count; i++)
{
var name = reader.ReadString();
if (name == "ExceptionType")
{
typeName = reader.ReadString();
}
else
{
var type = Type.GetType(reader.ReadString());
var value = MessagePackSerializer.Deserialize(type, ref reader, options);
info.AddValue(name, value);
}
}

if (typeName == null)
{
throw new MessagePackSerializationException("Exception type information is missing.");
}

var exceptionType = Type.GetType(typeName);
if (exceptionType == null)
{
throw new MessagePackSerializationException($"Exception type '{typeName}' not found.");
}

var ctor = exceptionType.GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
null,
new Type[] { typeof(SerializationInfo), typeof(StreamingContext) },
null
);

if (ctor != null)
{
return (T)ctor.Invoke(new object[] { info, new StreamingContext(StreamingContextStates.All) });
}

var message = info.GetString("Message");
var innerException = (Exception?)info.GetValue("InnerException", typeof(Exception));

T? exception;
var constructorWithInnerException = exceptionType.GetConstructor(new[] { typeof(string), typeof(Exception) });
if (constructorWithInnerException != null)
{
#pragma warning disable SYSLIB0011
return (T)formatter.Deserialize(stream);
#pragma warning restore SYSLIB0011
exception = (T)constructorWithInnerException.Invoke(new object[] { message!, innerException! });
}
else
{
var constructorWithMessage = exceptionType.GetConstructor(new[] { typeof(string) });
if (constructorWithMessage != null)
{
exception = (T)constructorWithMessage.Invoke(new object[] { message! });
}
else
{
exception = (T?)Activator.CreateInstance(exceptionType);
}
}

var stackTrace = info.GetString("StackTraceString");
if (!string.IsNullOrEmpty(stackTrace))
{
var stackTraceField = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance);
stackTraceField?.SetValue(exception, stackTrace);
}

return exception;
}
}
}

0 comments on commit 36b69fb

Please sign in to comment.