The Labs \ Source Viewer \ SSCLI \ System \ Exception

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*=============================================================================
  16. **
  17. ** Class: Exception
  18. **
  19. **
  20. ** Purpose: The base class for all exceptional conditions.
  21. **
  22. **
  23. =============================================================================*/
  24. namespace System
  25. {
  26.     using System;
  27.     using System.Runtime.InteropServices;
  28.     using System.Runtime.CompilerServices;
  29.     using MethodInfo = System.Reflection.MethodInfo;
  30.     using MethodBase = System.Reflection.MethodBase;
  31.     using System.Runtime.Serialization;
  32.     using System.Diagnostics;
  33.     using System.Security.Permissions;
  34.     using System.Security;
  35.     using System.IO;
  36.     using System.Text;
  37.     using System.Reflection;
  38.     using System.Collections;
  39.     using System.Globalization;
  40.    
  41.    
  42.     [ClassInterface(ClassInterfaceType.None)]
  43.     [ComDefaultInterface(typeof(_Exception))]
  44.     [Serializable()]
  45.     [ComVisible(true)]
  46.     public class Exception : ISerializable, _Exception
  47.     {
  48.         public Exception()
  49.         {
  50.             _message = null;
  51.             _stackTrace = null;
  52.             _dynamicMethods = null;
  53.             HResult = __HResults.COR_E_EXCEPTION;
  54.             _xcode = _COMPlusExceptionCode;
  55.             _xptrs = (IntPtr)0;
  56.         }
  57.        
  58.         public Exception(string message)
  59.         {
  60.             _message = message;
  61.             _stackTrace = null;
  62.             _dynamicMethods = null;
  63.             HResult = __HResults.COR_E_EXCEPTION;
  64.             _xcode = _COMPlusExceptionCode;
  65.             _xptrs = (IntPtr)0;
  66.         }
  67.        
  68.         // Creates a new Exception. All derived classes should
  69.         // provide this constructor.
  70.         // Note: the stack trace is not started until the exception
  71.         // is thrown
  72.         //
  73.         public Exception(string message, Exception innerException)
  74.         {
  75.             _message = message;
  76.             _stackTrace = null;
  77.             _dynamicMethods = null;
  78.             _innerException = innerException;
  79.             HResult = __HResults.COR_E_EXCEPTION;
  80.             _xcode = _COMPlusExceptionCode;
  81.             _xptrs = (IntPtr)0;
  82.         }
  83.        
  84.         protected Exception(SerializationInfo info, StreamingContext context)
  85.         {
  86.             if (info == null)
  87.                 throw new ArgumentNullException("info");
  88.            
  89.             _className = info.GetString("ClassName");
  90.             _message = info.GetString("Message");
  91.             _data = (IDictionary)(info.GetValueNoThrow("Data", typeof(IDictionary)));
  92.             _innerException = (Exception)(info.GetValue("InnerException", typeof(Exception)));
  93.             _helpURL = info.GetString("HelpURL");
  94.             _stackTraceString = info.GetString("StackTraceString");
  95.             _remoteStackTraceString = info.GetString("RemoteStackTraceString");
  96.             _remoteStackIndex = info.GetInt32("RemoteStackIndex");
  97.            
  98.             _exceptionMethodString = (string)(info.GetValue("ExceptionMethod", typeof(string)));
  99.             HResult = info.GetInt32("HResult");
  100.             _source = info.GetString("Source");
  101.            
  102.             if (_className == null || HResult == 0)
  103.                 throw new SerializationException(Environment.GetResourceString("Serialization_InsufficientState"));
  104.            
  105.             // If we are constructing a new exception after a cross-appdomain call...
  106.             if (context.State == StreamingContextStates.CrossAppDomain) {
  107.                 // ...this new exception may get thrown. It is logically a re-throw, but
  108.                 // physically a brand-new exception. Since the stack trace is cleared
  109.                 // on a new exception, the "_remoteStackTraceString" is provided to
  110.                 // effectively import a stack trace from a "remote" exception. So,
  111.                 // move the _stackTraceString into the _remoteStackTraceString. Note
  112.                 // that if there is an existing _remoteStackTraceString, it will be
  113.                 // preserved at the head of the new string, so everything works as
  114.                 // expected.
  115.                 // Even if this exception is NOT thrown, things will still work as expected
  116.                 // because the StackTrace property returns the concatenation of the
  117.                 // _remoteStackTraceString and the _stackTraceString.
  118.                 _remoteStackTraceString = _remoteStackTraceString + _stackTraceString;
  119.                 _stackTraceString = null;
  120.             }
  121.            
  122.         }
  123.        
  124.        
  125.         public virtual string Message {
  126.             get {
  127.                 if (_message == null) {
  128.                     if (_className == null) {
  129.                         _className = GetClassName();
  130.                     }
  131.                     return String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Exception_WasThrown"), _className);
  132.                 }
  133.                 else {
  134.                     return _message;
  135.                 }
  136.             }
  137.         }
  138.        
  139.         public virtual IDictionary Data {
  140.             get { return GetDataInternal(); }
  141.         }
  142.        
  143.         // This method is internal so that callers can't override which function they call.
  144.         internal IDictionary GetDataInternal()
  145.         {
  146.             if (_data == null)
  147.                 if (IsImmutableAgileException(this))
  148.                     _data = new EmptyReadOnlyDictionaryInternal();
  149.                 else
  150.                     _data = new ListDictionaryInternal();
  151.            
  152.             return _data;
  153.         }
  154.        
  155.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  156.         private static extern bool IsImmutableAgileException(Exception e);
  157.        
  158.        
  159.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  160.         private extern string GetClassName();
  161.        
  162.         // Retrieves the lowest exception (inner most) for the given Exception.
  163.         // This will traverse exceptions using the innerException property.
  164.         //
  165.         public virtual Exception GetBaseException()
  166.         {
  167.             Exception inner = InnerException;
  168.             Exception back = this;
  169.            
  170.             while (inner != null) {
  171.                 back = inner;
  172.                 inner = inner.InnerException;
  173.             }
  174.            
  175.             return back;
  176.         }
  177.        
  178.         // Returns the inner exception contained in this exception
  179.         //
  180.         public Exception InnerException {
  181.             get { return _innerException; }
  182.         }
  183.        
  184.        
  185.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  186.         unsafe private static extern void* _InternalGetMethod(object stackTrace);
  187.         unsafe private static RuntimeMethodHandle InternalGetMethod(object stackTrace)
  188.         {
  189.             return new RuntimeMethodHandle(_InternalGetMethod(stackTrace));
  190.         }
  191.        
  192.        
  193.         public MethodBase TargetSite {
  194.             get { return GetTargetSiteInternal(); }
  195.         }
  196.        
  197.        
  198.         // this function is provided as a private helper to avoid the security demand
  199.         private MethodBase GetTargetSiteInternal()
  200.         {
  201.             if (_exceptionMethod != null) {
  202.                 return _exceptionMethod;
  203.             }
  204.             if (_stackTrace == null) {
  205.                 return null;
  206.             }
  207.            
  208.             if (_exceptionMethodString != null) {
  209.                 _exceptionMethod = GetExceptionMethodFromString();
  210.             }
  211.             else {
  212.                 RuntimeMethodHandle method = InternalGetMethod(_stackTrace).GetTypicalMethodDefinition();
  213.                 _exceptionMethod = RuntimeType.GetMethodBase(method);
  214.             }
  215.             return _exceptionMethod;
  216.         }
  217.        
  218.         // Returns the stack trace as a string. If no stack trace is
  219.         // available, null is returned.
  220.         public virtual string StackTrace {
  221.             get {
  222.                 // if no stack trace, try to get one
  223.                 if (_stackTraceString != null) {
  224.                     return _remoteStackTraceString + _stackTraceString;
  225.                 }
  226.                 if (_stackTrace == null) {
  227.                     return _remoteStackTraceString;
  228.                 }
  229.                
  230.                 // Obtain the stack trace string. Note that since Environment.GetStackTrace
  231.                 // will add the path to the source file if the PDB is present and a demand
  232.                 // for PathDiscoveryPermission succeeds, we need to make sure we don't store
  233.                 // the stack trace string in the _stackTraceString member variable.
  234.                 string tempStackTraceString = Environment.GetStackTrace(this, true);
  235.                 return _remoteStackTraceString + tempStackTraceString;
  236.             }
  237.         }
  238.        
  239.         internal void SetErrorCode(int hr)
  240.         {
  241.             HResult = hr;
  242.         }
  243.        
  244.         // Sets the help link for this exception.
  245.         // This should be in a URL/URN form, such as:
  246.         // "file:///C:/Applications/Bazzal/help.html#ErrorNum42"
  247.         // Changed to be a read-write String and not return an exception
  248.         public virtual string HelpLink {
  249.             get { return _helpURL; }
  250.             set { _helpURL = value; }
  251.         }
  252.        
  253.         public virtual string Source {
  254.             get {
  255.                 if (_source == null) {
  256.                     StackTrace st = new StackTrace(this, true);
  257.                     if (st.FrameCount > 0) {
  258.                         StackFrame sf = st.GetFrame(0);
  259.                         MethodBase method = sf.GetMethod();
  260.                         _source = method.Module.Assembly.nGetSimpleName();
  261.                     }
  262.                 }
  263.                
  264.                 return _source;
  265.             }
  266.             set { _source = value; }
  267.         }
  268.        
  269.         public override string ToString()
  270.         {
  271.             string message = Message;
  272.             string s;
  273.             if (_className == null) {
  274.                 _className = GetClassName();
  275.             }
  276.            
  277.             if (message == null || message.Length <= 0) {
  278.                 s = _className;
  279.             }
  280.             else {
  281.                 s = _className + ": " + message;
  282.             }
  283.            
  284.             if (_innerException != null) {
  285.                 s = s + " ---> " + _innerException.ToString() + Environment.NewLine + " " + Environment.GetResourceString("Exception_EndOfInnerExceptionStack");
  286.             }
  287.            
  288.            
  289.             if (StackTrace != null)
  290.                 s += Environment.NewLine + StackTrace;
  291.            
  292.             return s;
  293.         }
  294.        
  295.         private string GetExceptionMethodString()
  296.         {
  297.             MethodBase methBase = GetTargetSiteInternal();
  298.             if (methBase == null) {
  299.                 return null;
  300.             }
  301.             // Note that the newline separator is only a separator, chosen such that
  302.             // it won't (generally) occur in a method name. This string is used
  303.             // only for serialization of the Exception Method.
  304.             char separator = '\n';
  305.             StringBuilder result = new StringBuilder();
  306.             if (methBase is ConstructorInfo) {
  307.                 RuntimeConstructorInfo rci = (RuntimeConstructorInfo)methBase;
  308.                 Type t = rci.ReflectedType;
  309.                 result.Append((int)MemberTypes.Constructor);
  310.                 result.Append(separator);
  311.                 result.Append(rci.Name);
  312.                 if (t != null) {
  313.                     result.Append(separator);
  314.                     result.Append(t.Assembly.FullName);
  315.                     result.Append(separator);
  316.                     result.Append(t.FullName);
  317.                 }
  318.                 result.Append(separator);
  319.                 result.Append(rci.ToString());
  320.             }
  321.             else {
  322.                 BCLDebug.Assert(methBase is MethodInfo, "[Exception.GetExceptionMethodString]methBase is MethodInfo");
  323.                 RuntimeMethodInfo rmi = (RuntimeMethodInfo)methBase;
  324.                 Type t = rmi.DeclaringType;
  325.                 result.Append((int)MemberTypes.Method);
  326.                 result.Append(separator);
  327.                 result.Append(rmi.Name);
  328.                 result.Append(separator);
  329.                 result.Append(rmi.Module.Assembly.FullName);
  330.                 result.Append(separator);
  331.                 if (t != null) {
  332.                     result.Append(t.FullName);
  333.                     result.Append(separator);
  334.                 }
  335.                 result.Append(rmi.ToString());
  336.             }
  337.            
  338.             return result.ToString();
  339.         }
  340.        
  341.         private MethodBase GetExceptionMethodFromString()
  342.         {
  343.             BCLDebug.Assert(_exceptionMethodString != null, "Method string cannot be NULL!");
  344.             string[] args = _exceptionMethodString.Split(new char[] {'\0', '\n'});
  345.             if (args.Length != 5) {
  346.                 throw new SerializationException();
  347.             }
  348.             SerializationInfo si = new SerializationInfo(typeof(MemberInfoSerializationHolder), new FormatterConverter());
  349.             si.AddValue("MemberType", (int)Int32.Parse(args[0], CultureInfo.InvariantCulture), typeof(Int32));
  350.             si.AddValue("Name", args[1], typeof(string));
  351.             si.AddValue("AssemblyName", args[2], typeof(string));
  352.             si.AddValue("ClassName", args[3]);
  353.             si.AddValue("Signature", args[4]);
  354.             MethodBase result;
  355.             StreamingContext sc = new StreamingContext(StreamingContextStates.All);
  356.             try {
  357.                 result = (MethodBase)new MemberInfoSerializationHolder(si, sc).GetRealObject(sc);
  358.             }
  359.             catch (SerializationException) {
  360.                 result = null;
  361.             }
  362.             return result;
  363.         }
  364.        
  365.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  366.         public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
  367.         {
  368.             string tempStackTraceString = _stackTraceString;
  369.            
  370.             if (info == null) {
  371.                 throw new ArgumentNullException("info");
  372.             }
  373.             if (_className == null) {
  374.                 _className = GetClassName();
  375.             }
  376.            
  377.             if (_stackTrace != null) {
  378.                 if (tempStackTraceString == null) {
  379.                     tempStackTraceString = Environment.GetStackTrace(this, true);
  380.                 }
  381.                 if (_exceptionMethod == null) {
  382.                     RuntimeMethodHandle method = InternalGetMethod(_stackTrace).GetTypicalMethodDefinition();
  383.                     _exceptionMethod = RuntimeType.GetMethodBase(method);
  384.                 }
  385.             }
  386.            
  387.             if (_source == null) {
  388.                 _source = Source;
  389.                 // Set the Source information correctly before serialization
  390.             }
  391.            
  392.             info.AddValue("ClassName", _className, typeof(string));
  393.             info.AddValue("Message", _message, typeof(string));
  394.             info.AddValue("Data", _data, typeof(IDictionary));
  395.             info.AddValue("InnerException", _innerException, typeof(Exception));
  396.             info.AddValue("HelpURL", _helpURL, typeof(string));
  397.             info.AddValue("StackTraceString", tempStackTraceString, typeof(string));
  398.             info.AddValue("RemoteStackTraceString", _remoteStackTraceString, typeof(string));
  399.             info.AddValue("RemoteStackIndex", _remoteStackIndex, typeof(Int32));
  400.             info.AddValue("ExceptionMethod", GetExceptionMethodString(), typeof(string));
  401.             info.AddValue("HResult", HResult);
  402.             info.AddValue("Source", _source, typeof(string));
  403.         }
  404.        
  405.         // This is used by remoting to preserve the server side stack trace
  406.         // by appending it to the message ... before the exception is rethrown
  407.         // at the client call site.
  408.         internal Exception PrepForRemoting()
  409.         {
  410.             string tmp = null;
  411.            
  412.             if (_remoteStackIndex == 0) {
  413.                 tmp = Environment.NewLine + "Server stack trace: " + Environment.NewLine + StackTrace + Environment.NewLine + Environment.NewLine + "Exception rethrown at [" + _remoteStackIndex + "]: " + Environment.NewLine;
  414.             }
  415.             else {
  416.                 tmp = StackTrace + Environment.NewLine + Environment.NewLine + "Exception rethrown at [" + _remoteStackIndex + "]: " + Environment.NewLine;
  417.             }
  418.            
  419.             _remoteStackTraceString = tmp;
  420.             _remoteStackIndex++;
  421.             return this;
  422.         }
  423.        
  424.         // This is used by the runtime when re-throwing a managed exception. It will
  425.         // copy the stack trace to _remoteStackTraceString.
  426.         internal void InternalPreserveStackTrace()
  427.         {
  428.             string tmpStackTraceString = StackTrace;
  429.             if (tmpStackTraceString != null && tmpStackTraceString.Length > 0)
  430.                 _remoteStackTraceString = tmpStackTraceString + Environment.NewLine;
  431.             _stackTrace = null;
  432.             _stackTraceString = null;
  433.         }
  434.        
  435.         private string _className;
  436.         //Needed for serialization.
  437.         private MethodBase _exceptionMethod;
  438.         //Needed for serialization.
  439.         private string _exceptionMethodString;
  440.         //Needed for serialization.
  441.         internal string _message;
  442.         private IDictionary _data;
  443.         private Exception _innerException;
  444.         private string _helpURL;
  445.         private object _stackTrace;
  446.        
  447.         private string _stackTraceString;
  448.         //Needed for serialization.
  449.         private string _remoteStackTraceString;
  450.         private int _remoteStackIndex;
  451.         #pragma warning disable 414 // Field is not used from managed.
  452.         // _dynamicMethods is an array of System.Resolver objects, used to keep
  453.         // DynamicMethodDescs alive for the lifetime of the exception. We do this because
  454.         // the _stackTrace field holds MethodDescs, and a DynamicMethodDesc can be destroyed
  455.         // unless a System.Resolver object roots it.
  456.         private object _dynamicMethods;
  457.         #pragma warning restore 414
  458.        
  459.         // @MANAGED: HResult is used from within the EE! Rename with care - check VM directory
  460.         internal int _HResult;
  461.         // HResult
  462.         protected int HResult {
  463.             get { return _HResult; }
  464.             set { _HResult = value; }
  465.         }
  466.        
  467.         private string _source;
  468.         // Mainly used by VB.
  469.         // WARNING: Don't delete/rename _xptrs and _xcode - used by functions
  470.         // on Marshal class. Native functions are in COMUtilNative.cpp & AppDomain
  471.         private IntPtr _xptrs;
  472.         // Internal EE stuff
  473.         #pragma warning disable 414 // Field is not used from managed.
  474.         private int _xcode;
  475.         // Internal EE stuff
  476.         #pragma warning restore 414
  477.         // See clr\src\vm\excep.h's EXCEPTION_COMPLUS definition:
  478.         private const int _COMPlusExceptionCode = unchecked((int)3763490644u);
  479.         // Win32 exception code for COM+ exceptions
  480.         internal virtual string InternalToString()
  481.         {
  482.             try {
  483.                 SecurityPermission sp = new SecurityPermission(SecurityPermissionFlag.ControlEvidence | SecurityPermissionFlag.ControlPolicy);
  484.                 sp.Assert();
  485.             }
  486.             catch {
  487.             }
  488.             return ToString();
  489.         }
  490.        
  491.         // this method is required so Object.GetType is not made virtual by the compiler
  492.         public new Type GetType()
  493.         {
  494.             return base.GetType();
  495.         }
  496.        
  497.         internal bool IsTransient {
  498.             get { return nIsTransient(_HResult); }
  499.         }
  500.        
  501.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  502.         private static extern bool nIsTransient(int hr);
  503.        
  504.        
  505.         // This piece of infrastructure exists to help avoid deadlocks
  506.         // between parts of mscorlib that might throw an exception while
  507.         // holding a lock that are also used by mscorlib's ResourceManager
  508.         // instance. As a special case of code that may throw while holding
  509.         // a lock, we also need to fix our asynchronous exceptions to use
  510.         // Win32 resources as well (assuming we ever call a managed
  511.         // constructor on instances of them). We should grow this set of
  512.         // exception messages as we discover problems, then move the resources
  513.         // involved to native code.
  514.         internal enum ExceptionMessageKind
  515.         {
  516.             ThreadAbort = 1,
  517.             ThreadInterrupted = 2,
  518.             OutOfMemory = 3
  519.         }
  520.        
  521.         // See comment on ExceptionMessageKind
  522.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  523.         static internal extern string GetMessageFromNativeResources(ExceptionMessageKind kind);
  524.     }
  525. }

Developer Fusion