diff options
Diffstat (limited to 'src/mscorlib/src/System/Runtime/Serialization')
10 files changed, 529 insertions, 183 deletions
diff --git a/src/mscorlib/src/System/Runtime/Serialization/FormatterConverter.cs b/src/mscorlib/src/System/Runtime/Serialization/FormatterConverter.cs index 7df221c9cd..b710ed0b3a 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/FormatterConverter.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/FormatterConverter.cs @@ -25,7 +25,7 @@ namespace System.Runtime.Serialization { public Object Convert(Object value, Type type) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ChangeType(value, type, CultureInfo.InvariantCulture); @@ -33,7 +33,7 @@ namespace System.Runtime.Serialization { public Object Convert(Object value, TypeCode typeCode) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ChangeType(value, typeCode, CultureInfo.InvariantCulture); @@ -41,7 +41,7 @@ namespace System.Runtime.Serialization { public bool ToBoolean(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToBoolean(value, CultureInfo.InvariantCulture); @@ -49,7 +49,7 @@ namespace System.Runtime.Serialization { public char ToChar(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToChar(value, CultureInfo.InvariantCulture); @@ -58,7 +58,7 @@ namespace System.Runtime.Serialization { [CLSCompliant(false)] public sbyte ToSByte(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToSByte(value, CultureInfo.InvariantCulture); @@ -66,7 +66,7 @@ namespace System.Runtime.Serialization { public byte ToByte(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToByte(value, CultureInfo.InvariantCulture); @@ -74,7 +74,7 @@ namespace System.Runtime.Serialization { public short ToInt16(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToInt16(value, CultureInfo.InvariantCulture); @@ -83,7 +83,7 @@ namespace System.Runtime.Serialization { [CLSCompliant(false)] public ushort ToUInt16(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToUInt16(value, CultureInfo.InvariantCulture); @@ -91,7 +91,7 @@ namespace System.Runtime.Serialization { public int ToInt32(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToInt32(value, CultureInfo.InvariantCulture); @@ -100,7 +100,7 @@ namespace System.Runtime.Serialization { [CLSCompliant(false)] public uint ToUInt32(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToUInt32(value, CultureInfo.InvariantCulture); @@ -108,7 +108,7 @@ namespace System.Runtime.Serialization { public long ToInt64(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToInt64(value, CultureInfo.InvariantCulture); @@ -117,7 +117,7 @@ namespace System.Runtime.Serialization { [CLSCompliant(false)] public ulong ToUInt64(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToUInt64(value, CultureInfo.InvariantCulture); @@ -125,7 +125,7 @@ namespace System.Runtime.Serialization { public float ToSingle(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToSingle(value, CultureInfo.InvariantCulture); @@ -133,7 +133,7 @@ namespace System.Runtime.Serialization { public double ToDouble(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToDouble(value, CultureInfo.InvariantCulture); @@ -141,7 +141,7 @@ namespace System.Runtime.Serialization { public Decimal ToDecimal(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToDecimal(value, CultureInfo.InvariantCulture); @@ -149,7 +149,7 @@ namespace System.Runtime.Serialization { public DateTime ToDateTime(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToDateTime(value, CultureInfo.InvariantCulture); @@ -157,7 +157,7 @@ namespace System.Runtime.Serialization { public String ToString(Object value) { if (value==null) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); return System.Convert.ToString(value, CultureInfo.InvariantCulture); diff --git a/src/mscorlib/src/System/Runtime/Serialization/FormatterServices.cs b/src/mscorlib/src/System/Runtime/Serialization/FormatterServices.cs index c6f27b5b2a..27c3f15136 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/FormatterServices.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/FormatterServices.cs @@ -29,16 +29,15 @@ namespace System.Runtime.Serialization { using System.IO; using System.Text; using System.Globalization; + using System.Diagnostics; using System.Diagnostics.Contracts; [System.Runtime.InteropServices.ComVisible(true)] public static class FormatterServices { #if FEATURE_SERIALIZATION internal static Dictionary<MemberHolder, MemberInfo[]> m_MemberInfoTable = new Dictionary<MemberHolder, MemberInfo[]>(32); - [System.Security.SecurityCritical] private static bool unsafeTypeForwardersIsEnabled = false; - [System.Security.SecurityCritical] private static volatile bool unsafeTypeForwardersIsEnabledInitialized = false; private static Object s_FormatterServicesSyncObject = null; @@ -56,7 +55,6 @@ namespace System.Runtime.Serialization { } } - [SecuritySafeCritical] static FormatterServices() { // Static initialization touches security critical types, so we need an @@ -100,7 +98,7 @@ namespace System.Runtime.Serialization { FieldInfo [] typeFields; RuntimeType parentType; - Contract.Assert((object)type != null, "[GetAllSerializableMembers]type!=null"); + Debug.Assert((object)type != null, "[GetAllSerializableMembers]type!=null"); if (type.IsInterface) { return new MemberInfo[0]; @@ -186,7 +184,6 @@ namespace System.Runtime.Serialization { // be included, properties must have both a getter and a setter. N.B.: A class // which implements ISerializable or has a serialization surrogate may not use all of these members // (or may have additional members). - [System.Security.SecurityCritical] // auto-generated_required public static MemberInfo[] GetSerializableMembers(Type type) { return GetSerializableMembers(type, new StreamingContext(StreamingContextStates.All)); } @@ -194,12 +191,11 @@ namespace System.Runtime.Serialization { // Get all of the Serializable Members for a particular class. If we're not cloning, this is all // non-transient, non-static fields. If we are cloning, include the transient fields as well since // we know that we're going to live inside of the same context. - [System.Security.SecurityCritical] // auto-generated_required public static MemberInfo[] GetSerializableMembers(Type type, StreamingContext context) { MemberInfo[] members; if ((object)type==null) { - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); } Contract.EndContractBlock(); @@ -230,14 +226,9 @@ namespace System.Runtime.Serialization { static readonly Type[] advancedTypes = new Type[]{ typeof(System.DelegateSerializationHolder), -#if FEATURE_REMOTING - typeof(System.Runtime.Remoting.ObjRef), - typeof(System.Runtime.Remoting.IEnvoyInfo), - typeof(System.Runtime.Remoting.Lifetime.ISponsor), -#endif }; - - public static void CheckTypeSecurity(Type t, TypeFilterLevel securityLevel) { + + public static void CheckTypeSecurity(Type t, TypeFilterLevel securityLevel) { if (securityLevel == TypeFilterLevel.Low){ for(int i=0;i<advancedTypes.Length;i++){ if (advancedTypes[i].IsAssignableFrom(t)) @@ -254,10 +245,9 @@ namespace System.Runtime.Serialization { // will not create an unitialized string because it is non-sensical to create an empty // instance of an immutable type. // - [System.Security.SecurityCritical] // auto-generated_required public static Object GetUninitializedObject(Type type) { if ((object)type == null) { - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); } Contract.EndContractBlock(); @@ -268,44 +258,33 @@ namespace System.Runtime.Serialization { return nativeGetUninitializedObject((RuntimeType)type); } - [System.Security.SecurityCritical] // auto-generated_required public static Object GetSafeUninitializedObject(Type type) { if ((object)type == null) { - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); } Contract.EndContractBlock(); - + if (!(type is RuntimeType)) { throw new SerializationException(Environment.GetResourceString("Serialization_InvalidType", type.ToString())); } -#if FEATURE_REMOTING - if (Object.ReferenceEquals(type, typeof(System.Runtime.Remoting.Messaging.ConstructionCall)) || - Object.ReferenceEquals(type, typeof(System.Runtime.Remoting.Messaging.LogicalCallContext)) || - Object.ReferenceEquals(type, typeof(System.Runtime.Remoting.Contexts.SynchronizationAttribute))) - return nativeGetUninitializedObject((RuntimeType)type); -#endif - try { - return nativeGetSafeUninitializedObject((RuntimeType)type); + try { + return nativeGetSafeUninitializedObject((RuntimeType)type); } - catch(SecurityException e) { + catch(SecurityException e) { throw new SerializationException(Environment.GetResourceString("Serialization_Security", type.FullName), e); - } + } } - [System.Security.SecurityCritical] // auto-generated [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern Object nativeGetSafeUninitializedObject(RuntimeType type); - [System.Security.SecurityCritical] // auto-generated [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern Object nativeGetUninitializedObject(RuntimeType type); #if FEATURE_SERIALIZATION - [System.Security.SecurityCritical] [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern bool GetEnableUnsafeTypeForwarders(); - [SecuritySafeCritical] internal static bool UnsafeTypeForwardersIsEnabled() { if (!unsafeTypeForwardersIsEnabledInitialized) @@ -318,7 +297,6 @@ namespace System.Runtime.Serialization { } #endif private static Binder s_binder = Type.DefaultBinder; - [System.Security.SecurityCritical] internal static void SerializationSetValue(MemberInfo fi, Object target, Object value) { Contract.Requires(fi != null); @@ -345,18 +323,17 @@ namespace System.Runtime.Serialization { // Fill in the members of obj with the data contained in data. // Returns the number of members populated. // - [System.Security.SecurityCritical] // auto-generated_required public static Object PopulateObjectMembers(Object obj, MemberInfo[] members, Object[] data) { if (obj==null) { - throw new ArgumentNullException("obj"); + throw new ArgumentNullException(nameof(obj)); } if (members==null) { - throw new ArgumentNullException("members"); + throw new ArgumentNullException(nameof(members)); } if (data==null) { - throw new ArgumentNullException("data"); + throw new ArgumentNullException(nameof(data)); } if (members.Length!=data.Length) { @@ -372,7 +349,7 @@ namespace System.Runtime.Serialization { mi = members[i]; if (mi==null) { - throw new ArgumentNullException("members", Environment.GetResourceString("ArgumentNull_NullMember", i)); + throw new ArgumentNullException(nameof(members), Environment.GetResourceString("ArgumentNull_NullMember", i)); } //If we find an empty, it means that the value was never set during deserialization. @@ -400,15 +377,14 @@ namespace System.Runtime.Serialization { // extract (must be FieldInfos or PropertyInfos). For each supplied member, extract the matching value and // return it in a Object[] of the same size. // - [System.Security.SecurityCritical] // auto-generated_required public static Object[] GetObjectData(Object obj, MemberInfo[] members) { if (obj==null) { - throw new ArgumentNullException("obj"); + throw new ArgumentNullException(nameof(obj)); } if (members==null) { - throw new ArgumentNullException("members"); + throw new ArgumentNullException(nameof(members)); } Contract.EndContractBlock(); @@ -421,11 +397,11 @@ namespace System.Runtime.Serialization { mi=members[i]; if (mi==null) { - throw new ArgumentNullException("members", Environment.GetResourceString("ArgumentNull_NullMember", i)); + throw new ArgumentNullException(nameof(members), Environment.GetResourceString("ArgumentNull_NullMember", i)); } if (mi.MemberType==MemberTypes.Field) { - Contract.Assert(mi is RuntimeFieldInfo || mi is SerializationFieldInfo, + Debug.Assert(mi is RuntimeFieldInfo || mi is SerializationFieldInfo, "[FormatterServices.GetObjectData]mi is RuntimeFieldInfo || mi is SerializationFieldInfo."); RtFieldInfo rfi = mi as RtFieldInfo; @@ -443,12 +419,11 @@ namespace System.Runtime.Serialization { return data; } - [System.Security.SecurityCritical] // auto-generated_required [System.Runtime.InteropServices.ComVisible(false)] public static ISerializationSurrogate GetSurrogateForCyclicalReference(ISerializationSurrogate innerSurrogate) { if (innerSurrogate == null) - throw new ArgumentNullException("innerSurrogate"); + throw new ArgumentNullException(nameof(innerSurrogate)); Contract.EndContractBlock(); return new SurrogateForCyclicalReference(innerSurrogate); } @@ -459,10 +434,9 @@ namespace System.Runtime.Serialization { **Arguments: **Exceptions: ==============================================================================*/ - [System.Security.SecurityCritical] // auto-generated_required public static Type GetTypeFromAssembly(Assembly assem, String name) { if (assem==null) - throw new ArgumentNullException("assem"); + throw new ArgumentNullException(nameof(assem)); Contract.EndContractBlock(); return assem.GetType(name, false, false); } @@ -499,7 +473,7 @@ namespace System.Runtime.Serialization { internal static string GetClrAssemblyName(Type type, out bool hasTypeForwardedFrom) { if ((object)type == null) { - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); } object[] typeAttributes = type.GetCustomAttributes(typeof(TypeForwardedFromAttribute), false); @@ -566,17 +540,15 @@ namespace System.Runtime.Serialization { internal SurrogateForCyclicalReference(ISerializationSurrogate innerSurrogate) { if (innerSurrogate == null) - throw new ArgumentNullException("innerSurrogate"); + throw new ArgumentNullException(nameof(innerSurrogate)); this.innerSurrogate = innerSurrogate; } - [System.Security.SecurityCritical] // auto-generated public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context) { innerSurrogate.GetObjectData(obj, info, context); } - [System.Security.SecurityCritical] // auto-generated public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { return innerSurrogate.SetObjectData(obj, info, context, selector); diff --git a/src/mscorlib/src/System/Runtime/Serialization/IObjectReference.cs b/src/mscorlib/src/System/Runtime/Serialization/IObjectReference.cs index f1a1bc0590..42662a10f6 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/IObjectReference.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/IObjectReference.cs @@ -22,7 +22,6 @@ namespace System.Runtime.Serialization { // Interface does not need to be marked with the serializable attribute [System.Runtime.InteropServices.ComVisible(true)] public interface IObjectReference { - [System.Security.SecurityCritical] // auto-generated_required Object GetRealObject(StreamingContext context); } } diff --git a/src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs b/src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs index e59fa65043..fc283d41f1 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/ISerializable.cs @@ -22,7 +22,6 @@ namespace System.Runtime.Serialization { [System.Runtime.InteropServices.ComVisible(true)] public interface ISerializable { - [System.Security.SecurityCritical] // auto-generated_required void GetObjectData(SerializationInfo info, StreamingContext context); } diff --git a/src/mscorlib/src/System/Runtime/Serialization/ISerializationSurrogate.cs b/src/mscorlib/src/System/Runtime/Serialization/ISerializationSurrogate.cs index 9bb30d99e0..226bbdcc75 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/ISerializationSurrogate.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/ISerializationSurrogate.cs @@ -24,13 +24,11 @@ namespace System.Runtime.Serialization { // Returns a SerializationInfo completely populated with all of the data needed to reinstantiate the // the object at the other end of serialization. // - [System.Security.SecurityCritical] // auto-generated_required void GetObjectData(Object obj, SerializationInfo info, StreamingContext context); // Reinflate the object using all of the information in data. The information in // members is used to find the particular field or property which needs to be set. // - [System.Security.SecurityCritical] // auto-generated_required Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector); } } diff --git a/src/mscorlib/src/System/Runtime/Serialization/ISurrogateSelector.cs b/src/mscorlib/src/System/Runtime/Serialization/ISurrogateSelector.cs index 01b960f86b..87b7845894 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/ISurrogateSelector.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/ISurrogateSelector.cs @@ -22,16 +22,13 @@ namespace System.Runtime.Serialization { // Interface does not need to be marked with the serializable attribute // Specifies the next ISurrogateSelector to be examined for surrogates if the current // instance doesn't have a surrogate for the given type and assembly in the given context. - [System.Security.SecurityCritical] // auto-generated_required void ChainSelector(ISurrogateSelector selector); // Returns the appropriate surrogate for the given type in the given context. - [System.Security.SecurityCritical] // auto-generated_required ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector); // Return the next surrogate in the chain. Returns null if no more exist. - [System.Security.SecurityCritical] // auto-generated_required ISurrogateSelector GetNextSelector(); } } diff --git a/src/mscorlib/src/System/Runtime/Serialization/SafeSerializationManager.cs b/src/mscorlib/src/System/Runtime/Serialization/SafeSerializationManager.cs new file mode 100644 index 0000000000..585d367605 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/Serialization/SafeSerializationManager.cs @@ -0,0 +1,446 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Reflection; +using System.Security; + +namespace System.Runtime.Serialization +{ + // + // #SafeSerialization + // + // Types which are serializable via the ISerializable interface have a problem when it comes to allowing + // transparent subtypes which can allow themselves to serialize since the GetObjectData method is + // SecurityCritical. + // + // For instance, System.Exception implements ISerializable, however it is also desirable to have + // transparent exceptions with their own fields that need to be serialized. (For instance, in transparent + // assemblies such as the DLR and F#, or even in partial trust application code). Since overriding + // GetObjectData requires that the overriding method be security critical, this won't work directly. + // + // SafeSerializationManager solves this problem by allowing any partial trust code to contribute + // individual chunks of serializable data to be included in the serialized version of the derived class. + // These chunks are then deserialized back out of the serialized type and notified that they should + // populate the fields of the deserialized object when serialization is complete. This allows partial + // trust or transparent code to participate in serialization of an ISerializable type without having to + // override GetObjectData or implement the ISerializable constructor. + // + // On the serialization side, SafeSerializationManager has an event SerializeObjectState which it will + // fire in response to serialization in order to gather the units of serializable data that should be + // stored with the rest of the object during serialization. Methods which respond to these events + // create serializable objects which implement the ISafeSerializationData interface and add them to the + // collection of other serialized data by calling AddSerializedState on the SafeSerializationEventArgs + // passed into the event. + // + // By using an event rather than a virtual method on the base ISerializable object, we allow multiple + // potentially untrusted subclasses to participate in serialization, without each one having to ensure + // that it calls up to the base type in order for the whole system to work. (For instance Exception : + // TrustedException : UntrustedException, in this scenario UntrustedException would be able to override + // the virtual method an prevent TrustedException from ever seeing the method call, either accidentally + // or maliciously). + // + // Further, by only allowing additions of new chunks of serialization state rather than exposing the + // whole underlying list, we avoid exposing potentially sensitive serialized state to any of the + // potentially untrusted subclasses. + // + // At deserialization time, SafeSerializationManager performs the reverse operation. It deserializes the + // chunks of serialized state, and then notifies them that the object they belong to is deserialized by + // calling their CompleteSerialization method. In repsonse to this call, the state objects populate the + // fields of the object being deserialized with the state that they held. + // + // From a security perspective, the chunks of serialized state can only contain data that the specific + // subclass itself had access to read (otherwise it wouldn't be able to populate the type with that + // data), as opposed to having access to far more data in the SerializationInfo that GetObjectData uses. + // Similarly, at deserialization time, the serialized state can only modify fields that the type itself + // has access to (again, as opposed to the full SerializationInfo which could be modified). + // + // Individual types which wish to participate in safe serialization do so by containing an instance of a + // SafeSerializationManager and exposing its serialization event. During GetObjectData, the + // SafeSerializationManager is serialized just like any other field of the containing type. However, at + // the end of serialization it is called back one last time to CompleteSerialization. + // + // In CompleteSerialization, if the SafeSerializationManager detects that it has extra chunks of + // data to handle, it substitutes the root type being serialized (formerly the real type hosting the + // SafeSerializationManager) with itself. This allows it to gain more control over the deserialization + // process. It also saves away an extra bit of state in the serialization info indicating the real type + // of object that should be recreated during deserialization. + // + // At this point the serialized state looks like this: + // Data: + // realSerializedData1 + // ... + // realSerializedDataN + // safeSerializationData -> this is the serialization data member of the parent type + // m_serializedState -> list of saved serialized states from subclasses responding to the safe + // serialization event + // RealTypeSerializationName -> type which is using safe serialization + // Type: + // SafeSerializationManager + // + // That is, the serialized data claims to be of type SafeSerializationManager, however contains only the + // data from the real object being serialized along with one bit of safe serialization metadata. + // + // At deserialization time, since the serialized data claims to be of type SafeSerializationManager, the + // root object being created is an instance of the SafeSerializationManager class. However, it detects + // that this isn't a real SafeSerializationManager (by looking for the real type field in the metadata), + // and simply saves away the SerializationInfo and the real type being deserialized. + // + // Since SafeSerializationManager implements IObjectReference, the next step of deserialization is the + // GetRealObject callback. This callback is the one responsible for getting the + // SafeSerializationManager out of the way and instead creating an instance of the actual type which was + // serialized. + // + // It does this by first creating an instance of the real type being deserialzed (saved away in the + // deserialzation constructor), but not running any of its constructors. Instead, it walks the + // inheritance hierarchy (moving toward the most derived type) looking for the last full trust type to + // implement the standard ISerializable constructor before any type does not implement the constructor. + // It is this last type's deserialization constructor which is then invoked, passing in the saved + // SerializationInfo. Once the constructors are run, we return this object as the real deserialized + // object. + // + // The reason that we do this walk is so that ISerializable types can protect themselves from malicious + // input during deserialization by making their deserialization constructors unavailable to partial + // trust code. By not requiring every type have a copy of this constructor, partial trust code can + // participate in safe serialization and not be required to have access to the parent's constructor. + // + // It should be noted however, that this heuristic means that if a full trust type does derive from + // a transparent or partial trust type using this safe serialization mechanism, that full trust type + // will not have its constructor called. Further, the protection of not invoking partial trust + // deserialization constructors only comes into play if SafeSerializationManager is in control of + // deserialization, which means there must be at least one (even empty) safe serialization event + // handler registered. + // + // Another interesting note is that at this point there are now two SafeSerializationManagers alive for + // this deserialization. The first object is the one which is controlling the deserialization and was + // created as the root object of the deserialization. The second one is the object which contains the + // serialized data chunks and is a data member of the real object being deserialized. For this reason, + // the data objects cannot be notified that the deserialization is complete during GetRealObject since + // the ISafeSerializationData objects are not members of the active SafeSerializationManager instance. + // + // The next step is the OnDeserialized callback, which comes to SafeSerializableObject since it was + // pretending to be the root object of the deserialization. It responds to this callback by calling + // any existing OnDeserialized callback on the real type that was deserialized. + // + // The real type needs to call its data member SafeSerializationData object's CompleteDeserialization + // method in response to the OnDeserialized call. This CompleteDeserialization call will then iterate + // through the ISafeSerializationData objects calling each of their CompleteDeserialization methods so + // that they can plug the nearly-complete object with their saved data. + // + // The reason for having a new ISafeSerializationData interface which is basically identical to + // IDeserializationCallback is that IDeserializationCallback will be called on the stored data chunks + // by the serialization code when they are deserialized, and that's not a desirable behavior. + // Essentially, we need to change the meaning of the object parameter to mean "parent object which + // participated in safe serialization", rather than "this object". + // + // Implementing safe serialization on an ISerialiable type is relatively straight forward. (For an + // example, see System.Exception): + // + // 1. Include a data member of type SafeSerializationManager: + // + // private SafeSerializationManager m_safeSerializationManager; + // + // 2. Add a protected SerializeObjectState event, which passes through to the SafeSerializationManager: + // + // protected event EventHandler<SafeSerializationEventArgs> SerializeObjectState + // { + // add { m_safeSerializationManager.SerializeObjectState += value; } + // remove { m_safeSerializationManager.SerializeObjectState -= value; } + // } + // + // 3. Serialize the safe serialization object in GetObjectData, and call its CompleteSerialization method: + // + // { + // info.AddValue("m_safeSerializationManager", m_safeSerializationManager, typeof(SafeSerializationManager)); + // m_safeSerializationManager.CompleteSerialization(this, info, context); + // } + // + // 4. Add an OnDeserialized handler if one doesn't already exist, and call CompleteDeserialization in it: + // + // [OnDeserialized] + // private void OnDeserialized(StreamingContext context) + // { + // m_safeSerializationManager.CompleteDeserialization(this); + // } + // + // On the client side, using safe serialization is also pretty easy. For example: + // + // [Serializable] + // public class TransparentException : Exception + // { + // [Serializable] + // private struct TransparentExceptionState : ISafeSerializationData + // { + // public string m_extraData; + // + // void ISafeSerializationData.CompleteDeserialization(object obj) + // { + // TransparentException exception = obj as TransparentException; + // exception.m_state = this; + // } + // } + // + // [NonSerialized] + // private TransparentExceptionState m_state = new TransparentExceptionState(); + // + // public TransparentException() + // { + // SerializeObjectState += delegate(object exception, SafeSerializationEventArgs eventArgs) + // { + // eventArgs.AddSerializedState(m_state); + // }; + // } + // + // public string ExtraData + // { + // get { return m_state.m_extraData; } + // set { m_state.m_extraData = value; } + // } + // } + // + + // SafeSerializationEventArgs are provided to the delegates which do safe serialization. Each delegate + // serializes its own state into an IDeserializationCallback instance which must, itself, be serializable. + // These indivdiual states are then added to the SafeSerializationEventArgs in order to be saved away when + // the original ISerializable type is serialized. + public sealed class SafeSerializationEventArgs : EventArgs + { + private StreamingContext m_streamingContext; + private List<object> m_serializedStates = new List<object>(); + + internal SafeSerializationEventArgs(StreamingContext streamingContext) + { + m_streamingContext = streamingContext; + } + + public void AddSerializedState(ISafeSerializationData serializedState) + { + if (serializedState == null) + throw new ArgumentNullException(nameof(serializedState)); + if (!serializedState.GetType().IsSerializable) + throw new ArgumentException(Environment.GetResourceString("Serialization_NonSerType", serializedState.GetType(), serializedState.GetType().Assembly.FullName)); + + m_serializedStates.Add(serializedState); + } + + internal IList<object> SerializedStates + { + get { return m_serializedStates; } + } + + public StreamingContext StreamingContext + { + get { return m_streamingContext; } + } + } + + // Interface to be supported by objects which are stored in safe serialization stores + public interface ISafeSerializationData + { + // CompleteDeserialization is called when the object to which the extra serialized data was attached + // has completed its deserialization, and now needs to be populated with the extra data stored in + // this object. + void CompleteDeserialization(object deserialized); + } +#if FEATURE_SERIALIZATION + // Helper class to implement safe serialization. Concrete ISerializable types which want to allow + // transparent subclasses code to participate in serialization should contain an instance of + // SafeSerializationManager and wire up to it as described in code:#SafeSerialization. + [Serializable] + internal sealed class SafeSerializationManager : IObjectReference, ISerializable + { + // Saved states to store in the serialization stream. This is typed as object rather than + // ISafeSerializationData because ISafeSerializationData can't be marked serializable. + private IList<object> m_serializedStates; + + // This is the SerializationInfo that is used when the SafeSerializationManager type has replaced + // itself as the target of serialziation. It is not used directly by the safe serialization code, + // but just held onto so that the real object being deserialzed can use it later. + private SerializationInfo m_savedSerializationInfo; + + // Real object that we've deserialized - this is stored when we complete construction and calling + // the deserialization .ctors on it and is used when we need to notify the stored safe + // deserialization data that they should populate the object with their fields. + private object m_realObject; + + // Real type that should be deserialized + private RuntimeType m_realType; + + // Event fired when we need to collect state to serialize into the parent object + internal event EventHandler<SafeSerializationEventArgs> SerializeObjectState; + + // Name that is used to store the real type being deserialized in the main SerializationInfo + private const string RealTypeSerializationName = "CLR_SafeSerializationManager_RealType"; + + internal SafeSerializationManager() + { + } + + private SafeSerializationManager(SerializationInfo info, StreamingContext context) + { + // We need to determine if we're being called to really deserialize a SafeSerializationManager, + // or if we're being called because we've intercepted the deserialization callback for the real + // object being deserialized. We use the presence of the RealTypeSerializationName field in the + // serialization info to indicate that this is the interception callback and we just need to + // safe the info. If that field is not present, then we should be in a real deserialization + // construction. + RuntimeType realType = info.GetValueNoThrow(RealTypeSerializationName, typeof(RuntimeType)) as RuntimeType; + + if (realType == null) + { + m_serializedStates = info.GetValue("m_serializedStates", typeof(List<object>)) as List<object>; + } + else + { + m_realType = realType; + m_savedSerializationInfo = info; + } + } + + // Determine if the serialization manager is in an active state - that is if any code is hooked up + // to use it for serialization + internal bool IsActive + { + get { return SerializeObjectState != null; } + } + + // CompleteSerialization is called by the base ISerializable in its GetObjectData method. It is + // responsible for gathering up the serialized object state of any delegates that wish to add their + // own state to the serialized object. + internal void CompleteSerialization(object serializedObject, + SerializationInfo info, + StreamingContext context) + { + Contract.Requires(serializedObject != null); + Contract.Requires(info != null); + Contract.Requires(typeof(ISerializable).IsAssignableFrom(serializedObject.GetType())); + Contract.Requires(serializedObject.GetType().IsAssignableFrom(info.ObjectType)); + + // Clear out any stale state + m_serializedStates = null; + + // We only want to kick in our special serialization sauce if someone wants to participate in + // it, otherwise if we have no delegates registered there's no reason for us to get in the way + // of the regular serialization machinery. + EventHandler<SafeSerializationEventArgs> serializeObjectStateEvent = SerializeObjectState; + if (serializeObjectStateEvent != null) + { + // Get any extra data to add to our serialization state now + SafeSerializationEventArgs eventArgs = new SafeSerializationEventArgs(context); + serializeObjectStateEvent(serializedObject, eventArgs); + m_serializedStates = eventArgs.SerializedStates; + + // Replace the type to be deserialized by the standard serialization code paths with + // ourselves, which allows us to control the deserialization process. + info.AddValue(RealTypeSerializationName, serializedObject.GetType(), typeof(RuntimeType)); + info.SetType(typeof(SafeSerializationManager)); + } + } + + // CompleteDeserialization is called by the base ISerializable object's OnDeserialized handler to + // finish the deserialization of the object by notifying the saved states that they should + // re-populate their portions of the deserialized object. + internal void CompleteDeserialization(object deserializedObject) + { + Contract.Requires(deserializedObject != null); + + if (m_serializedStates != null) + { + foreach (ISafeSerializationData serializedState in m_serializedStates) + { + serializedState.CompleteDeserialization(deserializedObject); + } + } + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("m_serializedStates", m_serializedStates, typeof(List<IDeserializationCallback>)); + } + + // GetRealObject intercepts the deserialization process in order to allow deserializing part of the + // object's inheritance heirarchy using standard ISerializable constructors, and the remaining + // portion using the saved serialization states. + object IObjectReference.GetRealObject(StreamingContext context) + { + // If we've already deserialized the real object, use that rather than deserializing it again + if (m_realObject != null) + { + return m_realObject; + } + + // If we don't have a real type to deserialize, then this is really a SafeSerializationManager + // and we don't need to rebuild the object that we're standing in for. + if (m_realType == null) + { + return this; + } + + // Look for the last type in GetRealType's inheritance hierarchy which implements a critical + // deserialization constructor. This will be the object that we use as the deserialization + // construction type to initialize via standard ISerializable semantics + + // First build up the chain starting at the type below Object and working to the real type we + // serialized. + Stack inheritanceChain = new Stack(); + RuntimeType currentType = m_realType; + do + { + inheritanceChain.Push(currentType); + currentType = currentType.BaseType as RuntimeType; + } + while (currentType != typeof(object)); + + // Now look for the first type that does not implement the ISerializable .ctor. When we find + // that, previousType will point at the last type that did implement the .ctor. We require that + // the .ctor we invoke also be non-transparent + RuntimeConstructorInfo serializationCtor = null; + RuntimeType previousType = null; + do + { + previousType = currentType; + currentType = inheritanceChain.Pop() as RuntimeType; + serializationCtor = currentType.GetSerializationCtor(); + } + while (serializationCtor != null && serializationCtor.IsSecurityCritical); + + // previousType is the last type that did implement the deserialization .ctor before the first + // type that did not, so we'll grab it's .ctor to use for deserialization. + BCLDebug.Assert(previousType != null, "We should have at least one inheritance from the base type"); + serializationCtor = ObjectManager.GetConstructor(previousType); + + // Allocate an instance of the final type and run the selected .ctor on that instance to get the + // standard ISerializable initialization done. + object deserialized = FormatterServices.GetUninitializedObject(m_realType); + serializationCtor.SerializationInvoke(deserialized, m_savedSerializationInfo, context); + m_savedSerializationInfo = null; + m_realType = null; + + // Save away the real object that was deserialized so that we can fill it in later, and return + // it back as the object that should result from the final deserialization. + m_realObject = deserialized; + return deserialized; + } + + [OnDeserialized] + private void OnDeserialized(StreamingContext context) + { + // We only need to complete deserialization if we were hooking the deserialization process. If + // we have not deserialized an object in the GetRealObject call, then there's nothing more for + // us to do here. + if (m_realObject != null) + { + // Fire the real object's OnDeserialized method if they registered one. Since we replaced + // ourselves as the target of the deserialization, OnDeserialized on the target won't + // automatically get triggered unless we do it manually. + SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(m_realObject.GetType()); + cache.InvokeOnDeserialized(m_realObject, context); + m_realObject = null; + } + } + } +#endif +} diff --git a/src/mscorlib/src/System/Runtime/Serialization/SerializationFieldInfo.cs b/src/mscorlib/src/System/Runtime/Serialization/SerializationFieldInfo.cs index 5e7851bc57..82536ce3b4 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/SerializationFieldInfo.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/SerializationFieldInfo.cs @@ -21,11 +21,9 @@ namespace System.Runtime.Serialization { using System; using System.Reflection; using System.Globalization; + using System.Diagnostics; using System.Diagnostics.Contracts; using System.Threading; -#if FEATURE_REMOTING - using System.Runtime.Remoting.Metadata; -#endif //FEATURE_REMOTING internal sealed class SerializationFieldInfo : FieldInfo { @@ -38,8 +36,8 @@ namespace System.Runtime.Serialization { public override int MetadataToken { get { return m_field.MetadataToken; } } internal SerializationFieldInfo(RuntimeFieldInfo field, String namePrefix) { - Contract.Assert(field!=null, "[SerializationFieldInfo.ctor]field!=null"); - Contract.Assert(namePrefix!=null, "[SerializationFieldInfo.ctor]namePrefix!=null"); + Debug.Assert(field!=null, "[SerializationFieldInfo.ctor]field!=null"); + Debug.Assert(namePrefix!=null, "[SerializationFieldInfo.ctor]namePrefix!=null"); m_field = field; m_serializationName = String.Concat(namePrefix, FakeNameSeparatorString, m_field.Name); @@ -91,7 +89,6 @@ namespace System.Runtime.Serialization { return m_field.GetValue(obj); } - [System.Security.SecurityCritical] internal Object InternalGetValue(Object obj) { RtFieldInfo field = m_field as RtFieldInfo; if (field != null) @@ -107,7 +104,6 @@ namespace System.Runtime.Serialization { m_field.SetValue(obj, value, invokeAttr, binder, culture); } - [System.Security.SecurityCritical] internal void InternalSetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture) { RtFieldInfo field = m_field as RtFieldInfo; if (field != null) @@ -136,31 +132,5 @@ namespace System.Runtime.Serialization { return m_field.Attributes; } } - -#if FEATURE_REMOTING - #region Legacy Remoting Cache - private RemotingFieldCachedData m_cachedData; - - internal RemotingFieldCachedData RemotingCache - { - get - { - // This grabs an internal copy of m_cachedData and uses - // that instead of looking at m_cachedData directly because - // the cache may get cleared asynchronously. This prevents - // us from having to take a lock. - RemotingFieldCachedData cache = m_cachedData; - if (cache == null) - { - cache = new RemotingFieldCachedData(this); - RemotingFieldCachedData ret = Interlocked.CompareExchange(ref m_cachedData, cache, null); - if (ret != null) - cache = ret; - } - return cache; - } - } - #endregion -#endif //FEATURE_REMOTING } } diff --git a/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs b/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs index 94e6825b51..55909c85fd 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs @@ -18,15 +18,11 @@ namespace System.Runtime.Serialization using System.Collections.Generic; using System.Reflection; using System.Runtime.Remoting; -#if FEATURE_REMOTING - using System.Runtime.Remoting.Proxies; -#endif using System.Globalization; + using System.Diagnostics; using System.Diagnostics.Contracts; using System.Security; -#if FEATURE_CORECLR using System.Runtime.CompilerServices; -#endif [System.Runtime.InteropServices.ComVisible(true)] public sealed class SerializationInfo @@ -61,12 +57,12 @@ namespace System.Runtime.Serialization { if ((object)type == null) { - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); } if (converter == null) { - throw new ArgumentNullException("converter"); + throw new ArgumentNullException(nameof(converter)); } Contract.EndContractBlock(); @@ -96,7 +92,7 @@ namespace System.Runtime.Serialization { if (null == value) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); @@ -111,12 +107,11 @@ namespace System.Runtime.Serialization { return m_assemName; } - [SecuritySafeCritical] set { if (null == value) { - throw new ArgumentNullException("value"); + throw new ArgumentNullException(nameof(value)); } Contract.EndContractBlock(); if (this.requireSameTokenInPartialTrust) @@ -128,12 +123,11 @@ namespace System.Runtime.Serialization } } - [SecuritySafeCritical] public void SetType(Type type) { if ((object)type == null) { - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); } Contract.EndContractBlock(); @@ -170,15 +164,8 @@ namespace System.Runtime.Serialization } } - [SecuritySafeCritical] internal static void DemandForUnsafeAssemblyNameAssignments(string originalAssemblyName, string newAssemblyName) { -#if !FEATURE_CORECLR - if (!IsAssemblyNameAssignmentSafe(originalAssemblyName, newAssemblyName)) - { - CodeAccessPermission.Demand(PermissionType.SecuritySerialization); - } -#endif } internal static bool IsAssemblyNameAssignmentSafe(string originalAssemblyName, string newAssemblyName) @@ -242,7 +229,7 @@ namespace System.Runtime.Serialization private void ExpandArrays() { int newSize; - Contract.Assert(m_members.Length == m_currMember, "[SerializationInfo.ExpandArrays]m_members.Length == m_currMember"); + Debug.Assert(m_members.Length == m_currMember, "[SerializationInfo.ExpandArrays]m_members.Length == m_currMember"); newSize = (m_currMember * 2); @@ -280,12 +267,12 @@ namespace System.Runtime.Serialization { if (null == name) { - throw new ArgumentNullException("name"); + throw new ArgumentNullException(nameof(name)); } if ((object)type == null) { - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); } Contract.EndContractBlock(); @@ -416,19 +403,14 @@ namespace System.Runtime.Serialization **Exceptions: None. All error checking is done with asserts. Although public in coreclr, ** it's not exposed in a contract and is only meant to be used by corefx. ==============================================================================*/ -#if FEATURE_CORECLR // This should not be used by clients: exposing out this functionality would allow children // to overwrite their parent's values. It is public in order to give corefx access to it for // its ObjectManager implementation, but it should not be exposed out of a contract. - public -#else - internal -#endif - void UpdateValue(String name, Object value, Type type) + public void UpdateValue(String name, Object value, Type type) { - Contract.Assert(null != name, "[SerializationInfo.UpdateValue]name!=null"); - Contract.Assert(null != value, "[SerializationInfo.UpdateValue]value!=null"); - Contract.Assert(null != (object)type, "[SerializationInfo.UpdateValue]type!=null"); + Debug.Assert(null != name, "[SerializationInfo.UpdateValue]name!=null"); + Debug.Assert(null != value, "[SerializationInfo.UpdateValue]value!=null"); + Debug.Assert(null != (object)type, "[SerializationInfo.UpdateValue]type!=null"); int index = FindElement(name); if (index < 0) @@ -447,7 +429,7 @@ namespace System.Runtime.Serialization { if (null == name) { - throw new ArgumentNullException("name"); + throw new ArgumentNullException(nameof(name)); } Contract.EndContractBlock(); BCLDebug.Trace("SER", "[SerializationInfo.FindElement]Looking for ", name, " CurrMember is: ", m_currMember); @@ -477,11 +459,11 @@ namespace System.Runtime.Serialization throw new SerializationException(Environment.GetResourceString("Serialization_NotFound", name)); } - Contract.Assert(index < m_data.Length, "[SerializationInfo.GetElement]index<m_data.Length"); - Contract.Assert(index < m_types.Length, "[SerializationInfo.GetElement]index<m_types.Length"); + Debug.Assert(index < m_data.Length, "[SerializationInfo.GetElement]index<m_data.Length"); + Debug.Assert(index < m_types.Length, "[SerializationInfo.GetElement]index<m_types.Length"); foundType = m_types[index]; - Contract.Assert((object)foundType != null, "[SerializationInfo.GetElement]foundType!=null"); + Debug.Assert((object)foundType != null, "[SerializationInfo.GetElement]foundType!=null"); return m_data[index]; } @@ -495,11 +477,11 @@ namespace System.Runtime.Serialization return null; } - Contract.Assert(index < m_data.Length, "[SerializationInfo.GetElement]index<m_data.Length"); - Contract.Assert(index < m_types.Length, "[SerializationInfo.GetElement]index<m_types.Length"); + Debug.Assert(index < m_data.Length, "[SerializationInfo.GetElement]index<m_data.Length"); + Debug.Assert(index < m_types.Length, "[SerializationInfo.GetElement]index<m_types.Length"); foundType = m_types[index]; - Contract.Assert((object)foundType != null, "[SerializationInfo.GetElement]foundType!=null"); + Debug.Assert((object)foundType != null, "[SerializationInfo.GetElement]foundType!=null"); return m_data[index]; } @@ -508,13 +490,12 @@ namespace System.Runtime.Serialization // form requested. // - [System.Security.SecuritySafeCritical] // auto-generated public Object GetValue(String name, Type type) { if ((object)type == null) { - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); } Contract.EndContractBlock(); @@ -526,53 +507,36 @@ namespace System.Runtime.Serialization Object value; value = GetElement(name, out foundType); -#if FEATURE_REMOTING - if (RemotingServices.IsTransparentProxy(value)) + + if (Object.ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null) { - RealProxy proxy = RemotingServices.GetRealProxy(value); - if (RemotingServices.ProxyCheckCast(proxy, rt)) - return value; + return value; } - else -#endif - if (Object.ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null) - { - return value; - } - Contract.Assert(m_converter != null, "[SerializationInfo.GetValue]m_converter!=null"); + Debug.Assert(m_converter != null, "[SerializationInfo.GetValue]m_converter!=null"); return m_converter.Convert(value, type); } - [System.Security.SecuritySafeCritical] // auto-generated [System.Runtime.InteropServices.ComVisible(true)] internal Object GetValueNoThrow(String name, Type type) { Type foundType; Object value; - Contract.Assert((object)type != null, "[SerializationInfo.GetValue]type ==null"); - Contract.Assert(type is RuntimeType, "[SerializationInfo.GetValue]type is not a runtime type"); + Debug.Assert((object)type != null, "[SerializationInfo.GetValue]type ==null"); + Debug.Assert(type is RuntimeType, "[SerializationInfo.GetValue]type is not a runtime type"); value = GetElementNoThrow(name, out foundType); if (value == null) return null; -#if FEATURE_REMOTING - if (RemotingServices.IsTransparentProxy(value)) + + if (Object.ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null) { - RealProxy proxy = RemotingServices.GetRealProxy(value); - if (RemotingServices.ProxyCheckCast(proxy, (RuntimeType)type)) - return value; + return value; } - else -#endif - if (Object.ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null) - { - return value; - } - Contract.Assert(m_converter != null, "[SerializationInfo.GetValue]m_converter!=null"); + Debug.Assert(m_converter != null, "[SerializationInfo.GetValue]m_converter!=null"); return m_converter.Convert(value, type); } diff --git a/src/mscorlib/src/System/Runtime/Serialization/SerializationInfoEnumerator.cs b/src/mscorlib/src/System/Runtime/Serialization/SerializationInfoEnumerator.cs index 6b256a6e1f..32c65492e1 100644 --- a/src/mscorlib/src/System/Runtime/Serialization/SerializationInfoEnumerator.cs +++ b/src/mscorlib/src/System/Runtime/Serialization/SerializationInfoEnumerator.cs @@ -14,6 +14,7 @@ ============================================================*/ namespace System.Runtime.Serialization { using System; + using System.Diagnostics; using System.Collections; using System.Diagnostics.Contracts; @@ -66,13 +67,13 @@ namespace System.Runtime.Serialization { bool m_current; internal SerializationInfoEnumerator(String[] members, Object[] info, Type[] types, int numItems) { - Contract.Assert(members!=null, "[SerializationInfoEnumerator.ctor]members!=null"); - Contract.Assert(info!=null, "[SerializationInfoEnumerator.ctor]info!=null"); - Contract.Assert(types!=null, "[SerializationInfoEnumerator.ctor]types!=null"); - Contract.Assert(numItems>=0, "[SerializationInfoEnumerator.ctor]numItems>=0"); - Contract.Assert(members.Length>=numItems, "[SerializationInfoEnumerator.ctor]members.Length>=numItems"); - Contract.Assert(info.Length>=numItems, "[SerializationInfoEnumerator.ctor]info.Length>=numItems"); - Contract.Assert(types.Length>=numItems, "[SerializationInfoEnumerator.ctor]types.Length>=numItems"); + Debug.Assert(members!=null, "[SerializationInfoEnumerator.ctor]members!=null"); + Debug.Assert(info!=null, "[SerializationInfoEnumerator.ctor]info!=null"); + Debug.Assert(types!=null, "[SerializationInfoEnumerator.ctor]types!=null"); + Debug.Assert(numItems>=0, "[SerializationInfoEnumerator.ctor]numItems>=0"); + Debug.Assert(members.Length>=numItems, "[SerializationInfoEnumerator.ctor]members.Length>=numItems"); + Debug.Assert(info.Length>=numItems, "[SerializationInfoEnumerator.ctor]info.Length>=numItems"); + Debug.Assert(types.Length>=numItems, "[SerializationInfoEnumerator.ctor]types.Length>=numItems"); m_members = members; m_data = info; |