From 2c8d5f0a392be3e4cf4f545690d8987fd2aa61bc Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 3 Oct 2019 21:59:40 -0400 Subject: [PATCH] Add ExceptionDispatchInfo.SetCurrentStackTrace (dotnet/coreclr#27004) * Add ExceptionDispatchInfo.SetCurrentStackTrace * Address PR feedback Signed-off-by: dotnet-bot --- .../shared/System/Diagnostics/StackTrace.cs | 17 ++++++++++------- .../System.Private.CoreLib/shared/System/Exception.cs | 1 + .../System/IO/FileStreamCompletionSource.Win32.cs | 5 ++++- .../Runtime/ExceptionServices/ExceptionDispatchInfo.cs | 18 ++++++++++++++++++ .../shared/System/Threading/Tasks/Task.cs | 1 + .../shared/System/Threading/Timer.cs | 5 ++++- 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/StackTrace.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/StackTrace.cs index aaabf2076e2..b69dc670755 100644 --- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/StackTrace.cs +++ b/netcore/System.Private.CoreLib/shared/System/Diagnostics/StackTrace.cs @@ -194,11 +194,16 @@ namespace System.Diagnostics /// internal string ToString(TraceFormat traceFormat) { + var sb = new StringBuilder(256); + ToString(traceFormat, sb); + return sb.ToString(); + } + + internal void ToString(TraceFormat traceFormat, StringBuilder sb) + { string word_At = SR.Word_At; string inFileLineNum = SR.StackTrace_InFileLineNumber; - bool fFirstFrame = true; - StringBuilder sb = new StringBuilder(255); for (int iFrameIndex = 0; iFrameIndex < _numOfFrames; iFrameIndex++) { StackFrame? sf = GetFrame(iFrameIndex); @@ -210,7 +215,7 @@ namespace System.Diagnostics if (fFirstFrame) fFirstFrame = false; else - sb.Append(Environment.NewLineConst); + sb.AppendLine(); sb.AppendFormat(CultureInfo.InvariantCulture, " {0} ", word_At); @@ -320,16 +325,14 @@ namespace System.Diagnostics // Skip EDI boundary for async if (sf.IsLastFrameFromForeignExceptionStackTrace && !isAsync) { - sb.Append(Environment.NewLineConst); + sb.AppendLine(); sb.Append(SR.Exception_EndStackTraceFromPreviousThrow); } } } if (traceFormat == TraceFormat.TrailingNewLine) - sb.Append(Environment.NewLineConst); - - return sb.ToString(); + sb.AppendLine(); } #endif // !CORERT diff --git a/netcore/System.Private.CoreLib/shared/System/Exception.cs b/netcore/System.Private.CoreLib/shared/System/Exception.cs index 5d38412538f..a437da1c33f 100644 --- a/netcore/System.Private.CoreLib/shared/System/Exception.cs +++ b/netcore/System.Private.CoreLib/shared/System/Exception.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections; +using System.Diagnostics; using System.Runtime.Serialization; namespace System diff --git a/netcore/System.Private.CoreLib/shared/System/IO/FileStreamCompletionSource.Win32.cs b/netcore/System.Private.CoreLib/shared/System/IO/FileStreamCompletionSource.Win32.cs index 81240d6ba9f..7345afec3f1 100644 --- a/netcore/System.Private.CoreLib/shared/System/IO/FileStreamCompletionSource.Win32.cs +++ b/netcore/System.Private.CoreLib/shared/System/IO/FileStreamCompletionSource.Win32.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Diagnostics; +using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -186,7 +187,9 @@ namespace System.IO } else { - TrySetException(Win32Marshal.GetExceptionForWin32Error(errorCode)); + Exception e = Win32Marshal.GetExceptionForWin32Error(errorCode); + e.SetCurrentStackTrace(); + TrySetException(e); } } else diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs index 60f3beaf605..93236955f2a 100644 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs +++ b/netcore/System.Private.CoreLib/shared/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs @@ -61,5 +61,23 @@ namespace System.Runtime.ExceptionServices // rather than replacing the original stack trace. [DoesNotReturn] public static void Throw(Exception source) => Capture(source).Throw(); + + /// Stores the current stack trace into the specified instance. + /// The unthrown instance. + /// The argument was null. + /// The argument was previously thrown or previously had a stack trace stored into it.. + /// The exception instance. + [StackTraceHidden] + public static Exception SetCurrentStackTrace(Exception source) + { + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } + + source.SetCurrentStackTrace(); + + return source; + } } } diff --git a/netcore/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs b/netcore/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs index 55c946add0d..9d2c4f17237 100644 --- a/netcore/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs +++ b/netcore/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @@ -1802,6 +1802,7 @@ namespace System.Threading.Tasks // may not contain a TCE, but an OCE or any OCE-derived type, which would mean we'd be // propagating an exception of a different type. canceledException = new TaskCanceledException(this); + canceledException.SetCurrentStackTrace(); } if (ExceptionRecorded) diff --git a/netcore/System.Private.CoreLib/shared/System/Threading/Timer.cs b/netcore/System.Private.CoreLib/shared/System/Threading/Timer.cs index 3574e4344e2..d7c0537f559 100644 --- a/netcore/System.Private.CoreLib/shared/System/Threading/Timer.cs +++ b/netcore/System.Private.CoreLib/shared/System/Threading/Timer.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.Tracing; +using System.Runtime.ExceptionServices; using System.Threading.Tasks; namespace System.Threading @@ -533,7 +534,9 @@ namespace System.Threading // returning false if you use it multiple times. Since first calling Timer.Dispose(WaitHandle) // and then calling Timer.DisposeAsync is not something anyone is likely to or should do, we // simplify by just failing in that case. - return new ValueTask(Task.FromException(new InvalidOperationException(SR.InvalidOperation_TimerAlreadyClosed))); + var e = new InvalidOperationException(SR.InvalidOperation_TimerAlreadyClosed); + e.SetCurrentStackTrace(); + return new ValueTask(Task.FromException(e)); } } else -- 2.11.4.GIT