Support SerializeObjectState for System.Exception (bug #39824)
authorAndi McClure <andi.mcclure@xamarin.com>
Wed, 13 Apr 2016 22:36:08 +0000 (18:36 -0400)
committerAndi McClure <andi.mcclure@xamarin.com>
Wed, 13 Apr 2016 22:36:08 +0000 (18:36 -0400)
Per current .NET, exception serialization may be implemented using the
SerializeObjectState event. Use of this approach is mandatory for
certain classes, such as HttpRequestException subclasses. Mono does
not support it. The solution is to switch out our System.Exception
implementation for the referencesource one.

To accommodate this, classes that access System.Exception internal
fields directly must switch to the new field names; a new support
method is added to System.Environment; the "security level" methods
and icall are added to MonoCMethods; and the field order in
_MonoException must be adjusted. A new test is also added in the
System.Runtime.Serialization assembly.

mcs/class/System.Runtime.Serialization/System.Runtime.Serialization_test.dll.sources
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/Exceptions.cs [new file with mode: 0644]
mcs/class/corlib/System.IO/Path.cs
mcs/class/corlib/System.Reflection/MonoMethod.cs
mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs
mcs/class/corlib/System/Environment.cs
mcs/class/corlib/System/Exception.cs [deleted file]
mcs/class/corlib/corlib.dll.sources
mono/metadata/icall-def.h
mono/metadata/object-internals.h

index b0c9706a1dbdd42ab798bdfcf4cfebe807e8ef57..547733453e01d33328e916ef748bc572767657f9 100644 (file)
@@ -15,6 +15,7 @@ System.Runtime.Serialization/DataContractSerializerTest_NullableWithDictionary.c
 System.Runtime.Serialization/DataContractSerializerTest_InvalidCharacters.cs
 System.Runtime.Serialization/DataContractSerializerTest_ISerializable.cs
 System.Runtime.Serialization/DataContractSerializerTest.cs
+System.Runtime.Serialization/Exceptions.cs
 System.Runtime.Serialization/KnownTypeAttributeTest.cs
 System.Runtime.Serialization/XmlObjectSerializerTest.cs
 System.Runtime.Serialization/XsdDataContractExporterTest.cs
diff --git a/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/Exceptions.cs b/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/Exceptions.cs
new file mode 100644 (file)
index 0000000..4303c6c
--- /dev/null
@@ -0,0 +1,95 @@
+//
+// Exceptions
+//
+// Authors:
+//      Andi McClure (andi.mcclure@xamarin.com)
+//
+// Copyright 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using NUnit.Framework;
+
+namespace MonoTests.System.Runtime.Serialization
+{
+       [TestFixture]
+       public class Exceptions
+       {
+               [Serializable]
+               public class SerializableException : Exception
+               {
+                       public string Data;
+
+                       public SerializableException (string data) {
+                               Data = data;
+
+                               SerializeObjectState += HandleSerialization;
+                       }
+
+                       private static void HandleSerialization (object exception, SafeSerializationEventArgs eventArgs) {
+                               eventArgs.AddSerializedState (new SerializableExceptionState (exception));
+                       }
+
+                       [Serializable]
+                       private class SerializableExceptionState : ISafeSerializationData {
+                               private string Data;
+
+                               public SerializableExceptionState (object _exception) {
+                                       SerializableException exception = (SerializableException)_exception;
+
+                                       Data = exception.Data;
+                               }
+
+                               public void CompleteDeserialization (object _exception) {
+                                       SerializableException exception = (SerializableException)_exception;
+                                       exception.SerializeObjectState += HandleSerialization;
+
+                                       exception.Data = Data;
+                               }
+                       }
+               }
+
+               // Effectively tests SerializeObjectState handler support on System.Exception
+               [Test]
+               public void Exception_SerializeObjectState () {
+                       SerializableException exception = new SerializableException ("success");
+                       SerializableException deserializedException;
+                       BinaryFormatter binaryFormatter = new BinaryFormatter ();
+
+                       using (MemoryStream memoryStream = new MemoryStream ())
+                       {
+                               binaryFormatter.Serialize (memoryStream, exception);
+                               memoryStream.Flush ();
+
+                               memoryStream.Seek (0, SeekOrigin.Begin);
+
+                               deserializedException = (SerializableException)binaryFormatter.Deserialize (memoryStream);
+                       }
+
+                       Assert.AreEqual ("success", deserializedException.Data);
+               }
+       }
+}
\ No newline at end of file
index 9ac0e97545427ada48cdaaadfddd1f60b0eef086..f053d51225e6e8a1db5babe82cd6507e70394c01 100644 (file)
@@ -488,7 +488,7 @@ namespace System.IO {
                                        f = new FileStream (path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read,
                                                            8192, false, (FileOptions) 1);
                                } catch (IOException ex){
-                                       if (ex.hresult != MonoIO.FileAlreadyExistsHResult || count ++ > 65536)
+                                       if (ex._HResult != MonoIO.FileAlreadyExistsHResult || count ++ > 65536)
                                                throw;
                                } catch (UnauthorizedAccessException ex) {
                                        if (count ++ > 65536)
index 544774d1786061abd71dcd490fc36a4c8e4dbf4b..1c0e73c485f4aee2d3f7e35a2b67a4d6737f5d0f 100644 (file)
@@ -751,5 +751,20 @@ namespace System.Reflection {
                public override IList<CustomAttributeData> GetCustomAttributesData () {
                        return CustomAttributeData.GetCustomAttributes (this);
                }
+
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               public extern int get_core_clr_security_level ();
+
+               public override bool IsSecurityTransparent {
+                       get { return get_core_clr_security_level () == 0; }
+               }
+
+               public override bool IsSecurityCritical {
+                       get { return get_core_clr_security_level () > 0; }
+               }
+
+               public override bool IsSecuritySafeCritical {
+                       get { return get_core_clr_security_level () == 1; }
+               }
        }
 }
index 8bed0815d260a9d15a98da78b35cdbbe2a62f6ba..24f15e3f980437e7877e372bf84a63afb6220ffb 100644 (file)
@@ -412,7 +412,7 @@ namespace System.Runtime.InteropServices
                        var errorInfo = new ManagedErrorInfo(e);
                        SetErrorInfo (0, errorInfo);
 
-                       return e.hresult;
+                       return e._HResult;
 #else                  
                        return -1;
 #endif
@@ -1591,7 +1591,7 @@ namespace System.Runtime.InteropServices
                                }
                        }
 
-                       if (info is ManagedErrorInfo && ((ManagedErrorInfo) info).Exception.hresult == errorCode) {
+                       if (info is ManagedErrorInfo && ((ManagedErrorInfo) info).Exception._HResult == errorCode) {
                                return ((ManagedErrorInfo) info).Exception;
                        }
 
index 1c17f0b76c0716362c35daf33e64de290a310b24..05513acf6b0c74888ea9038c64ea0627d53c55cc 100644 (file)
@@ -985,6 +985,19 @@ namespace System {
                {
 
                }
+
+               // Copied from referencesource Environment
+               internal static String GetStackTrace(Exception e, bool needFileInfo)
+               {
+                       System.Diagnostics.StackTrace st;
+                       if (e == null)
+                               st = new System.Diagnostics.StackTrace(needFileInfo);
+                       else
+                               st = new System.Diagnostics.StackTrace(e, needFileInfo);
+
+                       // Do not include a trailing newline for backwards compatibility
+                       return st.ToString( System.Diagnostics.StackTrace.TraceFormat.Normal );
+               }
        }
 }
 
diff --git a/mcs/class/corlib/System/Exception.cs b/mcs/class/corlib/System/Exception.cs
deleted file mode 100644 (file)
index 7b6b492..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-//
-// System.Exception.cs
-//
-// Author:
-//   Miguel de Icaza (miguel@ximian.com)
-//   Patrik Torstensson
-//
-// (C) Ximian, Inc.  http://www.ximian.com
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Reflection;
-using System.Text;
-using System.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
-using System.Runtime.Serialization;
-using System.Security.Permissions;
-
-namespace System
-{
-       [Serializable]
-       [ComVisible(true)]
-       [ComDefaultInterface (typeof (_Exception))]
-       [ClassInterface (ClassInterfaceType.None)]
-       [StructLayout (LayoutKind.Sequential)]
-#if MOBILE
-       public class Exception : ISerializable
-#else
-       public class Exception : ISerializable, _Exception
-#endif
-       {
-#pragma warning disable 169, 649
-               #region Sync with object-internals.h
-               /* Stores the IPs and the generic sharing infos
-                  (vtable/MRGCTX) of the frames. */
-               IntPtr [] trace_ips;
-               Exception inner_exception;
-               internal string _message;
-               string help_link;
-               string class_name;
-               string stack_trace;
-               // formerly known as remote_stack_trace (see #425512):
-               string _remoteStackTraceString;
-               int remote_stack_index;
-               internal int hresult = -2146233088;
-               string source;
-               IDictionary _data;
-               internal StackTrace[] captured_traces;
-               IntPtr[] native_trace_ips;
-               object dynamic_methods;
-               #endregion
-#pragma warning restore 169, 649
-
-               /* Don't add fields here, the runtime depends on the layout of subclasses */
-
-               public Exception ()
-               {
-               }
-
-               public Exception (string message)
-               {
-                       this._message = message;
-               }
-
-               protected Exception (SerializationInfo info, StreamingContext context)
-               {
-                       if (info == null)
-                               throw new ArgumentNullException ("info");
-
-                       class_name          = info.GetString ("ClassName");
-                       _message             = info.GetString ("Message");
-                       help_link           = info.GetString ("HelpURL");
-                       stack_trace         = info.GetString ("StackTraceString");
-                       _remoteStackTraceString  = info.GetString ("RemoteStackTraceString");
-                       remote_stack_index  = info.GetInt32  ("RemoteStackIndex");
-                       hresult             = info.GetInt32  ("HResult");
-                       source              = info.GetString ("Source");
-                       inner_exception     = (Exception) info.GetValue ("InnerException", typeof (Exception));
-
-                       try {
-                               _data = (IDictionary) info.GetValue ("Data", typeof (IDictionary));
-                       } catch (SerializationException) {
-                               // member did not exist in .NET 1.x
-                       }
-               }
-
-               public Exception (string message, Exception innerException)
-               {
-                       inner_exception = innerException;
-                       this._message = message;
-               }
-
-               public Exception InnerException {
-                       get { return inner_exception; }
-               }
-
-               public virtual string HelpLink {
-                       get { return help_link; }
-                       set { help_link = value; }
-               }
-
-               public int HResult {
-                       get { return hresult; }
-                       protected set { hresult = value; }
-               }
-               
-               internal void SetErrorCode(int hr)
-               {
-                       HResult = hr;
-               }
-
-               internal void SetMessage (string s)
-               {
-                       _message = s;
-               }
-
-               internal void SetStackTrace (string s)
-               {
-                       stack_trace = s;
-               }
-
-               string ClassName {
-                       get {
-                               if (class_name == null)
-                                       class_name = GetType ().ToString ();
-                               return class_name;
-                       }
-               }
-
-               public virtual string Message {
-                       get {
-                               if (_message == null)
-                                       _message = string.Format (Locale.GetText ("Exception of type '{0}' was thrown."),
-                                               ClassName);
-
-                               return _message;
-                       }
-               }
-               
-               [MonoTODO]
-               protected event EventHandler<SafeSerializationEventArgs> SerializeObjectState {
-                       add {
-                       }
-                       remove {
-                       }
-               }
-
-               public virtual string Source {
-                       get {
-                               if (source == null) {
-                                       StackTrace st = new StackTrace (this, true);
-                                       if (st.FrameCount > 0) {
-                                               StackFrame sf = st.GetFrame (0);
-                                               if (st != null) {
-                                                       MethodBase method = sf.GetMethod ();
-                                                       if (method != null) {
-                                                               source = method.DeclaringType.Assembly.UnprotectedGetName ().Name;
-                                                       }
-                                               }
-                                       }
-                               }
-
-                               // source can be null
-                               return source;
-                       }
-
-                       set {
-                               source = value;
-                       }
-               }
-
-               public virtual string StackTrace {
-                       get {
-                               if (stack_trace != null)
-                                       return stack_trace;
-
-                               if (trace_ips == null)
-                                       /* Not thrown yet */
-                                       return null;
-
-                               StackTrace st = new StackTrace (this, 0, true);
-                               return stack_trace = st.ToString ();
-                       }
-               }
-
-               public MethodBase TargetSite {
-                       get {
-                               StackTrace st = new StackTrace (this, true);
-                               if (st.FrameCount > 0)
-                                       return st.GetFrame (0).GetMethod ();
-                               
-                               return null;
-                       }
-               }
-
-               public virtual IDictionary Data {
-                       get {
-                               if (_data == null) {
-                                       // default to empty dictionary
-                                       _data = new Dictionary<object, object> ();
-                               }
-                               return _data;
-                       }
-               }
-
-               public virtual Exception GetBaseException ()
-               {
-                       Exception inner = inner_exception;
-                               
-                       while (inner != null)
-                       {
-                               if (inner.InnerException != null)
-                                       inner = inner.InnerException;
-                               else
-                                       return inner;
-                       }
-
-                       return this;
-               }
-
-               [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
-               public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
-               {
-                       if (info == null)
-                               throw new ArgumentNullException ("info");
-
-                       info.AddValue ("ClassName", ClassName);
-                       info.AddValue ("Message", _message);
-                       info.AddValue ("InnerException", inner_exception, typeof (Exception));
-                       info.AddValue ("HelpURL", help_link);
-                       info.AddValue ("StackTraceString", StackTrace);
-                       info.AddValue ("RemoteStackTraceString", _remoteStackTraceString);
-                       info.AddValue ("RemoteStackIndex", remote_stack_index);
-                       info.AddValue ("HResult", hresult);
-                       info.AddValue ("Source", Source);
-                       info.AddValue ("ExceptionMethod", null);
-                       info.AddValue ("Data", _data, typeof (IDictionary));
-               }
-
-               public override string ToString ()
-               {
-                       System.Text.StringBuilder result = new System.Text.StringBuilder (ClassName);
-                       result.Append (": ").Append (Message);
-
-                       if (null != _remoteStackTraceString)
-                               result.Append (_remoteStackTraceString);
-                               
-                       if (inner_exception != null) 
-                       {
-                               result.Append (" ---> ").Append (inner_exception.ToString ());
-                               result.Append (Environment.NewLine);
-                               result.Append (Locale.GetText ("  --- End of inner exception stack trace ---"));
-                       }
-
-                       if (StackTrace != null)
-                               result.Append (Environment.NewLine).Append (StackTrace);
-                       return result.ToString();
-               }
-
-               internal Exception FixRemotingException ()
-               {
-                       string message = (0 == remote_stack_index) ?
-                               Locale.GetText ("{0}{0}Server stack trace: {0}{1}{0}{0}Exception rethrown at [{2}]: {0}") :
-                               Locale.GetText ("{1}{0}{0}Exception rethrown at [{2}]: {0}");
-                       string tmp = String.Format (message, Environment.NewLine, StackTrace, remote_stack_index);
-
-                       _remoteStackTraceString = tmp;
-                       remote_stack_index++;
-
-                       stack_trace = null;
-
-                       return this;
-               }
-
-               // For ExceptionDispatchInfo
-               internal void RestoreExceptionDispatchInfo (System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo)
-               {
-                       captured_traces = (StackTrace[]) exceptionDispatchInfo.BinaryStackTraceArray;
-                       trace_ips = null;
-                       stack_trace = null;
-               }
-
-               //
-               // The documentation states that this is available in 1.x,
-               // but it was not available (MemberRefing this would fail)
-               // and it states the signature is `override sealed', but the
-               // correct value is `newslot' 
-               //
-               public new Type GetType ()
-               {
-                       return base.GetType ();
-               }
-
-               internal enum ExceptionMessageKind
-               {
-                       ThreadAbort = 1,
-                       ThreadInterrupted = 2,
-                       OutOfMemory = 3
-               }
-
-               internal static String GetMessageFromNativeResources (ExceptionMessageKind kind)
-               {
-                       switch (kind) {
-                       case ExceptionMessageKind.ThreadAbort:
-                               return "";
-                       case ExceptionMessageKind.ThreadInterrupted:
-                               return "";
-                       case ExceptionMessageKind.OutOfMemory:
-                               return "Out of memory";
-                       }
-                       return "";
-               }
-       }
-}
index c7f01bc6eb20ca1461ada0ce0b8511f5f1a637f4..fdca704f281fbf12cbce3fd54da84e1b067b445a 100644 (file)
@@ -100,7 +100,6 @@ System/DomainManagerInitializationFlags.cs
 System/EmptyArray.cs
 System/Environment.cs
 System/EnvironmentVariableTarget.cs
-System/Exception.cs
 System/GC.cs
 System/GCCollectionMode.cs
 System/GCNotificationStatus.cs
@@ -974,6 +973,7 @@ ReferenceSources/SecurityContext.cs
 ../../../external/referencesource/mscorlib/system/entrypointnotfoundexception.cs
 ../../../external/referencesource/mscorlib/system/eventargs.cs
 ../../../external/referencesource/mscorlib/system/eventhandler.cs
+../../../external/referencesource/mscorlib/system/exception.cs
 ../../../external/referencesource/mscorlib/system/executionengineexception.cs
 ../../../external/referencesource/mscorlib/system/fieldaccessexception.cs
 ../../../external/referencesource/mscorlib/system/flagsattribute.cs
index 44a1320f4d11176b36a263ae427d1846aa044305..60be82c6c144e9daf281083d09020dea81612acc 100644 (file)
@@ -578,6 +578,7 @@ ICALL(MODULE_13, "get_MetadataToken", ves_icall_reflection_get_token)
 ICALL_TYPE(MCMETH, "System.Reflection.MonoCMethod", MCMETH_1)
 ICALL(MCMETH_1, "GetGenericMethodDefinition_impl", ves_icall_MonoMethod_GetGenericMethodDefinition)
 ICALL(MCMETH_2, "InternalInvoke", ves_icall_InternalInvoke)
+ICALL(MCMETH_3, "get_core_clr_security_level", ves_icall_MonoMethod_get_core_clr_security_level)
 
 ICALL_TYPE(MEVIN, "System.Reflection.MonoEventInfo", MEVIN_1)
 ICALL(MEVIN_1, "get_event_info", ves_icall_MonoEventInfo_get_event_info)
index 691d4374674c269d090daa093cc12a1770cc425e..17d5eea26ef0a572d6a7ff0ad8c2676f88629860 100644 (file)
@@ -201,23 +201,24 @@ typedef struct {
 
 struct _MonoException {
        MonoObject object;
+       MonoString *class_name;
+       MonoString *message;
+       MonoObject *_data;
+       MonoObject *inner_ex;
+       MonoString *help_link;
        /* Stores the IPs and the generic sharing infos
           (vtable/MRGCTX) of the frames. */
        MonoArray  *trace_ips;
-       MonoObject *inner_ex;
-       MonoString *message;
-       MonoString *help_link;
-       MonoString *class_name;
        MonoString *stack_trace;
        MonoString *remote_stack_trace;
        gint32      remote_stack_index;
+       /* Dynamic methods referenced by the stack trace */
+       MonoObject *dynamic_methods;
        gint32      hresult;
        MonoString *source;
-       MonoObject *_data;
+       MonoObject *serialization_manager;
        MonoObject *captured_traces;
        MonoArray  *native_trace_ips;
-       /* Dynamic methods referenced by the stack trace */
-       MonoObject *dynamic_methods;
 };
 
 typedef struct {