1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*=============================================================================
9 ** Purpose: The base class for all exceptional conditions.
12 =============================================================================*/
17 using System.Runtime.InteropServices;
18 using System.Runtime.CompilerServices;
19 using System.Runtime.Serialization;
20 using System.Runtime.Versioning;
21 using System.Diagnostics;
22 using System.Security;
25 using System.Reflection;
26 using System.Collections;
27 using System.Globalization;
30 [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
31 public class Exception : ISerializable
37 _dynamicMethods = null;
38 HResult = HResults.COR_E_EXCEPTION;
39 _xcode = _COMPlusExceptionCode;
42 // Initialize the WatsonBuckets to be null
43 _watsonBuckets = null;
45 // Initialize the watson bucketing IP
46 _ipForWatsonBuckets = UIntPtr.Zero;
54 public Exception(String message)
60 // Creates a new Exception. All derived classes should
61 // provide this constructor.
62 // Note: the stack trace is not started until the exception
65 public Exception(String message, Exception innerException)
69 _innerException = innerException;
72 protected Exception(SerializationInfo info, StreamingContext context)
75 throw new ArgumentNullException(nameof(info));
77 _className = info.GetString("ClassName"); // Do not rename (binary serialization)
78 _message = info.GetString("Message"); // Do not rename (binary serialization)
79 _data = (IDictionary)(info.GetValueNoThrow("Data", typeof(IDictionary))); // Do not rename (binary serialization)
80 _innerException = (Exception)(info.GetValue("InnerException", typeof(Exception))); // Do not rename (binary serialization)
81 _helpURL = info.GetString("HelpURL"); // Do not rename (binary serialization)
82 _stackTraceString = info.GetString("StackTraceString"); // Do not rename (binary serialization)
83 _remoteStackTraceString = info.GetString("RemoteStackTraceString"); // Do not rename (binary serialization)
84 _remoteStackIndex = info.GetInt32("RemoteStackIndex"); // Do not rename (binary serialization)
86 HResult = info.GetInt32("HResult"); // Do not rename (binary serialization)
87 _source = info.GetString("Source"); // Do not rename (binary serialization)
89 // Get the WatsonBuckets that were serialized - this is particularly
90 // done to support exceptions going across AD transitions.
92 // We use the no throw version since we could be deserializing a pre-V4
93 // exception object that may not have this entry. In such a case, we would
95 _watsonBuckets = (Object)info.GetValueNoThrow("WatsonBuckets", typeof(byte[])); // Do not rename (binary serialization)
98 if (_className == null || HResult == 0)
99 throw new SerializationException(SR.Serialization_InsufficientState);
101 // If we are constructing a new exception after a cross-appdomain call...
102 if (context.State == StreamingContextStates.CrossAppDomain)
104 // ...this new exception may get thrown. It is logically a re-throw, but
105 // physically a brand-new exception. Since the stack trace is cleared
106 // on a new exception, the "_remoteStackTraceString" is provided to
107 // effectively import a stack trace from a "remote" exception. So,
108 // move the _stackTraceString into the _remoteStackTraceString. Note
109 // that if there is an existing _remoteStackTraceString, it will be
110 // preserved at the head of the new string, so everything works as
112 // Even if this exception is NOT thrown, things will still work as expected
113 // because the StackTrace property returns the concatenation of the
114 // _remoteStackTraceString and the _stackTraceString.
115 _remoteStackTraceString = _remoteStackTraceString + _stackTraceString;
116 _stackTraceString = null;
121 public virtual String Message
125 if (_message == null)
127 if (_className == null)
129 _className = GetClassName();
131 return SR.Format(SR.Exception_WasThrown, _className);
140 public virtual IDictionary Data
145 if (IsImmutableAgileException(this))
146 _data = new EmptyReadOnlyDictionaryInternal();
148 _data = new ListDictionaryInternal();
154 [MethodImplAttribute(MethodImplOptions.InternalCall)]
155 private static extern bool IsImmutableAgileException(Exception e);
157 #if FEATURE_COMINTEROP
159 // Exception requires anything to be added into Data dictionary is serializable
160 // This wrapper is made serializable to satisfy this requirement but does NOT serialize
161 // the object and simply ignores it during serialization, because we only need
162 // the exception instance in the app to hold the error object alive.
163 // Once the exception is serialized to debugger, debugger only needs the error reference string
166 internal class __RestrictedErrorObject
168 // Hold the error object instance but don't serialize/deserialize it
170 private object _realErrorObject;
172 internal __RestrictedErrorObject(object errorObject)
174 _realErrorObject = errorObject;
177 public object RealErrorObject
181 return _realErrorObject;
186 // [FriendAccessAllowed]
187 internal void AddExceptionDataForRestrictedErrorInfo(
188 string restrictedError,
189 string restrictedErrorReference,
190 string restrictedCapabilitySid,
191 object restrictedErrorObject,
192 bool hasrestrictedLanguageErrorObject = false)
194 IDictionary dict = Data;
197 dict.Add("RestrictedDescription", restrictedError);
198 dict.Add("RestrictedErrorReference", restrictedErrorReference);
199 dict.Add("RestrictedCapabilitySid", restrictedCapabilitySid);
201 // Keep the error object alive so that user could retrieve error information
202 // using Data["RestrictedErrorReference"]
203 dict.Add("__RestrictedErrorObject", (restrictedErrorObject == null ? null : new __RestrictedErrorObject(restrictedErrorObject)));
204 dict.Add("__HasRestrictedLanguageErrorObject", hasrestrictedLanguageErrorObject);
208 internal bool TryGetRestrictedLanguageErrorObject(out object restrictedErrorObject)
210 restrictedErrorObject = null;
211 if (Data != null && Data.Contains("__HasRestrictedLanguageErrorObject"))
213 if (Data.Contains("__RestrictedErrorObject"))
215 __RestrictedErrorObject restrictedObject = Data["__RestrictedErrorObject"] as __RestrictedErrorObject;
216 if (restrictedObject != null)
217 restrictedErrorObject = restrictedObject.RealErrorObject;
219 return (bool)Data["__HasRestrictedLanguageErrorObject"];
224 #endif // FEATURE_COMINTEROP
226 private string GetClassName()
228 // Will include namespace but not full instantiation and assembly name.
229 if (_className == null)
230 _className = GetType().ToString();
235 // Retrieves the lowest exception (inner most) for the given Exception.
236 // This will traverse exceptions using the innerException property.
238 public virtual Exception GetBaseException()
240 Exception inner = InnerException;
241 Exception back = this;
243 while (inner != null)
246 inner = inner.InnerException;
252 // Returns the inner exception contained in this exception
254 public Exception InnerException
256 get { return _innerException; }
260 [MethodImplAttribute(MethodImplOptions.InternalCall)]
261 static extern private IRuntimeMethodInfo GetMethodFromStackTrace(Object stackTrace);
263 private MethodBase GetExceptionMethodFromStackTrace()
265 IRuntimeMethodInfo method = GetMethodFromStackTrace(_stackTrace);
267 // Under certain race conditions when exceptions are re-used, this can be null
271 return RuntimeType.GetMethodBase(method);
274 public MethodBase TargetSite
278 return GetTargetSiteInternal();
283 // this function is provided as a private helper to avoid the security demand
284 private MethodBase GetTargetSiteInternal()
286 if (_exceptionMethod != null)
288 return _exceptionMethod;
290 if (_stackTrace == null)
295 _exceptionMethod = GetExceptionMethodFromStackTrace();
296 return _exceptionMethod;
299 // Returns the stack trace as a string. If no stack trace is
300 // available, null is returned.
301 public virtual String StackTrace
305 // By default attempt to include file and line number info
306 return GetStackTrace(true);
310 // Computes and returns the stack trace as a string
311 // Attempts to get source file and line number information if needFileInfo
312 // is true. Note that this requires FileIOPermission(PathDiscovery), and so
313 // will usually fail in CoreCLR. To avoid the demand and resulting
314 // SecurityException we can explicitly not even try to get fileinfo.
315 private string GetStackTrace(bool needFileInfo)
317 string stackTraceString = _stackTraceString;
318 string remoteStackTraceString = _remoteStackTraceString;
320 // if no stack trace, try to get one
321 if (stackTraceString != null)
323 return remoteStackTraceString + stackTraceString;
325 if (_stackTrace == null)
327 return remoteStackTraceString;
330 // Obtain the stack trace string. Note that since Environment.GetStackTrace
331 // will add the path to the source file if the PDB is present and a demand
332 // for FileIOPermission(PathDiscovery) succeeds, we need to make sure we
333 // don't store the stack trace string in the _stackTraceString member variable.
334 String tempStackTraceString = Environment.GetStackTrace(this, needFileInfo);
335 return remoteStackTraceString + tempStackTraceString;
338 // [FriendAccessAllowed]
339 internal void SetErrorCode(int hr)
344 // Sets the help link for this exception.
345 // This should be in a URL/URN form, such as:
346 // "file:///C:/Applications/Bazzal/help.html#ErrorNum42"
347 // Changed to be a read-write String and not return an exception
348 public virtual String HelpLink
360 public virtual String Source
366 StackTrace st = new StackTrace(this, true);
367 if (st.FrameCount > 0)
369 StackFrame sf = st.GetFrame(0);
370 MethodBase method = sf.GetMethod();
372 Module module = method.Module;
374 RuntimeModule rtModule = module as RuntimeModule;
376 if (rtModule == null)
378 System.Reflection.Emit.ModuleBuilder moduleBuilder = module as System.Reflection.Emit.ModuleBuilder;
379 if (moduleBuilder != null)
380 rtModule = moduleBuilder.InternalModule;
382 throw new ArgumentException(SR.Argument_MustBeRuntimeReflectionObject);
385 _source = rtModule.GetRuntimeAssembly().GetSimpleName();
391 set { _source = value; }
394 public override String ToString()
396 return ToString(true, true);
399 private String ToString(bool needFileLineInfo, bool needMessage)
401 String message = (needMessage ? Message : null);
404 if (message == null || message.Length <= 0)
410 s = GetClassName() + ": " + message;
413 if (_innerException != null)
415 s = s + " ---> " + _innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine +
416 " " + SR.Exception_EndOfInnerExceptionStack;
419 string stackTrace = GetStackTrace(needFileLineInfo);
420 if (stackTrace != null)
422 s += Environment.NewLine + stackTrace;
428 protected event EventHandler<SafeSerializationEventArgs> SerializeObjectState
430 add { throw new PlatformNotSupportedException(SR.PlatformNotSupported_SecureBinarySerialization); }
431 remove { throw new PlatformNotSupportedException(SR.PlatformNotSupported_SecureBinarySerialization); }
434 public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
438 throw new ArgumentNullException(nameof(info));
441 String tempStackTraceString = _stackTraceString;
443 if (_stackTrace != null)
445 if (tempStackTraceString == null)
447 tempStackTraceString = Environment.GetStackTrace(this, true);
449 if (_exceptionMethod == null)
451 _exceptionMethod = GetExceptionMethodFromStackTrace();
457 _source = Source; // Set the Source information correctly before serialization
460 info.AddValue("ClassName", GetClassName(), typeof(String)); // Do not rename (binary serialization)
461 info.AddValue("Message", _message, typeof(String)); // Do not rename (binary serialization)
462 info.AddValue("Data", _data, typeof(IDictionary)); // Do not rename (binary serialization)
463 info.AddValue("InnerException", _innerException, typeof(Exception)); // Do not rename (binary serialization)
464 info.AddValue("HelpURL", _helpURL, typeof(String)); // Do not rename (binary serialization)
465 info.AddValue("StackTraceString", tempStackTraceString, typeof(String)); // Do not rename (binary serialization)
466 info.AddValue("RemoteStackTraceString", _remoteStackTraceString, typeof(String)); // Do not rename (binary serialization)
467 info.AddValue("RemoteStackIndex", _remoteStackIndex, typeof(Int32)); // Do not rename (binary serialization)
468 info.AddValue("ExceptionMethod", null, typeof(String)); // Do not rename (binary serialization)
469 info.AddValue("HResult", HResult); // Do not rename (binary serialization)
470 info.AddValue("Source", _source, typeof(String)); // Do not rename (binary serialization)
472 // Serialize the Watson bucket details as well
473 info.AddValue("WatsonBuckets", _watsonBuckets, typeof(byte[])); // Do not rename (binary serialization)
476 // This method will clear the _stackTrace of the exception object upon deserialization
477 // to ensure that references from another AD/Process dont get accidentally used.
479 private void OnDeserialized(StreamingContext context)
483 // We wont serialize or deserialize the IP for Watson bucketing since
484 // we dont know where the deserialized object will be used in.
485 // Using it across process or an AppDomain could be invalid and result
486 // in AV in the runtime.
488 // Hence, we set it to zero when deserialization takes place.
489 _ipForWatsonBuckets = UIntPtr.Zero;
492 // This is used by the runtime when re-throwing a managed exception. It will
493 // copy the stack trace to _remoteStackTraceString.
494 internal void InternalPreserveStackTrace()
496 string tmpStackTraceString;
499 if (AppDomain.IsAppXModel())
501 // Call our internal GetStackTrace in AppX so we can parse the result should
502 // we need to strip file/line info from it to make it PII-free. Calling the
503 // public and overridable StackTrace getter here was probably not intended.
504 tmpStackTraceString = GetStackTrace(true);
506 // Make sure that the _source field is initialized if Source is not overriden.
507 // We want it to contain the original faulting point.
508 string source = Source;
511 #else // FEATURE_APPX
512 // Preinitialize _source on CoreSystem as well. The legacy behavior is not ideal and
513 // we keep it for back compat but we can afford to make the change on the Phone.
514 string source = Source;
515 #endif // FEATURE_APPX
517 // Call the StackTrace getter in classic for compat.
518 tmpStackTraceString = StackTrace;
521 if (tmpStackTraceString != null && tmpStackTraceString.Length > 0)
523 _remoteStackTraceString = tmpStackTraceString + Environment.NewLine;
527 _stackTraceString = null;
531 // This is the object against which a lock will be taken
532 // when attempt to restore the EDI. Since its static, its possible
533 // that unrelated exception object restorations could get blocked
534 // for a small duration but that sounds reasonable considering
535 // such scenarios are going to be extremely rare, where timing
536 // matches precisely.
538 private static object s_EDILock = new object();
540 internal UIntPtr IPForWatsonBuckets
544 return _ipForWatsonBuckets;
548 internal object WatsonBuckets
552 return _watsonBuckets;
556 internal string RemoteStackTrace
560 return _remoteStackTraceString;
564 [MethodImplAttribute(MethodImplOptions.InternalCall)]
565 private static extern void PrepareForForeignExceptionRaise();
567 [MethodImplAttribute(MethodImplOptions.InternalCall)]
568 private static extern void GetStackTracesDeepCopy(Exception exception, out object currentStackTrace, out object dynamicMethodArray);
570 [MethodImplAttribute(MethodImplOptions.InternalCall)]
571 internal static extern void SaveStackTracesFromDeepCopy(Exception exception, object currentStackTrace, object dynamicMethodArray);
573 [MethodImplAttribute(MethodImplOptions.InternalCall)]
574 private static extern object CopyStackTrace(object currentStackTrace);
576 [MethodImplAttribute(MethodImplOptions.InternalCall)]
577 private static extern object CopyDynamicMethods(object currentDynamicMethods);
579 internal object DeepCopyStackTrace(object currentStackTrace)
581 if (currentStackTrace != null)
583 return CopyStackTrace(currentStackTrace);
591 internal object DeepCopyDynamicMethods(object currentDynamicMethods)
593 if (currentDynamicMethods != null)
595 return CopyDynamicMethods(currentDynamicMethods);
603 internal void GetStackTracesDeepCopy(out object currentStackTrace, out object dynamicMethodArray)
605 GetStackTracesDeepCopy(this, out currentStackTrace, out dynamicMethodArray);
608 // This is invoked by ExceptionDispatchInfo.Throw to restore the exception stack trace, corresponding to the original throw of the
609 // exception, just before the exception is "rethrown".
610 internal void RestoreExceptionDispatchInfo(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo)
612 bool fCanProcessException = !(IsImmutableAgileException(this));
613 // Restore only for non-preallocated exceptions
614 if (fCanProcessException)
616 // Take a lock to ensure only one thread can restore the details
617 // at a time against this exception object that could have
618 // multiple ExceptionDispatchInfo instances associated with it.
620 // We do this inside a finally clause to ensure ThreadAbort cannot
621 // be injected while we have taken the lock. This is to prevent
622 // unrelated exception restorations from getting blocked due to TAE.
626 // When restoring back the fields, we again create a copy and set reference to them
627 // in the exception object. This will ensure that when this exception is thrown and these
628 // fields are modified, then EDI's references remain intact.
630 // Since deep copying can throw on OOM, try to get the copies
632 object _stackTraceCopy = (exceptionDispatchInfo.BinaryStackTraceArray == null) ? null : DeepCopyStackTrace(exceptionDispatchInfo.BinaryStackTraceArray);
633 object _dynamicMethodsCopy = (exceptionDispatchInfo.DynamicMethodArray == null) ? null : DeepCopyDynamicMethods(exceptionDispatchInfo.DynamicMethodArray);
635 // Finally, restore the information.
637 // Since EDI can be created at various points during exception dispatch (e.g. at various frames on the stack) for the same exception instance,
638 // they can have different data to be restored. Thus, to ensure atomicity of restoration from each EDI, perform the restore under a lock.
639 lock (Exception.s_EDILock)
641 _watsonBuckets = exceptionDispatchInfo.WatsonBuckets;
642 _ipForWatsonBuckets = exceptionDispatchInfo.IPForWatsonBuckets;
643 _remoteStackTraceString = exceptionDispatchInfo.RemoteStackTrace;
644 SaveStackTracesFromDeepCopy(this, _stackTraceCopy, _dynamicMethodsCopy);
646 _stackTraceString = null;
648 // Marks the TES state to indicate we have restored foreign exception
649 // dispatch information.
650 Exception.PrepareForForeignExceptionRaise();
655 private String _className; //Needed for serialization.
656 private MethodBase _exceptionMethod; //Needed for serialization.
657 internal String _message;
658 private IDictionary _data;
659 private Exception _innerException;
660 private String _helpURL;
661 private Object _stackTrace;
662 [OptionalField] // This isnt present in pre-V4 exception objects that would be serialized.
663 private Object _watsonBuckets;
664 private String _stackTraceString; //Needed for serialization.
665 private String _remoteStackTraceString;
666 private int _remoteStackIndex;
667 #pragma warning disable 414 // Field is not used from managed.
668 // _dynamicMethods is an array of System.Resolver objects, used to keep
669 // DynamicMethodDescs alive for the lifetime of the exception. We do this because
670 // the _stackTrace field holds MethodDescs, and a DynamicMethodDesc can be destroyed
671 // unless a System.Resolver object roots it.
672 private Object _dynamicMethods;
673 #pragma warning restore 414
675 // @MANAGED: HResult is used from within the EE! Rename with care - check VM directory
676 internal int _HResult; // HResult
690 private String _source; // Mainly used by VB.
691 // WARNING: Don't delete/rename _xptrs and _xcode - used by functions
692 // on Marshal class. Native functions are in COMUtilNative.cpp & AppDomain
693 private IntPtr _xptrs; // Internal EE stuff
694 #pragma warning disable 414 // Field is not used from managed.
695 private int _xcode; // Internal EE stuff
696 #pragma warning restore 414
698 private UIntPtr _ipForWatsonBuckets; // Used to persist the IP for Watson Bucketing
701 // See src\inc\corexcep.h's EXCEPTION_COMPLUS definition:
702 private const int _COMPlusExceptionCode = unchecked((int)0xe0434352); // Win32 exception code for COM+ exceptions
704 // InternalToString is called by the runtime to get the exception text
705 // and create a corresponding CrossAppDomainMarshaledException
706 internal virtual String InternalToString()
708 // Get the current stack trace string.
709 return ToString(true, true);
712 // this method is required so Object.GetType is not made virtual by the compiler
713 // _Exception.GetType()
714 public new Type GetType()
716 return base.GetType();
719 internal bool IsTransient
723 return nIsTransient(_HResult);
727 [MethodImplAttribute(MethodImplOptions.InternalCall)]
728 private extern static bool nIsTransient(int hr);
731 // This piece of infrastructure exists to help avoid deadlocks
732 // between parts of mscorlib that might throw an exception while
733 // holding a lock that are also used by mscorlib's ResourceManager
734 // instance. As a special case of code that may throw while holding
735 // a lock, we also need to fix our asynchronous exceptions to use
736 // Win32 resources as well (assuming we ever call a managed
737 // constructor on instances of them). We should grow this set of
738 // exception messages as we discover problems, then move the resources
739 // involved to native code.
740 internal enum ExceptionMessageKind
743 ThreadInterrupted = 2,
747 // See comment on ExceptionMessageKind
748 internal static String GetMessageFromNativeResources(ExceptionMessageKind kind)
750 string retMesg = null;
751 GetMessageFromNativeResources(kind, JitHelpers.GetStringHandleOnStack(ref retMesg));
755 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
756 private static extern void GetMessageFromNativeResources(ExceptionMessageKind kind, StringHandleOnStack retMesg);
759 //--------------------------------------------------------------------------
760 // Telesto: Telesto doesn't support appdomain marshaling of objects so
761 // managed exceptions that leak across appdomain boundaries are flatted to
762 // its ToString() output and rethrown as an CrossAppDomainMarshaledException.
763 // The Message field is set to the ToString() output of the original exception.
764 //--------------------------------------------------------------------------
766 internal sealed class CrossAppDomainMarshaledException : SystemException
768 public CrossAppDomainMarshaledException(String message, int errorCode)
774 // Normally, only Telesto's UEF will see these exceptions.
775 // This override prints out the original Exception's ToString()
776 // output and hides the fact that it is wrapped inside another excepton.
777 internal override String InternalToString()