// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System.Reflection;
using System.Collections;
using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
using System.Runtime.Remoting.Messaging;
using System.Security.Permissions;
namespace System.Runtime.Serialization.Formatters.Binary {
- public sealed class BinaryFormatter : IRemotingFormatter, IFormatter
+ [ComVisible (true)]
+ public sealed class BinaryFormatter :
+#if !FULL_AOT_RUNTIME
+ IRemotingFormatter,
+#endif
+ IFormatter
{
- private FormatterAssemblyStyle assembly_format = FormatterAssemblyStyle.Full;
+ private FormatterAssemblyStyle assembly_format = FormatterAssemblyStyle.Simple;
private SerializationBinder binder;
private StreamingContext context;
private ISurrogateSelector surrogate_selector;
private FormatterTypeStyle type_format = FormatterTypeStyle.TypesAlways;
-
-#if NET_1_1
- private TypeFilterLevel filter_level;
-#endif
+ private TypeFilterLevel filter_level = TypeFilterLevel.Full;
public BinaryFormatter()
{
- surrogate_selector=null;
+ surrogate_selector=DefaultSurrogateSelector;
context=new StreamingContext(StreamingContextStates.All);
}
surrogate_selector=selector;
this.context=context;
}
+
+ // Deserializing objects of type Dictionary<,> List<> and friends does not work in a CoreCLR sandbox, because
+ // the default deserialization code uses reflection to do its job, and the fields being reflected on live in mscorlib.dll.
+ // DefaultSurrogateSelector enables embedders to provide an alternative method of deserializing specific types in a way
+ // that does not violate the CoreCLR rules. See https://gist.github.com/878267 for some actual code that provides CoreCLR safe
+ // deserialization code for List<> and Dictionary<,>.
+ // DefaultSurrogateSelector is private, and needs to be set by the embedder trough reflection, so we do not expose any public
+ // API point that is not present in .NET
+ static ISurrogateSelector DefaultSurrogateSelector { get; set; }
+
public FormatterAssemblyStyle AssemblyFormat
{
get {
}
}
-#if NET_1_1
- [System.Runtime.InteropServices.ComVisible (false)]
public TypeFilterLevel FilterLevel
{
get { return filter_level; }
set { filter_level = value; }
}
-#endif
- public object Deserialize(Stream serializationStream)
+ [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
+ public object Deserialize (Stream serializationStream)
{
- return Deserialize (serializationStream, null);
+ return NoCheckDeserialize (serializationStream, null);
}
- public object Deserialize(Stream serializationStream, HeaderHandler handler)
+ [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
+ public object Deserialize (Stream serializationStream, HeaderHandler handler)
{
- if(serializationStream==null) \r
+ return NoCheckDeserialize (serializationStream, handler);
+ }
+
+ // shared by Deserialize and UnsafeDeserialize which both involve different security checks
+ private object NoCheckDeserialize (Stream serializationStream, HeaderHandler handler)
+ {
+ if(serializationStream==null)
{
- throw new ArgumentNullException("serializationStream is null");
+ throw new ArgumentNullException("serializationStream");
}
if(serializationStream.CanSeek &&
- serializationStream.Length==0) \r
+ serializationStream.Length==0)
{
throw new SerializationException("serializationStream supports seeking, but its length is 0");
}
// Messages are read using a special static method, which does not use ObjectReader
// if it is not needed. This saves time and memory.
- BinaryElement elem = (BinaryElement) reader.PeekChar();
+ BinaryElement elem = (BinaryElement) reader.Read ();
if (elem == BinaryElement.MethodCall) {
- return MessageFormatter.ReadMethodCall (reader, hasHeader, handler, this);
+ return MessageFormatter.ReadMethodCall (elem, reader, hasHeader, handler, this);
}
else if (elem == BinaryElement.MethodResponse) {
- return MessageFormatter.ReadMethodResponse (reader, hasHeader, handler, null, this);
+ return MessageFormatter.ReadMethodResponse (elem, reader, hasHeader, handler, null, this);
}
else {
ObjectReader serializer = new ObjectReader (this);
object result;
Header[] headers;
- serializer.ReadObjectGraph (reader, hasHeader, out result, out headers);
+ serializer.ReadObjectGraph (elem, reader, hasHeader, out result, out headers);
if (handler != null) handler(headers);
return result;
}
}
- public object DeserializeMethodResponse(Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallmessage)
+ [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
+ public object DeserializeMethodResponse (Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallMessage)
+ {
+ return NoCheckDeserializeMethodResponse (serializationStream, handler, methodCallMessage);
+ }
+
+ // shared by DeserializeMethodResponse and UnsafeDeserializeMethodResponse which both involve different security checks
+ private object NoCheckDeserializeMethodResponse (Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallMessage)
{
if(serializationStream==null) {
- throw new ArgumentNullException("serializationStream is null");
+ throw new ArgumentNullException("serializationStream");
}
if(serializationStream.CanSeek &&
serializationStream.Length==0) {
bool hasHeader;
ReadBinaryHeader (reader, out hasHeader);
- return MessageFormatter.ReadMethodResponse (reader, hasHeader, handler, methodCallmessage, this);
+ return MessageFormatter.ReadMethodResponse (reader, hasHeader, handler, methodCallMessage, this);
}
public void Serialize(Stream serializationStream, object graph)
}
BinaryWriter writer = new BinaryWriter (serializationStream);
- WriteBinaryHeader (writer, headers!=null);\r
-\r
- if (graph is IMethodCallMessage) {\r
- MessageFormatter.WriteMethodCall (writer, graph, headers, surrogate_selector, context, assembly_format, type_format);\r
- }\r
- else if (graph is IMethodReturnMessage) {\r
- MessageFormatter.WriteMethodResponse (writer, graph, headers, surrogate_selector, context, assembly_format, type_format);\r
- }\r
- else {\r
- ObjectWriter serializer = new ObjectWriter (surrogate_selector, context, assembly_format, type_format);
+ WriteBinaryHeader (writer, headers!=null);
+
+ if (graph is IMethodCallMessage) {
+ MessageFormatter.WriteMethodCall (writer, graph, headers, this);
+ }
+ else if (graph is IMethodReturnMessage) {
+ MessageFormatter.WriteMethodResponse (writer, graph, headers, this);
+ }
+ else {
+ ObjectWriter serializer = new ObjectWriter (this);
serializer.WriteObjectGraph (writer, graph, headers);
}
writer.Flush();
}
-\r
- [MonoTODO]
- [System.Runtime.InteropServices.ComVisible (false)]
- public object UnsafeDeserialize(Stream serializationStream, HeaderHandler handler)
+
+ // faster version (under CAS) as this requires a LinkDemand versus full Demand (i.e. a stack-walk)
+ // shouldn't be called unless the code is intended to be executed at full-trust
+ [ComVisible (false)]
+ [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
+ public object UnsafeDeserialize (Stream serializationStream, HeaderHandler handler)
{
- throw new NotImplementedException ();
+ return NoCheckDeserialize (serializationStream, handler);
}
- [MonoTODO]
- [System.Runtime.InteropServices.ComVisible (false)]
- public object UnsafeDeserializeMethodResponse(Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallmessage)
+ // faster version (under CAS) as this requires a LinkDemand versus full Demand (i.e. a stack-walk)
+ // shouldn't be called unless the code is intended to be executed at full-trust
+ [ComVisible (false)]
+ [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
+ public object UnsafeDeserializeMethodResponse (Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallMessage)
{
- throw new NotImplementedException ();
+ return NoCheckDeserializeMethodResponse (serializationStream, handler, methodCallMessage);
}
- private void WriteBinaryHeader (BinaryWriter writer, bool hasHeaders)\r
- {\r
- writer.Write ((byte)BinaryElement.Header);\r
- writer.Write ((int)1);\r
- if (hasHeaders) writer.Write ((int)2);\r
- else writer.Write ((int)-1);\r
- writer.Write ((int)1);\r
- writer.Write ((int)0);\r
- }\r
-\r
- private void ReadBinaryHeader (BinaryReader reader, out bool hasHeaders)\r
- {\r
- reader.ReadByte();\r
- reader.ReadInt32();\r
- int val = reader.ReadInt32();\r
- hasHeaders = (val==2);\r
- reader.ReadInt32();\r
- reader.ReadInt32();\r
- }\r
+ private void WriteBinaryHeader (BinaryWriter writer, bool hasHeaders)
+ {
+ writer.Write ((byte)BinaryElement.Header);
+ writer.Write ((int)1);
+ if (hasHeaders) writer.Write ((int)2);
+ else writer.Write ((int)-1);
+ writer.Write ((int)1);
+ writer.Write ((int)0);
+ }
+
+ private void ReadBinaryHeader (BinaryReader reader, out bool hasHeaders)
+ {
+ reader.ReadByte();
+ reader.ReadInt32();
+ int val = reader.ReadInt32();
+ hasHeaders = (val==2);
+ reader.ReadInt32();
+ reader.ReadInt32();
+ }
}
}